@@ -1004,6 +1004,11 @@ typedef struct cnonce {
10041004#define TYPE_LEN 64
10051005#define POLICY_LEN 24
10061006
1007+ struct cdb2_stmt_types {
1008+ int n ;
1009+ int types [0 ];
1010+ };
1011+
10071012struct cdb2_hndl {
10081013 char dbname [DBNAME_LEN ];
10091014 char cluster [64 ];
@@ -1102,6 +1107,7 @@ struct cdb2_hndl {
11021107 struct cdb2_hndl * fdb_hndl ;
11031108 int is_child_hndl ;
11041109 CDB2SQLQUERY__IdentityBlob * id_blob ;
1110+ struct cdb2_stmt_types * stmt_types ;
11051111};
11061112
11071113static void * cdb2_protobuf_alloc (void * allocator_data , size_t size )
@@ -3766,6 +3772,11 @@ int cdb2_close(cdb2_hndl_tp *hndl)
37663772 if (!hndl )
37673773 return 0 ;
37683774
3775+ if (hndl -> stmt_types ) {
3776+ free (hndl -> stmt_types );
3777+ hndl -> stmt_types = NULL ;
3778+ }
3779+
37693780 if (hndl -> fdb_hndl ) {
37703781 cdb2_close (hndl -> fdb_hndl );
37713782 hndl -> fdb_hndl = NULL ;
@@ -4399,6 +4410,94 @@ static inline void clear_snapshot_info(cdb2_hndl_tp *hndl, int line)
43994410 hndl -> is_retry = 0 ;
44004411}
44014412
4413+ static const struct {
4414+ const char * name ;
4415+ size_t name_sz ;
4416+ cdb2_coltype type ;
4417+ } all_types [] = {{"INTEGER" , sizeof ("INTEGER" ) - 1 , CDB2_INTEGER },
4418+ {"CSTRING" , sizeof ("CSTRING" ) - 1 , CDB2_CSTRING },
4419+ {"REAL" , sizeof ("REAL" ) - 1 , CDB2_REAL },
4420+ {"BLOB" , sizeof ("BLOB" ) - 1 , CDB2_BLOB },
4421+ {"DATETIME" , sizeof ("DATETIME" ) - 1 , CDB2_DATETIME },
4422+ {"DATETIMEUS" , sizeof ("DATETIMEUS" ) - 1 , CDB2_DATETIMEUS },
4423+ {"INTERVALDS" , sizeof ("INTERVALDS" ) - 1 , CDB2_INTERVALDS },
4424+ {"INTERVALDSUS" , sizeof ("INTERVALDSUS" ) - 1 , CDB2_INTERVALDSUS },
4425+ {"INTERVALYM" , sizeof ("INTERVALYM" ) - 1 , CDB2_INTERVALYM }};
4426+
4427+ static const int total_types = sizeof (all_types ) / sizeof (all_types [0 ]);
4428+
4429+ #define get_toklen (tok ) \
4430+ ({ \
4431+ cdb2_skipws(tok); \
4432+ int len = 0; \
4433+ while (tok[len] && !isspace(tok[len])) \
4434+ ++len; \
4435+ len; \
4436+ })
4437+
4438+ static int process_set_stmt_return_types (cdb2_hndl_tp * hndl , const char * sql )
4439+ {
4440+ int toklen ;
4441+ const char * tok = sql + 3 ; /* if we're here, first token is "set" */
4442+
4443+ toklen = get_toklen (tok );
4444+ if (toklen != 9 || strncasecmp (tok , "statement" , 9 ) != 0 )
4445+ return -1 ;
4446+ tok += toklen ;
4447+
4448+ toklen = get_toklen (tok );
4449+ if (toklen != 6 || strncasecmp (tok , "return" , 6 ) != 0 )
4450+ return -1 ;
4451+ tok += toklen ;
4452+
4453+ toklen = get_toklen (tok );
4454+ if (toklen != 5 || strncasecmp (tok , "types" , 5 ) != 0 )
4455+ return -1 ;
4456+ tok += toklen ;
4457+
4458+ if (hndl -> stmt_types ) {
4459+ sprintf (hndl -> errstr , "%s: already have %d parameter(s)" , __func__ , hndl -> stmt_types -> n );
4460+ return 1 ;
4461+ }
4462+
4463+ const int max_args = 1024 ;
4464+ uint8_t types [max_args ];
4465+ int count = 0 ;
4466+
4467+ while (1 ) {
4468+ toklen = get_toklen (tok );
4469+ if (toklen == 0 )
4470+ break ;
4471+ if (count == max_args ) {
4472+ sprintf (hndl -> errstr , "%s: max number of columns:%d" , __func__ , max_args );
4473+ return 1 ;
4474+ }
4475+ int i ;
4476+ for (i = 0 ; i < total_types ; ++ i ) {
4477+ if (toklen == all_types [i ].name_sz && strncasecmp (tok , all_types [i ].name , toklen ) == 0 ) {
4478+ tok += toklen ;
4479+ types [count ++ ] = all_types [i ].type ;
4480+ break ;
4481+ }
4482+ }
4483+ if (i >= total_types ) {
4484+ snprintf (hndl -> errstr , sizeof (hndl -> errstr ), "%s: column:%d has bad type:'%.*s'" , __func__ , count , toklen ,
4485+ tok );
4486+ return 1 ;
4487+ }
4488+ }
4489+ if (count == 0 ) {
4490+ sprintf (hndl -> errstr , "%s: bad number of columns:%d" , __func__ , count );
4491+ return 1 ;
4492+ }
4493+ hndl -> stmt_types = malloc (sizeof (struct cdb2_stmt_types ) + sizeof (int ) * count );
4494+ hndl -> stmt_types -> n = count ;
4495+ for (int i = 0 ; i < count ; ++ i ) {
4496+ hndl -> stmt_types -> types [i ] = types [i ];
4497+ }
4498+ return 0 ;
4499+ }
4500+
44024501static int process_set_command (cdb2_hndl_tp * hndl , const char * sql )
44034502{
44044503 int i , j , k ;
@@ -4411,8 +4510,10 @@ static int process_set_command(cdb2_hndl_tp *hndl, const char *sql)
44114510 return CDB2ERR_BADREQ ;
44124511 }
44134512
4414- int rc = process_ssl_set_command (hndl , sql );
4415- if (rc >= 0 )
4513+ int rc ;
4514+ if ((rc = process_ssl_set_command (hndl , sql )) >= 0 )
4515+ return rc ;
4516+ if ((rc = process_set_stmt_return_types (hndl , sql )) >= 0 )
44164517 return rc ;
44174518
44184519 i = hndl -> num_set_commands ;
@@ -4573,8 +4674,8 @@ static void attach_to_handle(cdb2_hndl_tp *child, cdb2_hndl_tp *parent)
45734674 child -> context_msgs .has_changed = child -> context_msgs .count > 0 ;
45744675}
45754676
4576- static int cdb2_run_statement_typed_int (cdb2_hndl_tp * hndl , const char * sql ,
4577- int ntypes , int * types , int line )
4677+ static int cdb2_run_statement_typed_int (cdb2_hndl_tp * hndl , const char * sql , int ntypes , int * types , int line ,
4678+ int * set_stmt )
45784679{
45794680 int return_value ;
45804681 int using_hint = 0 ;
@@ -4597,9 +4698,20 @@ static int cdb2_run_statement_typed_int(cdb2_hndl_tp *hndl, const char *sql,
45974698
45984699 /* sniff out 'set hasql on' here */
45994700 if (strncasecmp (sql , "set" , 3 ) == 0 ) {
4701+ * set_stmt = 1 ;
46004702 return process_set_command (hndl , sql );
46014703 }
46024704
4705+ if (hndl -> stmt_types ) {
4706+ if (ntypes || types ) {
4707+ sprintf (hndl -> errstr , "%s: provided %d type(s), but already have %d" , __func__ , ntypes ,
4708+ hndl -> stmt_types -> n );
4709+ return -1 ;
4710+ }
4711+ ntypes = hndl -> stmt_types -> n ;
4712+ types = hndl -> stmt_types -> types ;
4713+ }
4714+
46034715 if (strncasecmp (sql , "begin" , 5 ) == 0 ) {
46044716 debugprint ("setting is_begin flag\n" );
46054717 is_begin = 1 ;
@@ -5262,7 +5374,7 @@ int cdb2_run_statement_typed(cdb2_hndl_tp *hndl, const char *sql, int ntypes,
52625374{
52635375 int rc = 0 ;
52645376
5265- void * callbackrc ;
5377+ int set_stmt = 0 ;
52665378 int overwrite_rc = 0 ;
52675379 cdb2_event * e = NULL ;
52685380
@@ -5280,15 +5392,21 @@ int cdb2_run_statement_typed(cdb2_hndl_tp *hndl, const char *sql, int ntypes,
52805392
52815393 while ((e = cdb2_next_callback (hndl , CDB2_AT_ENTER_RUN_STATEMENT , e )) !=
52825394 NULL ) {
5283- callbackrc = cdb2_invoke_callback (hndl , e , 1 , CDB2_SQL , sql );
5395+ void * callbackrc = cdb2_invoke_callback (hndl , e , 1 , CDB2_SQL , sql );
52845396 PROCESS_EVENT_CTRL_BEFORE (hndl , e , rc , callbackrc , overwrite_rc );
52855397 }
52865398
5287- if (overwrite_rc )
5399+ if (overwrite_rc ) {
5400+ const char * first = sql ;
5401+ int len = get_toklen (first );
5402+ if (len == 3 && strncasecmp (first , "set" , 3 ) == 0 ) {
5403+ set_stmt = 1 ;
5404+ }
52885405 goto after_callback ;
5406+ }
52895407
52905408 if (hndl -> temp_trans && hndl -> in_trans ) {
5291- cdb2_run_statement_typed_int (hndl , "rollback" , 0 , NULL , __LINE__ );
5409+ cdb2_run_statement_typed_int (hndl , "rollback" , 0 , NULL , __LINE__ , & set_stmt );
52925410 }
52935411
52945412 hndl -> temp_trans = 0 ;
@@ -5297,7 +5415,7 @@ int cdb2_run_statement_typed(cdb2_hndl_tp *hndl, const char *sql, int ntypes,
52975415 (strncasecmp (sql , "set" , 3 ) != 0 && strncasecmp (sql , "begin" , 5 ) != 0 &&
52985416 strncasecmp (sql , "commit" , 6 ) != 0 &&
52995417 strncasecmp (sql , "rollback" , 8 ) != 0 )) {
5300- rc = cdb2_run_statement_typed_int (hndl , "begin" , 0 , NULL , __LINE__ );
5418+ rc = cdb2_run_statement_typed_int (hndl , "begin" , 0 , NULL , __LINE__ , & set_stmt );
53015419 if (rc ) {
53025420 debugprint ("cdb2_run_statement_typed_int rc = %d\n" , rc );
53035421 goto after_callback ;
@@ -5306,47 +5424,58 @@ int cdb2_run_statement_typed(cdb2_hndl_tp *hndl, const char *sql, int ntypes,
53065424 }
53075425
53085426 cdb2_skipws (sql );
5309- rc = cdb2_run_statement_typed_int (hndl , sql , ntypes , types , __LINE__ );
5427+ rc = cdb2_run_statement_typed_int (hndl , sql , ntypes , types , __LINE__ , & set_stmt );
53105428 if (rc )
53115429 debugprint ("rc = %d\n" , rc );
53125430
53135431 // XXX This code does not work correctly for WITH statements
53145432 // (they can be either read or write)
53155433 if (hndl -> temp_trans && !is_sql_read (sql )) {
53165434 if (rc == 0 ) {
5317- int commit_rc =
5318- cdb2_run_statement_typed_int (hndl , "commit" , 0 , NULL , __LINE__ );
5435+ int commit_rc = cdb2_run_statement_typed_int (hndl , "commit" , 0 , NULL , __LINE__ , & set_stmt );
53195436 debugprint ("rc = %d\n" , commit_rc );
53205437 rc = commit_rc ;
53215438 } else {
5322- cdb2_run_statement_typed_int (hndl , "rollback" , 0 , NULL , __LINE__ );
5439+ cdb2_run_statement_typed_int (hndl , "rollback" , 0 , NULL , __LINE__ , & set_stmt );
53235440 }
53245441 hndl -> temp_trans = 0 ;
53255442 }
53265443
53275444 if (log_calls ) {
5328- if (ntypes == 0 )
5445+ if (set_stmt || ( ntypes == 0 && hndl -> stmt_types == NULL ) )
53295446 fprintf (stderr , "%p> cdb2_run_statement(%p, \"%s\") = %d\n" ,
53305447 (void * )pthread_self (), hndl , sql , rc );
5331- else {
5448+ else if ( ntypes ) {
53325449 fprintf (stderr , "%p> cdb2_run_statement_typed(%p, \"%s\", [" ,
53335450 (void * )pthread_self (), hndl , sql );
53345451 for (int i = 0 ; i < ntypes ; i ++ ) {
53355452 fprintf (stderr , "%s%s" , cdb2_type_str (types [i ]),
53365453 i == ntypes - 1 ? "" : ", " );
53375454 }
53385455 fprintf (stderr , "] = %d\n" , rc );
5456+ } else {
5457+ int n = hndl -> stmt_types -> n ;
5458+ int * t = hndl -> stmt_types -> types ;
5459+ fprintf (stderr , "%p> cdb2_run_statement_typed(%p, \"%s\", [" , (void * )pthread_self (), hndl , sql );
5460+ for (int i = 0 ; i < n ; ++ i ) {
5461+ fprintf (stderr , "%s%s" , cdb2_type_str (t [i ]), i == n - 1 ? "" : ", " );
5462+ }
5463+ fprintf (stderr , "] = %d\n" , rc );
53395464 }
53405465 }
53415466
53425467after_callback :
53435468 while ((e = cdb2_next_callback (hndl , CDB2_AT_EXIT_RUN_STATEMENT , e )) !=
53445469 NULL ) {
5345- callbackrc = cdb2_invoke_callback (hndl , e , 2 , CDB2_SQL , sql ,
5346- CDB2_RETURN_VALUE , (intptr_t )rc );
5470+ void * callbackrc = cdb2_invoke_callback (hndl , e , 2 , CDB2_SQL , sql , CDB2_RETURN_VALUE , (intptr_t )rc );
53475471 PROCESS_EVENT_CTRL_AFTER (hndl , e , rc , callbackrc );
53485472 }
53495473
5474+ if (hndl -> stmt_types && !set_stmt ) {
5475+ free (hndl -> stmt_types );
5476+ hndl -> stmt_types = NULL ;
5477+ }
5478+
53505479 return rc ;
53515480}
53525481
0 commit comments