@@ -3608,6 +3608,11 @@ int cdb2_close(cdb2_hndl_tp *hndl)
36083608 if (!hndl )
36093609 return 0 ;
36103610
3611+ if (hndl -> stmt_types ) {
3612+ free (hndl -> stmt_types );
3613+ hndl -> stmt_types = NULL ;
3614+ }
3615+
36113616 if (hndl -> fdb_hndl ) {
36123617 cdb2_close (hndl -> fdb_hndl );
36133618 hndl -> fdb_hndl = NULL ;
@@ -3800,6 +3805,11 @@ static int cdb2_query_with_hint(cdb2_hndl_tp *hndl, const char *sqlquery,
38003805 return 0 ;
38013806}
38023807
3808+ struct cdb2_stmt_types {
3809+ int n ;
3810+ int types [0 ];
3811+ };
3812+
38033813int cdb2_run_statement (cdb2_hndl_tp * hndl , const char * sql )
38043814{
38053815 return cdb2_run_statement_typed (hndl , sql , 0 , NULL );
@@ -4241,6 +4251,94 @@ static inline void clear_snapshot_info(cdb2_hndl_tp *hndl, int line)
42414251 hndl -> is_retry = 0 ;
42424252}
42434253
4254+ static const struct {
4255+ const char * name ;
4256+ size_t name_sz ;
4257+ cdb2_coltype type ;
4258+ } all_types [] = {{"INTEGER" , sizeof ("INTEGER" ) - 1 , CDB2_INTEGER },
4259+ {"CSTRING" , sizeof ("CSTRING" ) - 1 , CDB2_CSTRING },
4260+ {"REAL" , sizeof ("REAL" ) - 1 , CDB2_REAL },
4261+ {"BLOB" , sizeof ("BLOB" ) - 1 , CDB2_BLOB },
4262+ {"DATETIME" , sizeof ("DATETIME" ) - 1 , CDB2_DATETIME },
4263+ {"DATETIMEUS" , sizeof ("DATETIMEUS" ) - 1 , CDB2_DATETIMEUS },
4264+ {"INTERVALDS" , sizeof ("INTERVALDS" ) - 1 , CDB2_INTERVALDS },
4265+ {"INTERVALDSUS" , sizeof ("INTERVALDSUS" ) - 1 , CDB2_INTERVALDSUS },
4266+ {"INTERVALYM" , sizeof ("INTERVALYM" ) - 1 , CDB2_INTERVALYM }};
4267+
4268+ static const int total_types = sizeof (all_types ) / sizeof (all_types [0 ]);
4269+
4270+ #define get_toklen (tok ) \
4271+ ({ \
4272+ cdb2_skipws(tok); \
4273+ int len = 0; \
4274+ while (tok[len] && !isspace(tok[len])) \
4275+ ++len; \
4276+ len; \
4277+ })
4278+
4279+ static int process_set_stmt_return_types (cdb2_hndl_tp * hndl , const char * sql )
4280+ {
4281+ int toklen ;
4282+ const char * tok = sql + 3 ; /* if we're here, first token is "set" */
4283+
4284+ toklen = get_toklen (tok );
4285+ if (toklen != 9 || strncasecmp (tok , "statement" , 9 ) != 0 )
4286+ return -1 ;
4287+ tok += toklen ;
4288+
4289+ toklen = get_toklen (tok );
4290+ if (toklen != 6 || strncasecmp (tok , "return" , 6 ) != 0 )
4291+ return -1 ;
4292+ tok += toklen ;
4293+
4294+ toklen = get_toklen (tok );
4295+ if (toklen != 5 || strncasecmp (tok , "types" , 5 ) != 0 )
4296+ return -1 ;
4297+ tok += toklen ;
4298+
4299+ if (hndl -> stmt_types ) {
4300+ sprintf (hndl -> errstr , "%s: already have %d parameter(s)" , __func__ , hndl -> stmt_types -> n );
4301+ return 1 ;
4302+ }
4303+
4304+ const int max_args = 1024 ;
4305+ uint8_t types [max_args ];
4306+ int count = 0 ;
4307+
4308+ while (1 ) {
4309+ toklen = get_toklen (tok );
4310+ if (toklen == 0 )
4311+ break ;
4312+ if (count == max_args ) {
4313+ sprintf (hndl -> errstr , "%s: max number of columns:%d" , __func__ , max_args );
4314+ return 1 ;
4315+ }
4316+ int i ;
4317+ for (i = 0 ; i < total_types ; ++ i ) {
4318+ if (toklen == all_types [i ].name_sz && strncasecmp (tok , all_types [i ].name , toklen ) == 0 ) {
4319+ tok += toklen ;
4320+ types [count ++ ] = all_types [i ].type ;
4321+ break ;
4322+ }
4323+ }
4324+ if (i >= total_types ) {
4325+ snprintf (hndl -> errstr , sizeof (hndl -> errstr ), "%s: column:%d has bad type:'%.*s'" , __func__ , count , toklen ,
4326+ tok );
4327+ return 1 ;
4328+ }
4329+ }
4330+ if (count == 0 ) {
4331+ sprintf (hndl -> errstr , "%s: bad number of columns:%d" , __func__ , count );
4332+ return 1 ;
4333+ }
4334+ hndl -> stmt_types = malloc (sizeof (struct cdb2_stmt_types ) + sizeof (int ) * count );
4335+ hndl -> stmt_types -> n = count ;
4336+ for (int i = 0 ; i < count ; ++ i ) {
4337+ hndl -> stmt_types -> types [i ] = types [i ];
4338+ }
4339+ return 0 ;
4340+ }
4341+
42444342static int process_set_command (cdb2_hndl_tp * hndl , const char * sql )
42454343{
42464344 int i , j , k ;
@@ -4253,8 +4351,10 @@ static int process_set_command(cdb2_hndl_tp *hndl, const char *sql)
42534351 return CDB2ERR_BADREQ ;
42544352 }
42554353
4256- int rc = process_ssl_set_command (hndl , sql );
4257- if (rc >= 0 )
4354+ int rc ;
4355+ if ((rc = process_ssl_set_command (hndl , sql )) >= 0 )
4356+ return rc ;
4357+ if ((rc = process_set_stmt_return_types (hndl , sql )) >= 0 )
42584358 return rc ;
42594359
42604360 i = hndl -> num_set_commands ;
@@ -4415,8 +4515,8 @@ static void attach_to_handle(cdb2_hndl_tp *child, cdb2_hndl_tp *parent)
44154515 child -> context_msgs .has_changed = child -> context_msgs .count > 0 ;
44164516}
44174517
4418- static int cdb2_run_statement_typed_int (cdb2_hndl_tp * hndl , const char * sql ,
4419- int ntypes , int * types , int line )
4518+ static int cdb2_run_statement_typed_int (cdb2_hndl_tp * hndl , const char * sql , int ntypes , int * types , int line ,
4519+ int * set_stmt )
44204520{
44214521 int return_value ;
44224522 int using_hint = 0 ;
@@ -4439,9 +4539,20 @@ static int cdb2_run_statement_typed_int(cdb2_hndl_tp *hndl, const char *sql,
44394539
44404540 /* sniff out 'set hasql on' here */
44414541 if (strncasecmp (sql , "set" , 3 ) == 0 ) {
4542+ * set_stmt = 1 ;
44424543 return process_set_command (hndl , sql );
44434544 }
44444545
4546+ if (hndl -> stmt_types ) {
4547+ if (ntypes || types ) {
4548+ sprintf (hndl -> errstr , "%s: provided %d type(s), but already have %d" , __func__ , ntypes ,
4549+ hndl -> stmt_types -> n );
4550+ return -1 ;
4551+ }
4552+ ntypes = hndl -> stmt_types -> n ;
4553+ types = hndl -> stmt_types -> types ;
4554+ }
4555+
44454556 if (strncasecmp (sql , "begin" , 5 ) == 0 ) {
44464557 debugprint ("setting is_begin flag\n" );
44474558 is_begin = 1 ;
@@ -5103,7 +5214,7 @@ int cdb2_run_statement_typed(cdb2_hndl_tp *hndl, const char *sql, int ntypes,
51035214{
51045215 int rc = 0 ;
51055216
5106- void * callbackrc ;
5217+ int set_stmt = 0 ;
51075218 int overwrite_rc = 0 ;
51085219 cdb2_event * e = NULL ;
51095220
@@ -5121,15 +5232,21 @@ int cdb2_run_statement_typed(cdb2_hndl_tp *hndl, const char *sql, int ntypes,
51215232
51225233 while ((e = cdb2_next_callback (hndl , CDB2_AT_ENTER_RUN_STATEMENT , e )) !=
51235234 NULL ) {
5124- callbackrc = cdb2_invoke_callback (hndl , e , 1 , CDB2_SQL , sql );
5235+ void * callbackrc = cdb2_invoke_callback (hndl , e , 1 , CDB2_SQL , sql );
51255236 PROCESS_EVENT_CTRL_BEFORE (hndl , e , rc , callbackrc , overwrite_rc );
51265237 }
51275238
5128- if (overwrite_rc )
5239+ if (overwrite_rc ) {
5240+ const char * first = sql ;
5241+ int len = get_toklen (first );
5242+ if (len == 3 && strncasecmp (first , "set" , 3 ) == 0 ) {
5243+ set_stmt = 1 ;
5244+ }
51295245 goto after_callback ;
5246+ }
51305247
51315248 if (hndl -> temp_trans && hndl -> in_trans ) {
5132- cdb2_run_statement_typed_int (hndl , "rollback" , 0 , NULL , __LINE__ );
5249+ cdb2_run_statement_typed_int (hndl , "rollback" , 0 , NULL , __LINE__ , & set_stmt );
51335250 }
51345251
51355252 hndl -> temp_trans = 0 ;
@@ -5138,7 +5255,7 @@ int cdb2_run_statement_typed(cdb2_hndl_tp *hndl, const char *sql, int ntypes,
51385255 (strncasecmp (sql , "set" , 3 ) != 0 && strncasecmp (sql , "begin" , 5 ) != 0 &&
51395256 strncasecmp (sql , "commit" , 6 ) != 0 &&
51405257 strncasecmp (sql , "rollback" , 8 ) != 0 )) {
5141- rc = cdb2_run_statement_typed_int (hndl , "begin" , 0 , NULL , __LINE__ );
5258+ rc = cdb2_run_statement_typed_int (hndl , "begin" , 0 , NULL , __LINE__ , & set_stmt );
51425259 if (rc ) {
51435260 debugprint ("cdb2_run_statement_typed_int rc = %d\n" , rc );
51445261 goto after_callback ;
@@ -5147,47 +5264,58 @@ int cdb2_run_statement_typed(cdb2_hndl_tp *hndl, const char *sql, int ntypes,
51475264 }
51485265
51495266 cdb2_skipws (sql );
5150- rc = cdb2_run_statement_typed_int (hndl , sql , ntypes , types , __LINE__ );
5267+ rc = cdb2_run_statement_typed_int (hndl , sql , ntypes , types , __LINE__ , & set_stmt );
51515268 if (rc )
51525269 debugprint ("rc = %d\n" , rc );
51535270
51545271 // XXX This code does not work correctly for WITH statements
51555272 // (they can be either read or write)
51565273 if (hndl -> temp_trans && !is_sql_read (sql )) {
51575274 if (rc == 0 ) {
5158- int commit_rc =
5159- cdb2_run_statement_typed_int (hndl , "commit" , 0 , NULL , __LINE__ );
5275+ int commit_rc = cdb2_run_statement_typed_int (hndl , "commit" , 0 , NULL , __LINE__ , & set_stmt );
51605276 debugprint ("rc = %d\n" , commit_rc );
51615277 rc = commit_rc ;
51625278 } else {
5163- cdb2_run_statement_typed_int (hndl , "rollback" , 0 , NULL , __LINE__ );
5279+ cdb2_run_statement_typed_int (hndl , "rollback" , 0 , NULL , __LINE__ , & set_stmt );
51645280 }
51655281 hndl -> temp_trans = 0 ;
51665282 }
51675283
51685284 if (log_calls ) {
5169- if (ntypes == 0 )
5285+ if (set_stmt || ( ntypes == 0 && hndl -> stmt_types == NULL ) )
51705286 fprintf (stderr , "%p> cdb2_run_statement(%p, \"%s\") = %d\n" ,
51715287 (void * )pthread_self (), hndl , sql , rc );
5172- else {
5288+ else if ( ntypes ) {
51735289 fprintf (stderr , "%p> cdb2_run_statement_typed(%p, \"%s\", [" ,
51745290 (void * )pthread_self (), hndl , sql );
51755291 for (int i = 0 ; i < ntypes ; i ++ ) {
51765292 fprintf (stderr , "%s%s" , cdb2_type_str (types [i ]),
51775293 i == ntypes - 1 ? "" : ", " );
51785294 }
51795295 fprintf (stderr , "] = %d\n" , rc );
5296+ } else {
5297+ int n = hndl -> stmt_types -> n ;
5298+ int * t = hndl -> stmt_types -> types ;
5299+ fprintf (stderr , "%p> cdb2_run_statement_typed(%p, \"%s\", [" , (void * )pthread_self (), hndl , sql );
5300+ for (int i = 0 ; i < n ; ++ i ) {
5301+ fprintf (stderr , "%s%s" , cdb2_type_str (t [i ]), i == n - 1 ? "" : ", " );
5302+ }
5303+ fprintf (stderr , "] = %d\n" , rc );
51805304 }
51815305 }
51825306
51835307after_callback :
51845308 while ((e = cdb2_next_callback (hndl , CDB2_AT_EXIT_RUN_STATEMENT , e )) !=
51855309 NULL ) {
5186- callbackrc = cdb2_invoke_callback (hndl , e , 2 , CDB2_SQL , sql ,
5187- CDB2_RETURN_VALUE , (intptr_t )rc );
5310+ void * callbackrc = cdb2_invoke_callback (hndl , e , 2 , CDB2_SQL , sql , CDB2_RETURN_VALUE , (intptr_t )rc );
51885311 PROCESS_EVENT_CTRL_AFTER (hndl , e , rc , callbackrc );
51895312 }
51905313
5314+ if (hndl -> stmt_types && !set_stmt ) {
5315+ free (hndl -> stmt_types );
5316+ hndl -> stmt_types = NULL ;
5317+ }
5318+
51915319 return rc ;
51925320}
51935321
0 commit comments