[tracker] SPARQL: Add support for GROUP_CONCAT



commit 87fd1404900e9e3a2c1688cc7dce55eb05e1881f
Author: Jürg Billeter <j bitron ch>
Date:   Wed Aug 12 10:55:55 2009 +0200

    SPARQL: Add support for GROUP_CONCAT

 src/libtracker-data/tracker-sparql-query.vala |    9 +++++++++
 src/rasqal/rasqal.h                           |    2 ++
 src/rasqal/rasqal.vapi                        |    3 ++-
 src/rasqal/rasqal_expr.c                      |    7 ++++++-
 src/rasqal/sparql_lexer.l                     |    1 +
 src/rasqal/sparql_parser.y                    |   24 +++++++++++++++++++++++-
 6 files changed, 43 insertions(+), 3 deletions(-)
---
diff --git a/src/libtracker-data/tracker-sparql-query.vala b/src/libtracker-data/tracker-sparql-query.vala
index 61b3c69..fac8d4f 100644
--- a/src/libtracker-data/tracker-sparql-query.vala
+++ b/src/libtracker-data/tracker-sparql-query.vala
@@ -266,6 +266,10 @@ public class Tracker.SparqlQuery : Object {
 		return "\"%s_u\"".printf (variable_name);
 	}
 
+	string escape_sql_string_literal (string literal) {
+		return "'%s'".printf (string.joinv ("''", literal.split ("'")));
+	}
+
 	string get_sql_for_expression (Rasqal.Expression expr) {
 		if (expr.op == Rasqal.Op.COUNT) {
 			return "COUNT(%s)".printf (get_sql_for_expression (expr.arg1));
@@ -277,6 +281,11 @@ public class Tracker.SparqlQuery : Object {
 			return "MIN(%s)".printf (get_sql_for_expression (expr.arg1));
 		} else if (expr.op == Rasqal.Op.MAX) {
 			return "MAX(%s)".printf (get_sql_for_expression (expr.arg1));
+		} else if (expr.op == Rasqal.Op.GROUP_CONCAT) {
+			var binding = new LiteralBinding ();
+			binding.literal = expr.arg2.literal.as_string ();
+			bindings.append (binding);
+			return "GROUP_CONCAT(%s,%s)".printf (get_sql_for_expression (expr.arg1), escape_sql_string_literal (expr.arg2.literal.as_string ()));
 		} else if (expr.op == Rasqal.Op.VARSTAR) {
 			return "*";
 		} else if (expr.op == Rasqal.Op.LITERAL) {
diff --git a/src/rasqal/rasqal.h b/src/rasqal/rasqal.h
index 5e68b13..cc54893 100644
--- a/src/rasqal/rasqal.h
+++ b/src/rasqal/rasqal.h
@@ -445,6 +445,7 @@ struct rasqal_literal_s {
  * @RASQAL_EXPR_AVG: Expression for LAQRS select AVG()
  * @RASQAL_EXPR_MIN: Expression for LAQRS select MIN()
  * @RASQAL_EXPR_MAX: Expression for LAQRS select MAX()
+ * @RASQAL_EXPR_GROUP_CONCAT: Expression for LAQRS select GROUP_CONCAT()
  * @RASQAL_EXPR_UNKNOWN: Internal
  * @RASQAL_EXPR_LAST: Internal
  *
@@ -498,6 +499,7 @@ typedef enum {
   RASQAL_EXPR_AVG,
   RASQAL_EXPR_MIN,
   RASQAL_EXPR_MAX,
+  RASQAL_EXPR_GROUP_CONCAT,
   /* internal */
   RASQAL_EXPR_LAST= RASQAL_EXPR_SAMETERM
 } rasqal_op;
diff --git a/src/rasqal/rasqal.vapi b/src/rasqal/rasqal.vapi
index 7e9e355..b5e6ea8 100644
--- a/src/rasqal/rasqal.vapi
+++ b/src/rasqal/rasqal.vapi
@@ -108,7 +108,8 @@ namespace Rasqal {
 		SUM,
 		AVG,
 		MIN,
-		MAX
+		MAX,
+		GROUP_CONCAT
 	}
 
 	[Compact]
diff --git a/src/rasqal/rasqal_expr.c b/src/rasqal/rasqal_expr.c
index 1e3b76f..f7bf53d 100644
--- a/src/rasqal/rasqal_expr.c
+++ b/src/rasqal/rasqal_expr.c
@@ -439,7 +439,7 @@ rasqal_new_0op_expression(rasqal_world* world, rasqal_op op)
  * @RASQAL_EXPR_ISLITERAL @RASQAL_EXPR_ORDER_COND_ASC
  * @RASQAL_EXPR_ORDER_COND_DESC @RASQAL_EXPR_GROUP_COND_ASC
  * @RASQAL_EXPR_GROUP_COND_DESC @RASQAL_EXPR_COUNT @RASQAL_EXPR_SUM
- * @RASQAL_EXPR_AVG @RASQAL_EXPR_MIN @RASQAL_EXPR_MAX
+ * @RASQAL_EXPR_AVG @RASQAL_EXPR_MIN @RASQAL_EXPR_MAX @RASQAL_EXPR_GROUP_CONCAT
  *
  * @RASQAL_EXPR_BANG and @RASQAL_EXPR_UMINUS are used by RDQL and
  * SPARQL.  @RASQAL_EXPR_TILDE by RDQL only.  The rest by SPARQL
@@ -773,6 +773,7 @@ rasqal_expression_clear(rasqal_expression* e)
     case RASQAL_EXPR_STR_NEQ:
     case RASQAL_EXPR_LANGMATCHES:
     case RASQAL_EXPR_SAMETERM:
+    case RASQAL_EXPR_GROUP_CONCAT:
       rasqal_free_expression(e->arg1);
       rasqal_free_expression(e->arg2);
       break;
@@ -920,6 +921,7 @@ rasqal_expression_visit(rasqal_expression* e,
     case RASQAL_EXPR_STR_NEQ:
     case RASQAL_EXPR_LANGMATCHES:
     case RASQAL_EXPR_SAMETERM:
+    case RASQAL_EXPR_GROUP_CONCAT:
       return rasqal_expression_visit(e->arg1, fn, user_data) ||
              rasqal_expression_visit(e->arg2, fn, user_data);
       break;
@@ -2104,6 +2106,7 @@ rasqal_expression_write(rasqal_expression* e, raptor_iostream* iostr)
     case RASQAL_EXPR_LANGMATCHES:
     case RASQAL_EXPR_REGEX:
     case RASQAL_EXPR_SAMETERM:
+    case RASQAL_EXPR_GROUP_CONCAT:
       raptor_iostream_write_counted_string(iostr, "op ", 3);
       rasqal_expression_write_op(e, iostr);
       raptor_iostream_write_byte(iostr, '(');
@@ -2231,6 +2234,7 @@ rasqal_expression_print(rasqal_expression* e, FILE* fh)
     case RASQAL_EXPR_LANGMATCHES:
     case RASQAL_EXPR_REGEX:
     case RASQAL_EXPR_SAMETERM:
+    case RASQAL_EXPR_GROUP_CONCAT:
       fputs("op ", fh);
       rasqal_expression_print_op(e, fh);
       fputc('(', fh);
@@ -2366,6 +2370,7 @@ rasqal_expression_is_constant(rasqal_expression* e)
     case RASQAL_EXPR_STR_NEQ:
     case RASQAL_EXPR_LANGMATCHES:
     case RASQAL_EXPR_SAMETERM:
+    case RASQAL_EXPR_GROUP_CONCAT:
       result=rasqal_expression_is_constant(e->arg1) &&
              rasqal_expression_is_constant(e->arg2);
       break;
diff --git a/src/rasqal/sparql_lexer.l b/src/rasqal/sparql_lexer.l
index 904e2db..f8ad6cc 100644
--- a/src/rasqal/sparql_lexer.l
+++ b/src/rasqal/sparql_lexer.l
@@ -357,6 +357,7 @@ EXPONENT [eE][+-]?[0-9]+
 [Aa][Vv][Gg] { return AVERAGE; }
 [Mm][Ii][Nn] { return MINIMUM; }
 [Mm][Aa][Xx] { return MAXIMUM; }
+[Gg][Rr][Oo][Uu][Pp]_[Cc][Oo][Nn][Cc][Aa][Tt] { return GROUP_CONCAT; }
 [Aa][Ss] { BEGIN(SPID); return AS; }
 [Dd][Ee][Ll][Ee][Tt][Ee]  { return DELETE; }
 [Ii][Nn][Ss][Ee][Rr][Tt]  { return INSERT; }
diff --git a/src/rasqal/sparql_parser.y b/src/rasqal/sparql_parser.y
index 29034d1..09955cb 100644
--- a/src/rasqal/sparql_parser.y
+++ b/src/rasqal/sparql_parser.y
@@ -145,7 +145,7 @@ static void sparql_query_error_full(rasqal_query *rq, const char *message, ...)
 %token ISLITERAL "isLiteral"
 %token SAMETERM "sameTerm"
 /* LAQRS */
-%token EXPLAIN GROUP COUNT SUM AVERAGE MINIMUM MAXIMUM AS
+%token EXPLAIN GROUP COUNT SUM AVERAGE MINIMUM MAXIMUM GROUP_CONCAT AS
 %token DELETE INSERT DROP
 
 
@@ -221,6 +221,7 @@ static void sparql_query_error_full(rasqal_query *rq, const char *message, ...)
 %type <expr> OrderCondition Filter Constraint SelectExpression
 %type <expr> AggregateExpression CountAggregateExpression SumAggregateExpression
 %type <expr> AvgAggregateExpression MinAggregateExpression MaxAggregateExpression
+%type <expr> GroupConcatAggregateExpression
 
 %type <literal> GraphTerm IRIref BlankNode
 %type <literal> VarOrIRIref
@@ -300,6 +301,7 @@ BrackettedExpression PrimaryExpression
 OrderCondition Filter Constraint SelectExpression
 AggregateExpression CountAggregateExpression SumAggregateExpression
 AvgAggregateExpression MinAggregateExpression MaxAggregateExpression
+GroupConcatAggregateExpression
 
 %destructor {
   if($$)
@@ -608,6 +610,10 @@ AggregateExpression: CountAggregateExpression
 {
   $$=$1;
 }
+| GroupConcatAggregateExpression
+{
+  $$=$1;
+}
 ;
 
 
@@ -707,6 +713,22 @@ MaxAggregateExpression: MAXIMUM '(' Expression ')'
 ;
 
 
+GroupConcatAggregateExpression: GROUP_CONCAT '(' Expression ',' Expression ')'
+{
+  rasqal_sparql_query_language* sparql=(rasqal_sparql_query_language*)(((rasqal_query*)rq)->context);
+
+  if(!sparql->extended) {
+    sparql_syntax_error((rasqal_query*)rq, "GROUP_CONCAT cannot be used with SPARQL");
+    $$=NULL;
+  } else {
+    $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_GROUP_CONCAT, $3, $5);
+    if(!$$)
+      YYERROR_MSG("GroupConcatAggregateExpression: cannot create expr");
+  }
+}
+;
+
+
 /* SPARQL Grammar: [6] ConstructQuery */
 ConstructQuery: CONSTRUCT ConstructTemplate
         DatasetClauseListOpt WhereClauseOpt SolutionModifier



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]