Hello,

There were requests for support of really long SPARQL INSERT DATA
statements but there was no good way of making that. Before.

The attached patch should be suitable for all recent Virtuoso 5.xx
builds. With this patch SPARQL INSERT DATA can load, say, the content of
links_bookmashup_en.nt from DBpedia (1.3 Mb long, 8903 triples) as a
single SPARQL statement, and it takes 3 seconds or about, not much
slower than a TURTLE loader.

Note that a megabyte-long statement can not be feed via ISQL tool.
However one can use other clients or, even better,
bypass the client connection and load the text of the statement
server-side via
exec (file_to_string ('my-large-file.sparql'))

A known bug exists: SPARQL DELETE DATA should report an error on attempt
of using bnodes in the statement, but it rund silently instead. As soon
as that is fixed, the patch will follow a usual way to Virtuoso Open
Source and Virtuoso Universal Server builds.

Best Regards,

Ivan Mikhailov
OpenLink Software
http://virtuoso.openlinksw.com

Index: eqlcomp.c
===================================================================
RCS file: /home/staff/us-cvs/virtuoso/libsrc/Wi/eqlcomp.c,v
retrieving revision 1.126
diff -u -U 10 -r1.126 eqlcomp.c
--- eqlcomp.c	18 Aug 2009 17:52:41 -0000	1.126
+++ eqlcomp.c	27 Nov 2009 20:01:17 -0000
@@ -601,20 +601,46 @@
     sl->ssl_const_val = box_copy_tree (val);
     sl->ssl_dtp = DV_TYPE_OF (val);
     if (sl->ssl_dtp == DV_LONG_STRING)
       sl->ssl_prec = box_length (val) - 1;
     else
       sl->ssl_prec = ddl_dv_default_prec (sl->ssl_dtp);
     return ((state_slot_t *) sl);
   }
 }
 
+state_slot_t *
+ssl_new_big_constant (comp_context_t * cc, caddr_t val)
+{
+#ifdef USE_SYS_CONSTANT
+  state_slot_t ** pre = (state_slot_t **) id_hash_get (constant_ssl, (caddr_t) &val);
+  if (pre)
+    return *pre;
+#endif
+  {
+    NEW_VARZ (state_const_slot_t, sl);
+    sl->ssl_next_const = cc->cc_query->qr_const_ssls;
+#ifdef USE_SYS_CONSTANT
+    cc->cc_query->qr_const_ssls = sl;
+#else
+    dk_set_push (&cc->cc_query->qr_state_map, (void *) sl);
+#endif
+    sl->ssl_type = SSL_CONSTANT;
+    sl->ssl_const_val = box_copy_tree (val);
+    sl->ssl_dtp = DV_TYPE_OF (val);
+    if (sl->ssl_dtp == DV_LONG_STRING)
+      sl->ssl_prec = box_length (val) - 1;
+    else
+      sl->ssl_prec = ddl_dv_default_prec (sl->ssl_dtp);
+    return ((state_slot_t *) sl);
+  }
+}
 
 state_slot_t *
 ssl_new_parameter (comp_context_t * cc, const char *name)
 {
   NEW_VARZ (state_slot_t, sl);
 
   cc->cc_query->qr_parms =
       dk_set_conc (cc->cc_query->qr_parms,
       dk_set_cons ((caddr_t) sl, NULL));
   /* Keep params in order. ODBC identifies them by index */
Index: eqlcomp.h
===================================================================
RCS file: /home/staff/us-cvs/virtuoso/libsrc/Wi/eqlcomp.h,v
retrieving revision 1.50
diff -u -U 10 -r1.50 eqlcomp.h
--- eqlcomp.h	9 Apr 2009 12:12:49 -0000	1.50
+++ eqlcomp.h	27 Nov 2009 19:58:30 -0000
@@ -65,21 +65,22 @@
 
 state_slot_t *ssl_new_parameter (comp_context_t * cc, const char *name);
 
 state_slot_t *ssl_new_column (comp_context_t * cc, const char *cr_name,
     dbe_column_t * col);
 
 state_slot_t *ssl_new_inst_variable (comp_context_t * cc, const char *name,
     dtp_t dtp);
 state_slot_t * ssl_new_tree (comp_context_t * cc, const char *name);
 
-state_slot_t *ssl_new_constant (comp_context_t * cc, caddr_t val);
+extern state_slot_t *ssl_new_constant (comp_context_t * cc, caddr_t val);
+extern state_slot_t *ssl_new_big_constant (comp_context_t * cc, caddr_t val);
 
 state_slot_t *ssl_new_placeholder (comp_context_t * cc, const char *name);
 
 state_slot_t *ssl_new_itc (comp_context_t * cc);
 
 int cc_new_instance_slot (comp_context_t * cc);
 
 void ins_free (insert_node_t * ins);
 
 void upd_free (update_node_t * upd);
Index: sparql.h
===================================================================
RCS file: /home/staff/us-cvs/virtuoso/libsrc/Wi/sparql.h,v
retrieving revision 1.104
diff -u -U 10 -r1.104 sparql.h
--- sparql.h	16 Nov 2009 03:28:53 -0000	1.104
+++ sparql.h	25 Nov 2009 21:51:35 -0000
@@ -257,21 +257,21 @@
   int sparp_yydebug;
 #endif
   caddr_t sparp_text;
   int sparp_unictr;			/*!< Unique counter for objects */
 /* Environment of yacc */
   sparp_env_t * sparp_env;
   int sparp_lexem_buf_len;
   int sparp_total_lexems_parsed;
   spar_lexem_t *sparp_curr_lexem;
   spar_lexbmk_t sparp_curr_lexem_bmk;
-  int sparp_in_precode_expn;		/*!< The parser reads precode-safe expression so it can not contain non-global variables */
+  int sparp_in_precode_expn;		/*!< If nonzero (usually 1) then the parser reads precode-safe expression so it can not contain non-global variables, if bit 2 is set then even global variables are prohibited (like it is in INSERT DATA statement) */
   int sparp_allow_aggregates_in_expn;	/*!< The parser reads result-set expressions or HAVING but not HAVING SELECT ... */
   int sparp_query_uses_aggregates;	/*!< Nonzero if there is at least one aggregate in the whole source query, (not in the current SELECT!). This is solely for bypassing expanding top retvals for "plain SPARQL" queries, not for other logic of the compiler */
   dk_set_t sparp_created_jsos;		/*!< Get-keyword style list of created JS objects. Object IRIs are keys, types (as free-text const char *) are values. This is solely for early (and incomplete) detection of probable errors. */
 /* Environment of lex */
   size_t sparp_text_ofs;
   size_t sparp_text_len;
   int sparp_lexlineno;			/*!< Source line number, starting from 1 */
   int sparp_lexdepth;			/*!< Lexical depth, it's equal to the current position in \c sparp_lexpars and \c sparp_lexstates */
   int sparp_lexpars[SPARP_MAX_LEXDEPTH+2];	/*!< Stack of not-yet-closed parenthesis */
   int sparp_lexstates[SPARP_MAX_LEXDEPTH+2];	/*!< Stack of lexical states */
Index: sparql.sql
===================================================================
RCS file: /home/staff/us-cvs/virtuoso/libsrc/Wi/sparql.sql,v
retrieving revision 1.459
diff -u -U 10 -r1.459 sparql.sql
--- sparql.sql	20 Nov 2009 01:20:13 -0000	1.459
+++ sparql.sql	28 Nov 2009 22:23:14 -0000
@@ -4616,65 +4616,84 @@
         _env := dict_new (31);
       if (0 < length (stats))
         DB.DBA.SPARQL_CONSTRUCT_ACC (_env, stats, vector(), vector(), use_dict_limit);
     }
   blank_ids := 0;
   for (triple_ctr := length (opcodes) - 1; triple_ctr >= 0; triple_ctr := triple_ctr-1)
     {
       declare fld_ctr integer;
       declare triple_vec any;
       triple_vec := vector (0,0,0);
+      -- dbg_obj_princ ('opcodes[triple_ctr]=', opcodes[triple_ctr]);
       for (fld_ctr := 2; fld_ctr >= 0; fld_ctr := fld_ctr - 1)
         {
           declare op integer;
           declare arg any;
           op := opcodes[triple_ctr][fld_ctr * 2];
           arg := opcodes[triple_ctr][fld_ctr * 2 + 1];
           if (1 = op)
             {
               declare i any;
               i := vars[arg];
               if (i is null)
                 goto end_of_adding_triple;
-              if ((2 > fld_ctr) and not (isiri_id (i) or (isstring (i) and (1 = __box_flags (i)))))
+              if (isiri_id (i))
+                {
+                  if ((1 = fld_ctr) and is_bnode_iri_id (i))
+                    signal ('RDF01', 'Bad variable value in CONSTRUCT: blank node can not be used as predicate');
+                }
+              else if ((isstring (i) and (1 = __box_flags (i))) or (217 = __tag(i)))
+                {
+                  if ((1 = fld_ctr) and (i like 'bnode://%'))
+                    signal ('RDF01', 'Bad variable value in CONSTRUCT: blank node can not be used as predicate');
+                  i := iri_to_id (i);
+                }
+              else if (2 > fld_ctr)
                 signal ('RDF01',
-                  sprintf ('Bad variable value in CONSTRUCT: "%.100s" is not a valid %s, only object of a triple can be a literal',
+                  sprintf ('Bad variable value in CONSTRUCT: "%.100s" (tag %d box flags %d) is not a valid %s, only object of a triple can be a literal',
+                    __tag (i), __box_flags (i),
                     __rdf_strsqlval (i),
                     case (fld_ctr) when 1 then 'predicate' else 'subject' end ) );
-              if ((1 = fld_ctr) and (
-                  (isiri_id (i) and (i >= min_bnode_iri_id ())) or
-                  (isstring (i) and (i like 'bnode://%')) ) )
-                signal ('RDF01', 'Bad variable value in CONSTRUCT: blank node can not be used as predicate');
               triple_vec[fld_ctr] := i;
             }
           else if (2 = op)
             {
-	      if (isinteger (blank_ids))
-	        blank_ids := vector (iri_id_from_num (sequence_next ('RDF_URL_IID_BLANK')));
+              if (isinteger (blank_ids))
+                blank_ids := vector (iri_id_from_num (sequence_next ('RDF_URL_IID_BLANK')));
               while (arg >= length (blank_ids))
                 blank_ids := vector_concat (blank_ids, vector (iri_id_from_num (sequence_next ('RDF_URL_IID_BLANK'))));
               if (1 = fld_ctr)
                 signal ('RDF01', 'Bad triple for CONSTRUCT: blank node can not be used as predicate');
               triple_vec[fld_ctr] := blank_ids[arg];
             }
           else if (3 = op)
             {
               if (arg is null)
                 goto end_of_adding_triple;
-              if ((2 > fld_ctr) and not (isiri_id (arg) or (isstring (arg) and (1 = __box_flags (arg)))))
-                signal ('RDF01', sprintf ('Bad const value in CONSTRUCT: "%.100s" is not a valid %s, only object of a triple can be a literal',
-                  __rdf_strsqlval (arg),
-                  case (fld_ctr) when 1 then 'predicate' else 'subject' end ) );
-              if ((1 = fld_ctr) and (
-                  (isiri_id (arg) and (arg >= min_bnode_iri_id ())) or
-                  (isstring (arg) and (arg like 'bnode://%')) ) )
-                signal ('RDF01', 'Bad const value in CONSTRUCT: blank node can not be used as predicate');
+
+              if (isiri_id (arg))
+                {
+                  if ((1 = fld_ctr) and is_bnode_iri_id (arg))
+                    signal ('RDF01', 'Bad const value in CONSTRUCT: blank node can not be used as predicate');
+                }
+              else if ((isstring (arg) and (1 = __box_flags (arg))) or (217 = __tag(arg)))
+                {
+                  if ((1 = fld_ctr) and (arg like 'bnode://%'))
+                    signal ('RDF01', 'Bad const value in CONSTRUCT: blank node can not be used as predicate');
+                  arg := iri_to_id (arg);
+                }
+              else if (2 > fld_ctr)
+                signal ('RDF01',
+                  sprintf ('Bad const value in CONSTRUCT: "%.100s" (tag %d box flags %d) is not a valid %s, only object of a triple can be a literal',
+                    __tag (arg), __box_flags (arg),
+                    __rdf_strsqlval (arg),
+                    case (fld_ctr) when 1 then 'predicate' else 'subject' end ) );
               triple_vec[fld_ctr] := arg;
             }
           else signal ('RDFXX', 'Bad opcode in DB.DBA.SPARQL_CONSTRUCT()');
         }
       -- dbg_obj_princ ('generated triple:', triple_vec);
       dict_put (_env, triple_vec, 0);
 end_of_adding_triple: ;
     }
 }
 ;
Index: sparql2sqltext.c
===================================================================
RCS file: /home/staff/us-cvs/virtuoso/libsrc/Wi/sparql2sqltext.c,v
retrieving revision 1.222
diff -u -U 10 -r1.222 sparql2sqltext.c
--- sparql2sqltext.c	20 Nov 2009 01:20:15 -0000	1.222
+++ sparql2sqltext.c	25 Nov 2009 23:09:40 -0000
@@ -7324,20 +7324,22 @@
         }
       /* No break here. INSERT_L and DELETE_L returns simple integers so no need to protect the client connection by formatting */
     case INSERT_L:
     case DELETE_L:
     case MODIFY_L:
     case CLEAR_L:
     case LOAD_L:
     case CREATE_L:
     case DROP_L:
     case SPARUL_RUN_SUBTYPE:
+    case SPARUL_INSERT_DATA:
+    case SPARUL_DELETE_DATA:
       if ((SPARUL_RUN_SUBTYPE == subtype) && !unbox (spar_compose_report_flag (ssg->ssg_sparp)))
         {
           ssg_puts ("set_row_count (");
           ssg->ssg_indent += 1;
           ssg_print_sparul_run_call (ssg, tree->_.req_top.pattern, retvals[0], 0);
           ssg_newline (0);
           ssg_puts (" )");
           ssg->ssg_indent -= 1;
           return;
         }
Index: sparql_core.c
===================================================================
RCS file: /home/staff/us-cvs/virtuoso/libsrc/Wi/sparql_core.c,v
retrieving revision 1.167
diff -u -U 10 -r1.167 sparql_core.c
--- sparql_core.c	19 Nov 2009 14:29:20 -0000	1.167
+++ sparql_core.c	25 Nov 2009 21:51:35 -0000
@@ -2214,22 +2214,27 @@
   caddr_t selid = NULL;
 #ifdef DEBUG
   caddr_t rvr_list_test[] = {SPART_RVR_LIST_OF_NULLS};
   if (sizeof (rvr_list_test) != sizeof (rdf_val_range_t))
     GPF_T; /* Don't forget to add NULLS to SPART_RVR_LIST_OF_NULLS when adding fields to rdf_val_range_t */
 #endif
   if (is_global)
     {
       t_set_push_new_string (&(sparp->sparp_env->spare_global_var_names), name);
     }
-  if (sparp->sparp_in_precode_expn && !is_global)
-    spar_error (sparp, "non-global variable '%.100s' can not be used outside any group pattern or result-set list");
+  if (sparp->sparp_in_precode_expn)
+    {
+      if (2 & sparp->sparp_in_precode_expn)
+        spar_error (sparp, "Variable '%.100s' is not allowed in a constant clause", name);
+      else if (!is_global)
+        spar_error (sparp, "non-global variable '%.100s' can not be used outside any group pattern or result-set list", name);
+    }
   if (NULL != env->spare_selids)
     selid = env->spare_selids->data;
   else if (is_global) /* say, 'insert in graph ?:someglobalvariable {...} where {...} */
     selid = t_box_dv_uname_string ("(global)");
   else
     spar_internal_error (sparp, "non-global variable outside any group pattern or result-set list");
   res = spartlist (sparp, 6 + (sizeof (rdf_val_range_t) / sizeof (caddr_t)),
       SPAR_VARIABLE, name,
       selid, NULL,
       (ptrlong)(0), SPART_BAD_EQUIV_IDX, SPART_RVR_LIST_OF_NULLS );
Index: sparql_p.y
===================================================================
RCS file: /home/staff/us-cvs/virtuoso/libsrc/Wi/sparql_p.y,v
retrieving revision 1.119
diff -u -U 10 -r1.119 sparql_p.y
--- sparql_p.y	16 Nov 2009 10:35:09 -0000	1.119
+++ sparql_p.y	25 Nov 2009 22:53:27 -0000
@@ -227,20 +227,22 @@
 %token TRANSITIVE_L	/*:: PUNCT_SPAR_LAST("TRANSITIVE") ::*/
 %token true_L		/*:: PUNCT_SPAR_LAST("true") ::*/
 %token UNION_L		/*:: PUNCT_SPAR_LAST("UNION") ::*/
 %token USING_L		/*:: PUNCT_SPAR_LAST("USING") ::*/
 %token WHERE_L		/*:: PUNCT("WHERE"), SPAR, LAST1("WHERE {"), LAST1("WHERE ("), LAST1("WHERE #cmt\n{"), LAST1("WHERE\r\n("), ERR("WHERE"), ERR("WHERE bad") ::*/
 %token __SPAR_PUNCT_END	/* Delimiting value for syntax highlighting */
 
 %token START_OF_SPARQL_TEXT	/*:: FAKE("the beginning of SPARQL text"), SPAR, NULL ::*/
 %token END_OF_SPARQL_TEXT	/*:: FAKE("the end of SPARQL text"), SPAR, NULL ::*/
 %token SPARUL_RUN_SUBTYPE	/*:: FAKE("subtype for request top of SPARUL statement"), SPAR, NULL ::*/
+%token SPARUL_INSERT_DATA	/*:: FAKE("subtype for request top of INSERT DATA statement"), SPAR, NULL ::*/
+%token SPARUL_DELETE_DATA	/*:: FAKE("subtype for request top of DELETE DATA statement"), SPAR, NULL ::*/
 
 %token __SPAR_NONPUNCT_START	/* Delimiting value for syntax highlighting */
 
 %token <box> TEXT_BL	/*:: PUNCT_SPAR_LAST("TEXT") ::*/
 %token <box> XML_BL	/*:: PUNCT_SPAR_LAST("XML") ::*/
 
 %token <box> SPARQL_INTEGER	/*:: LITERAL("%d"), SPAR, LAST("1234") ::*/
 %token <box> SPARQL_DECIMAL	/*:: LITERAL("%d"), SPAR, LAST("1234.56") ::*/
 %token <box> SPARQL_DOUBLE	/*:: LITERAL("%d"), SPAR, LAST("1234.56e1") ::*/
 
@@ -1119,29 +1121,32 @@
 	| spar_numeric_literal		{ $$ = $1; }
 	| _PLUS spar_numeric_literal	{ $$ = $2; }
 	| _MINUS spar_numeric_literal	{ $$ = $2; spar_change_sign (&($2->_.lit.val)); }
         | spar_boolean_literal		{ $$ = $1; }
         | spar_blank_node		{ $$ = $1; }
 	| NIL_L				{ $$ = (SPART *)t_box_dv_uname_string ("http://www.w3.org/1999/02/22-rdf-syntax-ns#nil";); }
 	| spar_backquoted
 	;
 
 spar_backquoted		/* [Virt]	Backquoted	 ::=  '`' Expn '`'	*/
-	: _BACKQUOTE spar_expn _BACKQUOTE {
+	: _BACKQUOTE {
+		if (2 & sparp_arg->sparp_in_precode_expn)
+		  spar_error (sparp_arg, "Backquoted expressions are not allowed in constant clauses"); }
+	    spar_expn _BACKQUOTE {
 		  dk_set_t gp_st = sparp_env()->spare_context_gp_subtypes;
                   if ((NULL == gp_st) || (CONSTRUCT_L == (ptrlong)(gp_st->data)))
-                    $$ = $2; /* redundant backquotes in retlist or backquotes to bypass syntax limitation in CONSTRUCT gp */
+                    $$ = $3; /* redundant backquotes in retlist or backquotes to bypass syntax limitation in CONSTRUCT gp */
                   else
 		    {
 		      SPART *bn = spar_make_blank_node (sparp_arg, spar_mkid (sparp_arg, "_:calc"), 1);
 		      SPART *eq;
-		      SPAR_BIN_OP (eq, BOP_EQ, t_full_box_copy_tree ((caddr_t)bn), $2);
+		      SPAR_BIN_OP (eq, BOP_EQ, t_full_box_copy_tree ((caddr_t)bn), $3);
                       spar_gp_add_filter (sparp_arg, eq);
 		      $$ = bn;
                     }
 		}
 	;
 
 spar_expn		/* [43]	Expn		 ::=  ConditionalOrExpn	*/
 	: spar_expn _BAR_BAR spar_expn { /* [44]	ConditionalOrExpn	 ::=  ConditionalAndExpn ( '||' ConditionalAndExpn )*	*/
 		  SPAR_BIN_OP ($$, BOP_OR, $1, $3); }
 	| spar_expn _AMP_AMP spar_expn { /* [45]	ConditionalAndExpn	 ::=  ValueLogical ( '&&' ValueLogical )*	*/
@@ -1400,24 +1405,26 @@
 		$$ = spar_make_top_or_special_case_from_wm (sparp_arg, INSERT_L, NULL,
                   spar_selid_pop (sparp_arg), $5 );
                 spar_compose_retvals_of_insert_or_delete (sparp_arg, $$, $2, $4); }
 	;
 
 spar_sparul_insertdata	/* [DML]*	InsertDataAction	 ::=  */
 			/*... 'INSERT' 'DATA' ( ( 'IN' | 'INTO ) 'GRAPH' ( 'IDENTIFIED' 'BY' )? )? */
 			/*... PrecodeExpn ConstructTemplate	*/
 	: INSERT_L DATA_L spar_in_graph_precode_opt {
 		sparp_arg->sparp_env->spare_top_retval_selid = spar_selid_push (sparp_arg);
-		t_set_push (&(sparp_arg->sparp_env->spare_propvar_sets), NULL); }
+		t_set_push (&(sparp_arg->sparp_env->spare_propvar_sets), NULL);
+		sparp_arg->sparp_in_precode_expn = 2; }
             spar_ctor_template {
                 SPART *fake = spar_make_fake_action_solution (sparp_arg);
-		$$ = spar_make_top_or_special_case_from_wm (sparp_arg, INSERT_L, NULL,
+		sparp_arg->sparp_in_precode_expn = 0;
+		$$ = spar_make_top_or_special_case_from_wm (sparp_arg, SPARUL_INSERT_DATA, NULL,
                   spar_selid_pop (sparp_arg), fake );
                 spar_compose_retvals_of_insert_or_delete (sparp_arg, $$, $3, $5); }
 	;
 
 spar_sparul_delete	/* [DML]*	DeleteAction	 ::=  */
 			/*... 'DELETE' ( 'FROM' 'GRAPH' ( 'IDENTIFIED' 'BY' )? )? PrecodeExpn	*/
 			/*... ConstructTemplate ( DatasetClause* WhereClause SolutionModifier )?	*/
 	: DELETE_L spar_from_graph_precode_opt {
 		sparp_arg->sparp_env->spare_top_retval_selid = spar_selid_push (sparp_arg);
 		t_set_push (&(sparp_arg->sparp_env->spare_propvar_sets), NULL); }
@@ -1425,24 +1432,26 @@
 		$$ = spar_make_top_or_special_case_from_wm (sparp_arg, DELETE_L, NULL,
                   spar_selid_pop (sparp_arg), $5 );
                 spar_compose_retvals_of_insert_or_delete (sparp_arg, $$, $2, $4); }
 	;
 
 spar_sparul_deletedata	/* [DML]*	DeleteDataAction	 ::=  */
 			/*... 'DELETE' 'DATA' ( 'FROM' 'GRAPH' ( 'IDENTIFIED' 'BY' )? )?	*/
 			/*... PrecodeExpn ConstructTemplate	*/
 	: DELETE_L DATA_L spar_from_graph_precode_opt {
 		sparp_arg->sparp_env->spare_top_retval_selid = spar_selid_push (sparp_arg);
-		t_set_push (&(sparp_arg->sparp_env->spare_propvar_sets), NULL); }
+		t_set_push (&(sparp_arg->sparp_env->spare_propvar_sets), NULL);
+		sparp_arg->sparp_in_precode_expn = 2; }
             spar_ctor_template {
                 SPART *fake = spar_make_fake_action_solution (sparp_arg);
-		$$ = spar_make_top_or_special_case_from_wm (sparp_arg, DELETE_L, NULL,
+		sparp_arg->sparp_in_precode_expn = 0;
+		$$ = spar_make_top_or_special_case_from_wm (sparp_arg, SPARUL_DELETE_DATA, NULL,
                   spar_selid_pop (sparp_arg), fake );
                 spar_compose_retvals_of_insert_or_delete (sparp_arg, $$, $3, $5); }
 	;
 
 spar_sparul_modify	/* [DML]*	ModifyAction	 ::=  */
 			/*... 'MODIFY' ( 'GRAPH' ( 'IDENTIFIED' 'BY' )? PrecodeExpn?	*/
 			/*... 'DELETE' ConstructTemplate 'INSERT' ConstructTemplate	*/
 			/*... ( DatasetClause* WhereClause SolutionModifier )?	*/
 	: MODIFY_L spar_graph_precode_opt {
 		sparp_arg->sparp_env->spare_top_retval_selid = spar_selid_push (sparp_arg);
Index: sparul2sql.c
===================================================================
RCS file: /home/staff/us-cvs/virtuoso/libsrc/Wi/sparul2sql.c,v
retrieving revision 1.26
diff -u -U 10 -r1.26 sparul2sql.c
--- sparul2sql.c	1 Oct 2009 12:54:43 -0000	1.26
+++ sparul2sql.c	28 Nov 2009 22:00:15 -0000
@@ -241,34 +241,102 @@
       sts_this->sts_curr_array [sts_this->sts_ofs_of_curr_in_array] = limofs_aref;
     }
   return SPAR_GPT_NODOWN;
 }
 
 #define CTOR_OPCODE_VARIABLE 1
 #define CTOR_OPCODE_BNODE 2
 #define CTOR_OPCODE_CONST_OR_EXPN 3
 
 void
-spar_compose_retvals_of_ctor (sparp_t *sparp, SPART *ctor_gp, const char *funname, SPART *arg0, SPART *arglast, SPART ***retvals, ctor_var_enumerator_t *cve,
+spar_compose_retvals_of_ctor (sparp_t *sparp, SPART *ctor_gp, const char *funname, sql_comp_t *sc_for_big_ssl_const, SPART *arg0, SPART *arglast, SPART ***retvals, ctor_var_enumerator_t *cve,
   const char *formatter, const char *agg_formatter, const char *agg_mdata, int use_limits )
 {
   int triple_ctr, fld_ctr, var_ctr;
   dk_set_t bnode_iter;
   SPART *ctor_call;
   SPART *var_vector_expn;
   SPART *var_vector_arg;
   SPART *arg1, *arg3;
   dk_set_t const_tvectors = NULL;
   dk_set_t var_tvectors = NULL;
   dk_set_t bnodes_acc = NULL;	/*!< Accumulator of bnodes with distinct names used in triple patterns of constructors */
   int bnode_count = 0;		/*!< Length of bnodes_acc */
 /* Making lists of variables, blank nodes, fixed triples, triples with variables and blank nodes. */
+  if (NULL != sc_for_big_ssl_const)
+    {
+      dk_set_t list_of_triples = NULL;
+      caddr_t **ssl_consts_ptr = &(sc_for_big_ssl_const->sc_big_ssl_consts);
+      int ssl_count = BOX_ELEMENTS_0 (ssl_consts_ptr[0]);
+      for (triple_ctr = BOX_ELEMENTS_INT (ctor_gp->_.gp.members); triple_ctr--; /* no step */)
+        {
+          SPART *triple = ctor_gp->_.gp.members[triple_ctr];
+          caddr_t *args = (caddr_t *)list (6,
+            (ptrlong)CTOR_OPCODE_CONST_OR_EXPN, NULL,
+            (ptrlong)CTOR_OPCODE_CONST_OR_EXPN, NULL,
+            (ptrlong)CTOR_OPCODE_CONST_OR_EXPN, NULL );
+          for (fld_ctr = 1; fld_ctr < SPART_TRIPLE_FIELDS_COUNT; fld_ctr++)
+            {
+              SPART *fld = triple->_.triple.tr_fields[fld_ctr];
+              ptrlong fld_type = SPART_TYPE(fld);
+              caddr_t val;
+              switch (fld_type)
+                {
+                case SPAR_BLANK_NODE_LABEL:
+                  if (cve->cve_bnodes_are_prohibited)
+                    spar_error (sparp, "Blank nodes are not allowed in DELETE constructor patterns");
+                  var_ctr = bnode_count;
+                  for (bnode_iter = bnodes_acc; NULL != bnode_iter; bnode_iter = bnode_iter->next)
+                    {
+                      SPART *old_bnode = (SPART *)(bnode_iter->data);
+                      var_ctr--;
+                      if (!strcmp (fld->_.var.vname, old_bnode->_.var.vname))
+                        goto bnode_found_or_added_for_big_ssl; /* see below */
+                    }
+                  t_set_push (&bnodes_acc, fld);
+                  var_ctr = bnode_count++;
+bnode_found_or_added_for_big_ssl:
+                  args [(fld_ctr-1)*2] = (caddr_t)((ptrlong)CTOR_OPCODE_BNODE);
+                  args [(fld_ctr-1)*2 + 1] = box_num (var_ctr);
+                  break;
+                case SPAR_LIT:
+                  if ((NULL != fld->_.lit.datatype) || (NULL != fld->_.lit.language))
+                    val = list (3, box_copy (fld->_.lit.val), box_copy (fld->_.lit.datatype), box_copy (fld->_.lit.language));
+                  else
+                    val = box_copy (fld->_.qname.val);
+                  args[(fld_ctr-1)*2 + 1] = val;
+                  break;
+                case SPAR_QNAME:
+                  val = box_copy (fld->_.qname.val);
+                  args[(fld_ctr-1)*2 + 1] = val;
+                  if (DV_STRING == DV_TYPE_OF (val))
+                    box_flags (val) = BF_IRI;
+                  break;
+                default: spar_internal_error (sparp, "Non-const in big ssl const mode constructor pattern");
+                }
+            }
+          dk_set_push (&list_of_triples, args);
+        }
+      if (NULL == ssl_consts_ptr[0])
+        ssl_consts_ptr[0] = (caddr_t *)list (1, NULL);
+      else
+        {
+          caddr_t *new_consts = (caddr_t *)dk_alloc_box ((ssl_count + 1) * sizeof (caddr_t), DV_ARRAY_OF_POINTER);
+          memcpy (new_consts, ssl_consts_ptr[0], ssl_count * sizeof (caddr_t));
+          dk_free_box (ssl_consts_ptr[0]);
+          ssl_consts_ptr[0] = new_consts;
+        }
+      ssl_consts_ptr[0][ssl_count] = (caddr_t)list_to_array (list_of_triples);
+      arg1 = spar_make_funcall (sparp, 0, "bif:vector", (SPART **)t_list (0));
+      arg3 = spar_make_funcall (sparp, 0, "bif:__ssl_const", (SPART *)t_list (1, t_box_num_nonull (ssl_count)));
+      goto args_ready; /* see below */
+    }
   for (triple_ctr = BOX_ELEMENTS_INT (ctor_gp->_.gp.members); triple_ctr--; /* no step */)
     {
       SPART *triple = ctor_gp->_.gp.members[triple_ctr];
       SPART **tvector_args;
       SPART *tvector_call;
       int triple_is_const = 1;
       tvector_args = (SPART **)t_list (6, NULL, NULL, NULL, NULL, NULL, NULL);
       tvector_call = spar_make_funcall (sparp, 0, ((NULL == formatter) ? "LONG::bif:vector" :  "bif:vector"), tvector_args);
       for (fld_ctr = 1; fld_ctr < SPART_TRIPLE_FIELDS_COUNT; fld_ctr++)
         {
@@ -284,21 +352,21 @@
               break;
             case SPAR_BLANK_NODE_LABEL:
               if (cve->cve_bnodes_are_prohibited)
                 spar_error (sparp, "Blank nodes are not allowed in DELETE constructor patterns");
               var_ctr = bnode_count;
               for (bnode_iter = bnodes_acc; NULL != bnode_iter; bnode_iter = bnode_iter->next)
                 {
                   SPART *old_bnode = (SPART *)(bnode_iter->data);
                   var_ctr--;
                   if (!strcmp (fld->_.var.vname, old_bnode->_.var.vname))
-                    goto bnode_found_or_added;
+                    goto bnode_found_or_added; /* see below */
                 }
               t_set_push (&bnodes_acc, fld);
               var_ctr = bnode_count++;
 bnode_found_or_added:
               tvector_args [(fld_ctr-1)*2] = (SPART *)t_box_num_nonull (CTOR_OPCODE_BNODE);
               tvector_args [(fld_ctr-1)*2 + 1] = (SPART *)t_box_num_nonull (var_ctr);
               triple_is_const = 0;
               break;
             case SPAR_LIT: case SPAR_QNAME:
               tvector_args [(fld_ctr-1)*2] = (SPART *)t_box_num_nonull (CTOR_OPCODE_CONST_OR_EXPN);
@@ -317,28 +385,30 @@
         }
       if (triple_is_const)
         {
           t_set_push (&const_tvectors, tvector_call);
         }
       else
         {
           t_set_push (&var_tvectors, tvector_call);
         }
     }
+  arg1 = spar_make_funcall (sparp, 0, "bif:vector", (SPART **)t_list_to_array (var_tvectors));
+  arg3 = spar_make_funcall (sparp, 0, "bif:vector", (SPART **)t_list_to_array (const_tvectors));
+
+args_ready:
   var_vector_expn = spar_make_funcall (sparp, 0, ((NULL == formatter) ? "LONG::bif:vector" :  "bif:vector"),
     (SPART **)t_revlist_to_array (cve->cve_dist_vars_acc) );
   if (cve->cve_limofs_var)
     var_vector_arg = cve->cve_limofs_var;
   else
     var_vector_arg = var_vector_expn;
-  arg1 = spar_make_funcall (sparp, 0, "bif:vector", (SPART **)t_list_to_array (var_tvectors));
-  arg3 = spar_make_funcall (sparp, 0, "bif:vector", (SPART **)t_list_to_array (const_tvectors));
   if (NULL != arglast)
     ctor_call = spar_make_funcall (sparp, 1, funname,
       (SPART **)t_list (5, arg0, arg1, var_vector_arg, arg3, arglast) );
   else if (NULL != arg0)
     ctor_call = spar_make_funcall (sparp, 1, funname,
       (SPART **)t_list (4, arg0, arg1, var_vector_arg, arg3) );
   else
     ctor_call = spar_make_funcall (sparp, 1, funname,
       (SPART **)t_list (4, arg1, var_vector_arg, arg3, t_box_num (use_limits)) );
   if (cve->cve_limofs_var_alias)
@@ -362,81 +432,98 @@
   memset (&cve, 0, sizeof (ctor_var_enumerator_t));
   if (need_limofs_trick)
     {
       caddr_t limofs_name = t_box_dv_short_string (":\"limofs\".\"ctor-1\"");
       cve.cve_limofs_var = spar_make_variable (sparp, limofs_name);
       cve.cve_limofs_var_alias = t_box_dv_short_string ("ctor-1");
     }
   if ((NULL == sparp->sparp_env->spare_storage_name) ||
     ('\0' != sparp->sparp_env->spare_storage_name) )
     use_limits = 1;
-  spar_compose_retvals_of_ctor (sparp, ctor_gp, "sql:SPARQL_CONSTRUCT", NULL, NULL,
+  spar_compose_retvals_of_ctor (sparp, ctor_gp, "sql:SPARQL_CONSTRUCT", NULL /* no big ssl const */, NULL, NULL,
     &(top->_.req_top.retvals), &cve, formatter, agg_formatter, agg_mdata, use_limits );
 
 }
 
 SPART *
 spar_simplify_graph_to_patch (sparp_t *sparp, SPART *g)
 {
   if (SPAR_GRAPH != SPART_TYPE (g))
     return g;
   if ((SPART_GRAPH_NOT_FROM == g->_.graph.subtype) || (SPART_GRAPH_NOT_NAMED == g->_.graph.subtype))
     spar_internal_error (sparp, "NOT FROM and NOT FROM NAMED are not fully supported by SPARUL operations, sorry");
   if (SPAR_QNAME == SPART_TYPE (g->_.graph.expn))
     return (SPART *)(g->_.graph.iri);
   return g->_.graph.expn;
 }
 
 void
 spar_compose_retvals_of_insert_or_delete (sparp_t *sparp, SPART *top, SPART *graph_to_patch, SPART *ctor_gp)
 {
   int need_limofs_trick = CTOR_NEEDS_LIMOFS_TRICK(top);
+  int top_subtype = top->_.req_top.subtype;
+  int top_subtype_is_insert = ((INSERT_L == top_subtype) || (SPARUL_INSERT_DATA == top_subtype));
+  int big_ssl_const_mode = ((SPARUL_INSERT_DATA == top_subtype) || (SPARUL_DELETE_DATA == top_subtype));
   const char *top_fname;
   caddr_t log_mode;
   SPART **rv;
   ctor_var_enumerator_t cve;
+  sql_comp_t *sc_for_big_ssl_const = NULL;
   graph_to_patch = spar_simplify_graph_to_patch (sparp, graph_to_patch);
   memset (&cve, 0, sizeof (ctor_var_enumerator_t));
   log_mode = sparp->sparp_env->spare_sparul_log_mode;
   if (NULL == log_mode)
     log_mode = t_NEW_DB_NULL;
   if (need_limofs_trick)
     {
       caddr_t limofs_name = t_box_dv_short_string (":\"limofs\".\"ctor-1\"");
       cve.cve_limofs_var = spar_make_variable (sparp, limofs_name);
       cve.cve_limofs_var_alias = t_box_dv_short_string ("ctor-1");
     }
-  spar_compose_retvals_of_ctor (sparp, ctor_gp, "sql:SPARQL_CONSTRUCT", NULL, NULL,
+  if (big_ssl_const_mode)
+    {
+      sc_for_big_ssl_const = sparp->sparp_sparqre->sparqre_super_sc;
+      if (NULL == sc_for_big_ssl_const)
+        {
+          big_ssl_const_mode = 0;
+#ifdef NDEBUG
+          spar_error (sparp, "The query can be compiled and executed but not translated to an accurate SQL text");
+#endif
+        }
+      else
+        {
+          while (NULL != sc_for_big_ssl_const->sc_super)
+            sc_for_big_ssl_const->sc_super = sc_for_big_ssl_const->sc_super;
+        }
+    }
+  spar_compose_retvals_of_ctor (sparp, ctor_gp, "sql:SPARQL_CONSTRUCT", sc_for_big_ssl_const, NULL, NULL,
     &(top->_.req_top.retvals), &cve, NULL, NULL, NULL, 0 );
   rv = top->_.req_top.retvals;
-  if (INSERT_L != top->_.req_top.subtype)
+  if ((INSERT_L != top->_.req_top.subtype) && (SPARUL_INSERT_DATA != top->_.req_top.subtype))
     cve.cve_bnodes_are_prohibited = 1;
   if (NULL != sparp->sparp_env->spare_output_route_name)
     {
       top_fname = t_box_sprintf (200, "sql:SPARQL_ROUTE_DICT_CONTENT_%.100s", sparp->sparp_env->spare_output_route_name);
       rv[0] = spar_make_funcall (sparp, 0, top_fname,
         (SPART **)t_list (11, graph_to_patch,
-          t_box_dv_short_string ((INSERT_L == top->_.req_top.subtype) ? "INSERT" : "DELETE"),
+          t_box_dv_short_string (top_subtype_is_insert ? "INSERT" : "DELETE"),
           ((NULL == sparp->sparp_env->spare_storage_name) ? t_NEW_DB_NULL : sparp->sparp_env->spare_storage_name),
           ((NULL == sparp->sparp_env->spare_output_storage_name) ? t_NEW_DB_NULL : sparp->sparp_env->spare_output_storage_name),
           ((NULL == sparp->sparp_env->spare_output_format_name) ? t_NEW_DB_NULL : sparp->sparp_env->spare_output_format_name),
           ((INSERT_L == top->_.req_top.subtype) ? t_NEW_DB_NULL : (caddr_t)(rv[0])),
           ((INSERT_L == top->_.req_top.subtype) ? (caddr_t)(rv[0]) : t_NEW_DB_NULL),
           t_NEW_DB_NULL,
           spar_exec_uid_and_gs_cbk (sparp), log_mode, spar_compose_report_flag (sparp) ) );
     }
   else
     {
-      if (INSERT_L == top->_.req_top.subtype)
-        top_fname = "sql:SPARQL_INSERT_DICT_CONTENT";
-      else
-        top_fname = "sql:SPARQL_DELETE_DICT_CONTENT";
+      top_fname = top_subtype_is_insert ? "sql:SPARQL_INSERT_DICT_CONTENT" : "sql:SPARQL_DELETE_DICT_CONTENT";
       rv[0] = spar_make_funcall (sparp, 0, top_fname,
         (SPART **)t_list (5, graph_to_patch, rv[0],
           spar_exec_uid_and_gs_cbk (sparp), log_mode, spar_compose_report_flag (sparp) ) );
     }
 }
 
 void
 spar_compose_retvals_of_modify (sparp_t *sparp, SPART *top, SPART *graph_to_patch, SPART *del_ctor_gp, SPART *ins_ctor_gp)
 {
   int need_limofs_trick;
@@ -462,25 +549,25 @@
   log_mode = sparp->sparp_env->spare_sparul_log_mode;
   if (NULL == log_mode)
     log_mode = t_NEW_DB_NULL;
   if (need_limofs_trick)
     {
       caddr_t limofs_name = t_box_dv_short_string (":\"limofs\".\"ctor-1\"");
       cve.cve_limofs_var = spar_make_variable (sparp, limofs_name);
       cve.cve_limofs_var_alias = t_box_dv_short_string ("ctor-1");
     }
   cve.cve_bnodes_are_prohibited = 1;
-  spar_compose_retvals_of_ctor (sparp, del_ctor_gp, "sql:SPARQL_CONSTRUCT", NULL, NULL,
+  spar_compose_retvals_of_ctor (sparp, del_ctor_gp, "sql:SPARQL_CONSTRUCT", NULL /* no big ssl const */, NULL, NULL,
     &(top->_.req_top.retvals), &cve, NULL, NULL, NULL, 0 );
   cve.cve_limofs_var_alias = NULL;
   cve.cve_bnodes_are_prohibited = 0;
-  spar_compose_retvals_of_ctor (sparp, ins_ctor_gp, "sql:SPARQL_CONSTRUCT", NULL, NULL,
+  spar_compose_retvals_of_ctor (sparp, ins_ctor_gp, "sql:SPARQL_CONSTRUCT", NULL /* no big ssl const */, NULL, NULL,
     &ins, &cve, NULL, NULL, NULL, 0 );
   rv = top->_.req_top.retvals;
 
   if (NULL != sparp->sparp_env->spare_output_route_name)
     rv[0] = spar_make_funcall (sparp, 0,
       t_box_sprintf (200, "sql:SPARQL_ROUTE_DICT_CONTENT_%.100s", sparp->sparp_env->spare_output_route_name),
       (SPART **)t_list (11, graph_to_patch,
         t_box_dv_short_string ("MODIFY"),
         ((NULL == sparp->sparp_env->spare_storage_name) ? t_NEW_DB_NULL : sparp->sparp_env->spare_storage_name),
         ((NULL == sparp->sparp_env->spare_output_storage_name) ? t_NEW_DB_NULL : sparp->sparp_env->spare_output_storage_name),
Index: sqlcmps.h
===================================================================
RCS file: /home/staff/us-cvs/virtuoso/libsrc/Wi/sqlcmps.h,v
retrieving revision 1.106
diff -u -U 10 -r1.106 sqlcmps.h
--- sqlcmps.h	15 Jul 2009 04:40:46 -0000	1.106
+++ sqlcmps.h	26 Nov 2009 19:19:24 -0000
@@ -203,20 +203,21 @@
 
     dk_set_t		sc_compound_scopes;
     int 		sc_is_trigger_decl;
     int 		sc_in_cursor_def;
     state_slot_t *	sc_grouping;
     ST **		sc_groupby_set;
     int		sc_is_update;
     char	sc_is_union;
     update_node_t * 	sc_update_keyset;
     id_hash_t *	sc_sample_cache;
+    caddr_t * sc_big_ssl_consts;	/*!< Vector of saved values for SSL consts of unusual types (like vectors) or just too big to fit into SQL text in a plain way */
   } sql_comp_t;
 
 #define SC_G_ID(sc) \
   (sc->sc_client->cli_user ? sc->sc_client->cli_user->usr_g_id : G_ID_DBA)
 
 #define SC_U_ID(sc) \
   (sc->sc_client->cli_user ? sc->sc_client->cli_user->usr_id : U_ID_DBA)
 
 
 #if 0
Index: sqlcomp2.c
===================================================================
RCS file: /home/staff/us-cvs/virtuoso/libsrc/Wi/sqlcomp2.c,v
retrieving revision 1.191
diff -u -U 10 -r1.191 sqlcomp2.c
--- sqlcomp2.c	18 Aug 2009 17:52:53 -0000	1.191
+++ sqlcomp2.c	27 Nov 2009 20:50:35 -0000
@@ -1114,20 +1114,33 @@
       id_hash_iterator_t hit;
       caddr_t * pid, *pnum;
       id_hash_iterator (&hit, sc->sc_sample_cache);
       while (hit_next (&hit, (caddr_t *)&pid, (caddr_t *)&pnum))
 	{
 	  dk_free_tree (*pid);
 	  dk_free_box (*pnum);
 	}
       id_hash_free (sc->sc_sample_cache);
     }
+  if (NULL != sc->sc_big_ssl_consts)
+    {
+#ifndef NDEBUG
+      int ctr;
+      DO_BOX_FAST (caddr_t, itm, ctr, sc->sc_big_ssl_consts)
+        {
+          if (NULL != itm)
+            dbg_printf (("\nUnused big ssl const # %d", ctr));
+        }
+      END_DO_BOX_FAST;
+#endif
+      dk_free_tree (sc->sc_big_ssl_consts);
+    }
 }
 
 query_t *
 sqlc_make_proc_store_qr (client_connection_t * cli, query_t * proc_or_trig, const char * text)
 {
   comp_context_t cc;
   sql_comp_t scs;
   sql_comp_t *sc = &scs;
   caddr_t text2 = box_dv_short_string (text);
   NEW_VARZ (query_t, qr);
Index: sqlexp.c
===================================================================
RCS file: /home/staff/us-cvs/virtuoso/libsrc/Wi/sqlexp.c,v
retrieving revision 1.130
diff -u -U 10 -r1.130 sqlexp.c
--- sqlexp.c	18 Aug 2009 17:52:54 -0000	1.130
+++ sqlexp.c	27 Nov 2009 20:54:23 -0000
@@ -150,20 +150,38 @@
   caddr_t func = tree->_.call.name;
   state_slot_t *fun_ssl = NULL;
   caddr_t fun_name = NULL;
   state_slot_t **params = NULL;
   char *full_name = NULL;
   query_t *proc = NULL;
   int inx;
   int n_params = act_params ? BOX_ELEMENTS (act_params) : 0;
   caddr_t fun_udt_name = NULL, type_name = BOX_ELEMENTS (tree) > 4 ? tree->_.call.type_name : NULL;
   size_t func_len = ((DV_SYMBOL == DV_TYPE_OF (func)) ? (box_length (func) - 1) : 0);
+/*                                        0         1  */
+/*                                        012345678901 */
+  if (!stricmp (func, "__ssl_const"))
+    {
+      sql_comp_t * topmost_sc = sc;
+      ptrlong idx = unbox ((ccaddr_t)(tree->_.call.params[0]));
+      caddr_t val;
+      state_slot_t *val_ssl;
+      while (NULL != topmost_sc->sc_super)
+        topmost_sc = topmost_sc->sc_super;
+      if ((idx >= BOX_ELEMENTS_0 (topmost_sc->sc_big_ssl_consts)) || (NULL == ret))
+        sqlc_new_error (sc->sc_cc, "42000", "SQ???", "Internal SQL compiler error: bad usage of __ssl_const()");
+      val = topmost_sc->sc_big_ssl_consts[idx];
+      topmost_sc->sc_big_ssl_consts[idx] = NULL;
+      val_ssl = ssl_new_big_constant (sc->sc_cc, val);
+      cv_artm (code, box_identity, ret, val_ssl, NULL);
+      return;
+    }
   if ((func_len > 10) && !stricmp (func + (func_len - 10), " (w/cache)") && (n_params > 0))
     {
       state_slot_t *cache = ssl_new_inst_variable (sc->sc_cc, "cache", DV_ARRAY_OF_POINTER);
       ((ptrlong *)(act_params[n_params - 1]))[0] = cache->ssl_index;
     }
   if (ret_param)
     params = (state_slot_t **) t_alloc_box ((n_params + 1) * sizeof (caddr_t), DV_ARRAY_OF_POINTER);
   else
     params = (state_slot_t **) t_box_copy ((caddr_t) act_params);
 

Reply via email to