3 @brief Load an abstract representation of a query from the database.
9 #include "opensrf/utils.h"
10 #include "opensrf/log.h"
11 #include "opensrf/string_array.h"
12 #include "opensrf/osrf_hash.h"
13 #include "openils/oils_buildq.h"
15 #define PRINT if( verbose ) printf
23 static int oils_result_get_bool_idx( dbi_result result, int i );
25 static FromRelation* getFromRelation( BuildSQLState* state, int id );
26 static FromRelation* constructFromRelation( BuildSQLState* state, dbi_result result );
27 static FromRelation* getJoinList( BuildSQLState* state, int id );
28 static void joinListFree( FromRelation* join_list );
29 static void fromRelationFree( FromRelation* fr );
31 static QSeq* loadChildQueries( BuildSQLState* state, int parent_id, const char* type_str );
32 static QSeq* constructQSeq( BuildSQLState* state, dbi_result result );
33 static void freeQSeqList( QSeq* seq );
34 static StoredQ* constructStoredQ( BuildSQLState* state, dbi_result result );
36 static SelectItem* getSelectList( BuildSQLState* state, int query_id );
37 static SelectItem* constructSelectItem( BuildSQLState* state, dbi_result result );
38 static void selectListFree( SelectItem* sel );
40 static BindVar* getBindVar( BuildSQLState* state, const char* name );
41 static BindVar* constructBindVar( BuildSQLState* state, dbi_result result );
42 static void bindVarFree( char* name, void* p );
44 static Expression* getExpression( BuildSQLState* state, int id );
45 static Expression* constructExpression( BuildSQLState* state, dbi_result result );
46 static void expressionListFree( Expression* exp );
47 static void expressionFree( Expression* exp );
48 static Expression* getExpressionList( BuildSQLState* state, int id );
50 static OrderItem* getOrderByList( BuildSQLState* state, int query_id );
51 static OrderItem* constructOrderItem( BuildSQLState* state, dbi_result result );
52 static void orderItemListFree( OrderItem* ord );
54 static void push_id( IdNode** stack, int id, const char* alias );
55 static const IdNode* searchIdStack( const IdNode* stack, int id, const char* alias );
57 // A series of free lists to store already-allocated objects that are not in use, for
58 // potential reuse. This is a hack to reduce churning through malloc() and free().
59 static StoredQ* free_storedq_list = NULL;
60 static FromRelation* free_from_relation_list = NULL;
61 static SelectItem* free_select_item_list = NULL;
62 static BindVar* free_bindvar_list = NULL;
63 static Expression* free_expression_list = NULL;
64 static IdNode* free_id_node_list = NULL;
65 static QSeq* free_qseq_list = NULL;
66 static OrderItem* free_order_item_list = NULL;
68 // Boolean; settable by call to oilsStoredQSetVerbose(), used by PRINT macro.
69 // The idea is to allow debugging messages from a command line test driver for ease of
70 // testing and development, but not from a real server, where messages to stdout don't
72 static int verbose = 0;
75 @brief Load a stored query.
76 @param state Pointer to the query-building context.
77 @param query_id ID of the query in query.stored_query.
78 @return A pointer to the newly loaded StoredQ if successful, or NULL if not.
80 The calling code is responsible for freeing the StoredQ by calling storedQFree().
82 StoredQ* getStoredQuery( BuildSQLState* state, int query_id ) {
86 // Check the stack to see if the current query is nested inside itself. If it is, then
87 // abort in order to avoid infinite recursion. If it isn't, then add it to the stack.
88 // (Make sure to pop it off the stack before returning.)
89 if( searchIdStack( state->query_stack, query_id, NULL )) {
90 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
91 "Infinite recursion detected; query # %d is nested within itself", query_id ));
95 push_id( &state->query_stack, query_id, NULL );
98 dbi_result result = dbi_conn_queryf( state->dbhandle,
99 "SELECT id, type, use_all, use_distinct, from_clause, where_clause, having_clause "
100 "FROM query.stored_query WHERE id = %d;", query_id );
102 if( dbi_result_first_row( result ) ) {
103 sq = constructStoredQ( state, result );
105 PRINT( "Got a query row\n" );
106 PRINT( "\tid: %d\n", sq->id );
107 PRINT( "\ttype: %d\n", (int) sq->type );
108 PRINT( "\tuse_all: %s\n", sq->use_all ? "true" : "false" );
109 PRINT( "\tuse_distinct: %s\n", sq->use_distinct ? "true" : "false" );
111 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
112 "Unable to build a query for id = %d", query_id ));
114 sqlAddMsg( state, "Stored query not found for id %d", query_id );
117 dbi_result_free( result );
120 int errnum = dbi_conn_error( state->dbhandle, &msg );
121 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
122 "Unable to query query.stored_query table: #%d %s",
123 errnum, msg ? msg : "No description available" ));
127 pop_id( &state->query_stack );
132 @brief Construct a StoredQ.
133 @param Pointer to the query-building context.
134 @param result Database cursor positioned at a row in query.stored_query.
135 @return Pointer to a newly constructed StoredQ, if successful, or NULL if not.
137 The calling code is responsible for freeing the StoredQ by calling storedQFree().
139 static StoredQ* constructStoredQ( BuildSQLState* state, dbi_result result ) {
141 // Get the column values from the result
142 int id = dbi_result_get_int_idx( result, 1 );
143 const char* type_str = dbi_result_get_string_idx( result, 2 );
146 if( !strcmp( type_str, "SELECT" ))
148 else if( !strcmp( type_str, "UNION" ))
150 else if( !strcmp( type_str, "INTERSECT" ))
152 else if( !strcmp( type_str, "EXCEPT" ))
155 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
156 "Invalid query type \"%s\"", type_str ));
160 int use_all = oils_result_get_bool_idx( result, 3 );
161 int use_distinct = oils_result_get_bool_idx( result, 4 );
164 if( dbi_result_field_is_null_idx( result, 5 ) )
167 from_clause_id = dbi_result_get_int_idx( result, 5 );
170 if( dbi_result_field_is_null_idx( result, 6 ) )
171 where_clause_id = -1;
173 where_clause_id = dbi_result_get_int_idx( result, 6 );
175 int having_clause_id;
176 if( dbi_result_field_is_null_idx( result, 7 ) )
177 having_clause_id = -1;
179 having_clause_id = dbi_result_get_int_idx( result, 7 );
181 FromRelation* from_clause = NULL;
182 if( QT_SELECT == type ) {
183 // A SELECT query needs a FROM clause; go get it
184 if( from_clause_id != -1 ) {
185 from_clause = getFromRelation( state, from_clause_id );
187 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
188 "Unable to construct FROM clause for id = %d", from_clause_id ));
193 // Must be one of UNION, INTERSECT, or EXCEPT
194 if( from_clause_id != -1 )
195 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
196 "FROM clause found and ignored for %s query in query #%d", type_str, id ));
199 // If this is a SELECT query, we need a SELECT list. Go get one.
200 SelectItem* select_list = NULL;
201 QSeq* child_list = NULL;
202 if( QT_SELECT == type ) {
203 select_list = getSelectList( state, id );
205 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
206 "No SELECT list found for query id = %d", id ));
207 fromRelationFree( from_clause );
211 // Construct child queries of UNION, INTERSECT, or EXCEPT query
212 child_list = loadChildQueries( state, id, type_str );
214 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
215 "Unable to load child queries for %s query # %d", type_str, id ));
217 fromRelationFree( from_clause );
222 // Get the WHERE clause, if there is one
223 Expression* where_clause = NULL;
224 if( where_clause_id != -1 ) {
225 where_clause = getExpression( state, where_clause_id );
226 if( ! where_clause ) {
227 // shouldn't happen due to foreign key constraint
228 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
229 "Unable to fetch WHERE expression for query id = %d", id ));
230 freeQSeqList( child_list );
231 fromRelationFree( from_clause );
232 selectListFree( select_list );
238 Expression* having_clause = NULL;
239 if( having_clause_id != -1 ) {
240 having_clause = getExpression( state, having_clause_id );
241 if( ! having_clause ) {
242 // shouldn't happen due to foreign key constraint
243 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
244 "Unable to fetch HAVING expression for query id = %d", id ));
245 expressionFree( where_clause );
246 freeQSeqList( child_list );
247 fromRelationFree( from_clause );
248 selectListFree( select_list );
254 // Get the ORDER BY clause, if there is one
255 OrderItem* order_by_list = getOrderByList( state, id );
257 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
258 "Unable to load ORDER BY clause for query %d", id ));
259 expressionFree( having_clause );
260 expressionFree( where_clause );
261 freeQSeqList( child_list );
262 fromRelationFree( from_clause );
263 selectListFree( select_list );
267 // Allocate a StoredQ: from the free list if possible, from the heap if necessary
270 if( free_storedq_list ) {
271 sq = free_storedq_list;
272 free_storedq_list = free_storedq_list->next;
274 sq = safe_malloc( sizeof( StoredQ ) );
276 // Populate the StoredQ
281 sq->use_all = use_all;
282 sq->use_distinct = use_distinct;
283 sq->from_clause = from_clause;
284 sq->where_clause = where_clause;
285 sq->select_list = select_list;
286 sq->child_list = child_list;
287 sq->having_clause = having_clause;
288 sq->order_by_list = order_by_list;
294 @brief Load the child queries subordinate to a UNION, INTERSECT, or EXCEPT query.
295 @param state Pointer to the query-building context.
296 @param parent ID of the UNION, INTERSECT, or EXCEPT query.
297 @param type_str The type of the query ("UNION", "INTERSECT", or "EXCEPT").
298 @return If successful, a pointer to a linked list of QSeq, each bearing a pointer to a
299 StoredQ; otherwise NULL.
301 The @a type_str parameter is used only for building error messages.
303 static QSeq* loadChildQueries( BuildSQLState* state, int parent_id, const char* type_str ) {
304 QSeq* child_list = NULL;
306 // The ORDER BY is in descending order so that we can build the list by adding to
307 // the head, and it will wind up in the right order.
308 dbi_result result = dbi_conn_queryf( state->dbhandle,
309 "SELECT id, parent_query, seq_no, child_query "
310 "FROM query.query_sequence WHERE parent_query = %d ORDER BY seq_no DESC", parent_id );
312 if( dbi_result_first_row( result ) ) {
316 QSeq* seq = constructQSeq( state, result );
318 PRINT( "Found a child query\n" );
319 PRINT( "\tid: %d\n", seq->id );
320 PRINT( "\tparent id: %d\n", seq->parent_query_id );
321 PRINT( "\tseq_no: %d\n", seq->seq_no );
322 // Add to the head of the list
323 seq->next = child_list;
326 freeQSeqList( child_list );
329 if( !dbi_result_next_row( result ))
333 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
334 "%s query # %d has only one child query", type_str, parent_id ));
336 freeQSeqList( child_list );
340 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
341 "%s query # %d has no child queries within it", type_str, parent_id ));
347 int errnum = dbi_conn_error( state->dbhandle, &msg );
348 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
349 "Unable to query query.query_sequence table: # %d %s",
350 errnum, msg ? msg : "No description available" ));
359 @brief Construct a QSeq.
360 @param Pointer to the query-building context.
361 @param result Database cursor positioned at a row in query.query_sequence.
362 @return Pointer to a newly constructed QSeq, if successful, or NULL if not.
364 The calling code is responsible for freeing QSeqs by calling freeQSeqList().
366 static QSeq* constructQSeq( BuildSQLState* state, dbi_result result ) {
367 int id = dbi_result_get_int_idx( result, 1 );
368 int parent_query_id = dbi_result_get_int_idx( result, 2 );
369 int seq_no = dbi_result_get_int_idx( result, 3 );
370 int child_query_id = dbi_result_get_int_idx( result, 4 );
372 StoredQ* child_query = getStoredQuery( state, child_query_id );
374 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
375 "Unable to load child query # %d for parent query %d",
376 child_query_id, parent_query_id ));
381 // Allocate a QSeq; from the free list if possible, from the heap if necessary
383 if( free_qseq_list ) {
384 seq = free_qseq_list;
385 free_qseq_list = free_qseq_list->next;
387 seq = safe_malloc( sizeof( QSeq ));
391 seq->parent_query_id = parent_query_id;
392 seq->seq_no = seq_no;
393 seq->child_query = child_query;
399 @brief Free a list of QSeq's.
400 @param seq Pointer to the first in a linked list of QSeq's to be freed.
402 Each QSeq goes onto a free list for potential reuse.
404 static void freeQSeqList( QSeq* seq ) {
410 storedQFree( seq->child_query );
411 seq->child_query = NULL;
416 seq->next = free_qseq_list;
421 free_qseq_list = first;
425 @brief Deallocate the memory owned by a StoredQ.
426 @param sq Pointer to the StoredQ to be deallocated.
428 void storedQFree( StoredQ* sq ) {
430 fromRelationFree( sq->from_clause );
431 sq->from_clause = NULL;
432 selectListFree( sq->select_list );
433 sq->select_list = NULL;
434 expressionFree( sq->where_clause );
435 sq->where_clause = NULL;
436 if( sq->child_list ) {
437 freeQSeqList( sq->child_list );
438 sq->child_list = NULL;
440 if( sq->order_by_list ) {
441 orderItemListFree( sq->order_by_list );
442 sq->order_by_list = NULL;
444 if( sq->having_clause )
445 expressionFree( sq->having_clause );
447 // Stick the empty husk on the free list for potential reuse
448 sq->next = free_storedq_list;
449 free_storedq_list = sq;
454 @brief Given an id from query.from_relation, load a FromRelation.
455 @param state Pointer the the query-building context.
456 @param id Id of the FromRelation.
457 @return Pointer to a newly-created FromRelation if successful, or NULL if not.
459 The calling code is responsible for freeing the new FromRelation by calling
462 static FromRelation* getFromRelation( BuildSQLState* state, int id ) {
463 FromRelation* fr = NULL;
464 dbi_result result = dbi_conn_queryf( state->dbhandle,
465 "SELECT id, type, table_name, class_name, subquery, function_call, "
466 "table_alias, parent_relation, seq_no, join_type, on_clause "
467 "FROM query.from_relation WHERE id = %d;", id );
469 if( dbi_result_first_row( result ) ) {
470 fr = constructFromRelation( state, result );
472 PRINT( "Got a from_relation row\n" );
473 PRINT( "\tid: %d\n", fr->id );
474 PRINT( "\ttype: %d\n", (int) fr->type );
475 PRINT( "\ttable_name: %s\n", fr->table_name ? fr->table_name : "(none)" );
476 PRINT( "\tclass_name: %s\n", fr->class_name ? fr->class_name : "(none)" );
477 PRINT( "\tsubquery_id: %d\n", fr->subquery_id );
478 PRINT( "\tfunction_call_id: %d\n", fr->function_call_id );
479 PRINT( "\ttable_alias: %s\n", fr->table_alias ? fr->table_alias : "(none)" );
480 PRINT( "\tparent_relation_id: %d\n", fr->parent_relation_id );
481 PRINT( "\tseq_no: %d\n", fr->seq_no );
482 PRINT( "\tjoin_type = %d\n", fr->join_type );
483 // Check the stack to see if the current from clause is nested inside itself.
484 // If it is, then abort in order to avoid infinite recursion. If it isn't,
485 // then add it to the stack. (Make sure to pop it off the stack before
487 const char* effective_alias = fr->table_alias;
488 if( !effective_alias )
489 effective_alias = fr->class_name;
490 const IdNode* node = searchIdStack( state->from_stack, id, effective_alias );
493 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
494 "Infinite recursion detected; from clause # %d is nested "
495 "within itself", id ));
497 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
498 "Conflicting nested table aliases \"%s\" in from clause # %d",
499 effective_alias, node->id ));
503 push_id( &state->from_stack, id, effective_alias );
505 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
506 "Unable to build a FromRelation for id = %d", id ));
508 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
509 "FROM relation not found for id = %d", id ));
511 dbi_result_free( result );
514 int errnum = dbi_conn_error( state->dbhandle, &msg );
515 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
516 "Unable to query query.from_relation table: #%d %s",
517 errnum, msg ? msg : "No description available" ));
522 pop_id( &state->from_stack );
528 @brief Construct a FromRelation.
529 @param Pointer to the query-building context.
530 @param result Database cursor positioned at a row in query.from_relation.
531 @return Pointer to a newly constructed FromRelation, if successful, or NULL if not.
533 The calling code is responsible for freeing FromRelations by calling joinListFree().
535 static FromRelation* constructFromRelation( BuildSQLState* state, dbi_result result ) {
536 // Get the column values from the result
537 int id = dbi_result_get_int_idx( result, 1 );
538 const char* type_str = dbi_result_get_string_idx( result, 2 );
540 FromRelationType type;
541 if( !strcmp( type_str, "RELATION" ))
543 else if( !strcmp( type_str, "SUBQUERY" ))
545 else if( !strcmp( type_str, "FUNCTION" ))
548 type = FRT_RELATION; // shouldn't happen due to database constraint
550 const char* table_name = dbi_result_get_string_idx( result, 3 );
551 const char* class_name = dbi_result_get_string_idx( result, 4 );
554 if( dbi_result_field_is_null_idx( result, 5 ) )
557 subquery_id = dbi_result_get_int_idx( result, 5 );
559 int function_call_id;
560 if( dbi_result_field_is_null_idx( result, 6 ) )
561 function_call_id = -1;
563 function_call_id = dbi_result_get_int_idx( result, 6 );
565 Expression* function_call = NULL;
566 const char* table_alias = dbi_result_get_string_idx( result, 7 );
568 int parent_relation_id;
569 if( dbi_result_field_is_null_idx( result, 8 ) )
570 parent_relation_id = -1;
572 parent_relation_id = dbi_result_get_int_idx( result, 8 );
574 int seq_no = dbi_result_get_int_idx( result, 9 );
577 const char* join_type_str = dbi_result_get_string_idx( result, 10 );
580 else if( !strcmp( join_type_str, "INNER" ) )
581 join_type = JT_INNER;
582 else if( !strcmp( join_type_str, "LEFT" ) )
584 else if( !strcmp( join_type_str, "RIGHT" ) )
585 join_type = JT_RIGHT;
586 else if( !strcmp( join_type_str, "FULL" ) )
589 join_type = JT_NONE; // shouldn't happen due to database constraint
592 if( dbi_result_field_is_null_idx( result, 11 ) )
595 on_clause_id = dbi_result_get_int_idx( result, 11 );
597 StoredQ* subquery = NULL;
603 if( -1 == subquery_id ) {
604 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
605 "Internal error: no subquery specified for FROM relation # %d", id ));
609 if( ! table_alias ) {
610 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
611 "Subquery needs alias in FROM relation # %d", id ));
615 subquery = getStoredQuery( state, subquery_id );
617 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
618 "Unable to load subquery for FROM relation # %d", id ));
624 if( -1 == function_call_id ) {
625 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
626 "FROM clause # %d purports to reference a function; not identified", id ));
631 function_call = getExpression( state, function_call_id );
632 if( !function_call ) {
633 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
634 "Unable to build function call # %d in FROM relation # %d",
635 function_call_id, id ));
638 } else if( function_call->type != EXP_FUNCTION ) {
639 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
640 "In FROM relation # %d: supposed function call expression # %d "
641 "is not a function call", id, function_call_id ));
647 FromRelation* join_list = getJoinList( state, id );
649 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
650 "Unable to load join list for FROM relation # %d", id ));
654 Expression* on_clause = NULL;
655 if( on_clause_id != -1 ) {
656 on_clause = getExpression( state, on_clause_id );
658 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
659 "Unable to load ON condition for FROM relation # %d", id ));
660 joinListFree( join_list );
665 PRINT( "\tGot an ON condition\n" );
668 // Allocate a FromRelation: from the free list if possible, from the heap if necessary
671 if( free_from_relation_list ) {
672 fr = free_from_relation_list;
673 free_from_relation_list = free_from_relation_list->next;
675 fr = safe_malloc( sizeof( FromRelation ) );
677 // Populate the FromRelation
682 fr->table_name = table_name ? strdup( table_name ) : NULL;
683 fr->class_name = class_name ? strdup( class_name ) : NULL;
684 fr->subquery_id = subquery_id;
685 fr->subquery = subquery;
686 fr->function_call_id = function_call_id;
687 fr->function_call = function_call;
688 fr->table_alias = table_alias ? strdup( table_alias ) : NULL;
689 fr->parent_relation_id = parent_relation_id;
691 fr->join_type = join_type;
692 fr->on_clause = on_clause;
693 fr->join_list = join_list;
699 @brief Build a list of joined relations.
700 @param state Pointer to the query-building context.
701 @param id ID of the parent relation.
702 @return A pointer to the first in a linked list of FromRelations, if there are any; or
703 NULL if there aren't any, or in case of an error.
705 Look for relations joined directly to the parent relation, and make a list of them.
707 static FromRelation* getJoinList( BuildSQLState* state, int id ) {
708 FromRelation* join_list = NULL;
710 // The ORDER BY is in descending order so that we can build the list by adding to
711 // the head, and it will wind up in the right order.
712 dbi_result result = dbi_conn_queryf( state->dbhandle,
713 "SELECT id, type, table_name, class_name, subquery, function_call, "
714 "table_alias, parent_relation, seq_no, join_type, on_clause "
715 "FROM query.from_relation WHERE parent_relation = %d ORDER BY seq_no DESC", id );
718 if( dbi_result_first_row( result ) ) {
720 FromRelation* relation = constructFromRelation( state, result );
722 PRINT( "Found a joined relation\n" );
723 PRINT( "\tjoin_type: %d\n", relation->join_type );
724 PRINT( "\ttable_name: %s\n", relation->table_name );
725 relation->next = join_list;
726 join_list = relation;
728 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
729 "Unable to build join list for from relation id #%d", id ));
730 joinListFree( join_list );
734 if( !dbi_result_next_row( result ) )
740 int errnum = dbi_conn_error( state->dbhandle, &msg );
741 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
742 "Unable to query query.from_relation table for join list: #%d %s",
743 errnum, msg ? msg : "No description available" ));
751 @brief Free a list of FromRelations.
752 @param join_list Pointer to the first FromRelation in the list.
754 static void joinListFree( FromRelation* join_list ) {
756 FromRelation* temp = join_list->next;
757 fromRelationFree( join_list );
763 @brief Deallocate a FromRelation.
764 @param fr Pointer to the FromRelation to be freed.
766 Free the strings that the FromRelation owns. The FromRelation itself goes onto a
767 free list for potential reuse.
769 static void fromRelationFree( FromRelation* fr ) {
771 free( fr->table_name );
772 fr->table_name = NULL;
773 free( fr->class_name );
774 fr->class_name = NULL;
776 storedQFree( fr->subquery );
779 if( fr->function_call ) {
780 expressionFree( fr->function_call );
781 fr->function_call = NULL;
783 free( fr->table_alias );
784 fr->table_alias = NULL;
785 if( fr->on_clause ) {
786 expressionFree( fr->on_clause );
787 fr->on_clause = NULL;
789 joinListFree( fr->join_list );
790 fr->join_list = NULL;
792 fr->next = free_from_relation_list;
793 free_from_relation_list = fr;
798 @brief Build a SELECT list for a given query ID.
799 @param state Pointer to the query-building context.
800 @param query_id ID of the query to which the SELECT list belongs.
802 static SelectItem* getSelectList( BuildSQLState* state, int query_id ) {
803 SelectItem* select_list = NULL;
805 // The ORDER BY is in descending order so that we can build the list by adding to
806 // the head, and it will wind up in the right order.
807 dbi_result result = dbi_conn_queryf( state->dbhandle,
808 "SELECT id, stored_query, seq_no, expression, column_alias, grouped_by "
809 "FROM query.select_item WHERE stored_query = %d ORDER BY seq_no DESC", query_id );
811 if( dbi_result_first_row( result ) ) {
813 SelectItem* item = constructSelectItem( state, result );
815 PRINT( "Found a SELECT item\n" );
816 PRINT( "\tid: %d\n", item->id );
817 PRINT( "\tstored_query_id: %d\n", item->stored_query_id );
818 PRINT( "\tseq_no: %d\n", item->seq_no );
819 PRINT( "\tcolumn_alias: %s\n",
820 item->column_alias ? item->column_alias : "(none)" );
821 PRINT( "\tgrouped_by: %d\n", item->grouped_by );
823 item->next = select_list;
826 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
827 "Unable to build select list for query id #%d", query_id ));
828 selectListFree( select_list );
832 if( !dbi_result_next_row( result ) )
838 int errnum = dbi_conn_error( state->dbhandle, &msg );
839 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
840 "Unable to query query.select_list table: #%d %s",
841 errnum, msg ? msg : "No description available" ));
849 @brief Construct a SelectItem.
850 @param Pointer to the query-building context.
851 @param result Database cursor positioned at a row in query.select_item.
852 @return Pointer to a newly constructed SelectItem, if successful, or NULL if not.
854 The calling code is responsible for freeing the SelectItems by calling selectListFree().
856 static SelectItem* constructSelectItem( BuildSQLState* state, dbi_result result ) {
858 // Get the column values
859 int id = dbi_result_get_int_idx( result, 1 );
860 int stored_query_id = dbi_result_get_int_idx( result, 2 );
861 int seq_no = dbi_result_get_int_idx( result, 3 );
862 int expression_id = dbi_result_get_int_idx( result, 4 );
863 const char* column_alias = dbi_result_get_string_idx( result, 5 );
864 int grouped_by = oils_result_get_bool_idx( result, 6 );
866 // Construct an Expression
867 Expression* expression = getExpression( state, expression_id );
869 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
870 "Unable to fetch expression for id = %d", expression_id ));
875 // Allocate a SelectItem: from the free list if possible, from the heap if necessary
878 if( free_select_item_list ) {
879 sel = free_select_item_list;
880 free_select_item_list = free_select_item_list->next;
882 sel = safe_malloc( sizeof( SelectItem ) );
886 sel->stored_query_id = stored_query_id;
887 sel->seq_no = seq_no;
888 sel->expression = expression;
889 sel->column_alias = column_alias ? strdup( column_alias ) : NULL;
890 sel->grouped_by = grouped_by;
896 @brief Free a list of SelectItems.
897 @param sel Pointer to the first item in the list to be freed.
899 Free the column alias and expression owned by each item. Put the entire list into a free
902 static void selectListFree( SelectItem* sel ) {
904 return; // Nothing to free
906 SelectItem* first = sel;
908 free( sel->column_alias );
909 sel->column_alias = NULL;
910 expressionFree( sel->expression );
911 sel->expression = NULL;
913 if( NULL == sel->next ) {
914 sel->next = free_select_item_list;
920 // Transfer the entire list to the free list
921 free_select_item_list = first;
925 @brief Given the name of a bind variable, build a corresponding BindVar.
926 @param state Pointer to the query-building context.
927 @param name Name of the bind variable.
928 @return Pointer to the newly-built BindVar.
930 Since the same bind variable may appear multiple times, we load it only once for the
931 entire query, and reference the one copy wherever needed.
933 static BindVar* getBindVar( BuildSQLState* state, const char* name ) {
934 BindVar* bind = NULL;
935 if( state->bindvar_list ) {
936 bind = osrfHashGet( state->bindvar_list, name );
938 return bind; // Already loaded it...
941 // Load a BindVar from the Database.
942 dbi_result result = dbi_conn_queryf( state->dbhandle,
943 "SELECT name, type, description, default_value, label "
944 "FROM query.bind_variable WHERE name = \'%s\';", name );
946 if( dbi_result_first_row( result ) ) {
947 bind = constructBindVar( state, result );
949 PRINT( "Got a bind variable for %s\n", name );
951 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
952 "Unable to load bind variable \"%s\"", name ));
954 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
955 "No bind variable found with name \"%s\"", name ));
959 int errnum = dbi_conn_error( state->dbhandle, &msg );
960 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
961 "Unable to query query.bind_variable table for \"%s\": #%d %s",
962 name, errnum, msg ? msg : "No description available" ));
967 // Add the new bind variable to the list
968 if( !state->bindvar_list ) {
969 // Don't have a list yet? Start one.
970 state->bindvar_list = osrfNewHash();
971 osrfHashSetCallback( state->bindvar_list, bindVarFree );
973 osrfHashSet( state->bindvar_list, bind, name );
981 @brief Construct a BindVar to represent a bind variable.
982 @param Pointer to the query-building context.
983 @param result Database cursor positioned at a row in query.bind_variable.
984 @return Pointer to a newly constructed BindVar, if successful, or NULL if not.
986 The calling code is responsible for freeing the BindVar by calling bindVarFree().
988 static BindVar* constructBindVar( BuildSQLState* state, dbi_result result ) {
990 const char* name = dbi_result_get_string_idx( result, 1 );
992 const char* type_str = dbi_result_get_string_idx( result, 2 );
994 if( !strcmp( type_str, "string" ))
996 else if( !strcmp( type_str, "number" ))
998 else if( !strcmp( type_str, "string_list" ))
999 type = BIND_STR_LIST;
1000 else if( !strcmp( type_str, "number_list" ))
1001 type = BIND_NUM_LIST;;
1003 const char* description = dbi_result_get_string_idx( result, 3 );
1005 // The default value is encoded as JSON. Translate it into a jsonObject.
1006 const char* default_value_str = dbi_result_get_string_idx( result, 4 );
1007 jsonObject* default_value = NULL;
1008 if( default_value_str ) {
1009 default_value = jsonParse( default_value_str );
1010 if( !default_value ) {
1011 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
1012 "Unable to parse JSON string for default value of bind variable \"%s\"",
1019 const char* label = dbi_result_get_string_idx( result, 5 );
1021 // Allocate a BindVar: from the free list if possible, from the heap if necessary
1022 BindVar* bind = NULL;
1023 if( free_bindvar_list ) {
1024 bind = free_bindvar_list;
1025 free_bindvar_list = free_bindvar_list->next;
1027 bind = safe_malloc( sizeof( BindVar ) );
1030 bind->name = strdup( name );
1031 bind->label = strdup( label );
1033 bind->description = strdup( description );
1034 bind->default_value = default_value;
1035 bind->actual_value = NULL;
1041 @brief Deallocate a BindVar.
1042 @param key Pointer to the bind variable name (not used).
1043 @param p Pointer to the BindVar to be deallocated, cast to a void pointer.
1045 Free the strings and jsonObjects owned by the BindVar, and put the BindVar itself into a
1048 This function is a callback installed in an osrfHash; hence the peculiar signature.
1050 static void bindVarFree( char* key, void* p ) {
1054 free( bind->label );
1055 free( bind->description );
1056 if( bind->default_value ) {
1057 jsonObjectFree( bind->default_value );
1058 bind->default_value = NULL;
1060 if( bind->actual_value ) {
1061 jsonObjectFree( bind->actual_value );
1062 bind->actual_value = NULL;
1065 // Prepend to free list
1066 bind->next = free_bindvar_list;
1067 free_bindvar_list = bind;
1072 @brief Given an id for a row in query.expression, build an Expression struct.
1073 @param Pointer to the query-building context.
1074 @param id ID of a row in query.expression.
1075 @return Pointer to a newly-created Expression if successful, or NULL if not.
1077 static Expression* getExpression( BuildSQLState* state, int id ) {
1079 // Check the stack to see if the current expression is nested inside itself. If it is,
1080 // then abort in order to avoid infinite recursion. If it isn't, then add it to the
1081 // stack. (Make sure to pop it off the stack before returning.)
1082 if( searchIdStack( state->expr_stack, id, NULL )) {
1083 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1084 "Infinite recursion detected; expression # %d is nested within itself", id ));
1088 push_id( &state->expr_stack, id, NULL );
1090 Expression* exp = NULL;
1091 dbi_result result = dbi_conn_queryf( state->dbhandle,
1092 "SELECT exp.id, exp.type, exp.parenthesize, exp.parent_expr, exp.seq_no, "
1093 "exp.literal, exp.table_alias, exp.column_name, exp.left_operand, exp.operator, "
1094 "exp.right_operand, exp.subquery, exp.cast_type, exp.negate, exp.bind_variable, "
1095 "func.function_name "
1096 "FROM query.expression AS exp LEFT JOIN query.function_sig AS func "
1097 "ON (exp.function_id = func.id) "
1098 "WHERE exp.id = %d;", id );
1100 if( dbi_result_first_row( result ) ) {
1101 exp = constructExpression( state, result );
1103 PRINT( "Got an expression\n" );
1104 PRINT( "\tid = %d\n", exp->id );
1105 PRINT( "\ttype = %d\n", exp->type );
1106 PRINT( "\tparenthesize = %d\n", exp->parenthesize );
1107 PRINT( "\tcolumn_name = %s\n", exp->column_name ? exp->column_name : "(none)" );
1109 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
1110 "Unable to construct an Expression for id = %d", id ));
1114 int errnum = dbi_conn_error( state->dbhandle, &msg );
1115 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
1116 "Unable to query query.expression table: #%d %s",
1117 errnum, msg ? msg : "No description available" ));
1121 pop_id( &state->expr_stack );
1126 @brief Construct an Expression.
1127 @param Pointer to the query-building context.
1128 @param result Database cursor positioned at a row in query.expression.
1129 @return Pointer to a newly constructed Expression, if successful, or NULL if not.
1131 The calling code is responsible for freeing the Expression by calling expressionFree().
1133 static Expression* constructExpression( BuildSQLState* state, dbi_result result ) {
1135 int id = dbi_result_get_int_idx( result, 1 );
1136 const char* type_str = dbi_result_get_string_idx( result, 2 );
1139 if( !strcmp( type_str, "xbet" ))
1141 else if( !strcmp( type_str, "xbind" ))
1143 else if( !strcmp( type_str, "xbool" ))
1145 else if( !strcmp( type_str, "xcase" ))
1147 else if( !strcmp( type_str, "xcast" ))
1149 else if( !strcmp( type_str, "xcol" ))
1151 else if( !strcmp( type_str, "xex" ))
1153 else if( !strcmp( type_str, "xfld" ))
1155 else if( !strcmp( type_str, "xfunc" ))
1156 type = EXP_FUNCTION;
1157 else if( !strcmp( type_str, "xin" ))
1159 else if( !strcmp( type_str, "xisnull" ))
1161 else if( !strcmp( type_str, "xnull" ))
1163 else if( !strcmp( type_str, "xnum" ))
1165 else if( !strcmp( type_str, "xop" ))
1166 type = EXP_OPERATOR;
1167 else if( !strcmp( type_str, "xser" ))
1169 else if( !strcmp( type_str, "xstr" ))
1171 else if( !strcmp( type_str, "xsubq" ))
1172 type = EXP_SUBQUERY;
1174 type = EXP_NULL; // shouldn't happen due to database constraint
1176 int parenthesize = oils_result_get_bool_idx( result, 3 );
1179 if( dbi_result_field_is_null_idx( result, 4 ))
1180 parent_expr_id = -1;
1182 parent_expr_id = dbi_result_get_int_idx( result, 4 );
1184 int seq_no = dbi_result_get_int_idx( result, 5 );
1185 const char* literal = dbi_result_get_string_idx( result, 6 );
1186 const char* table_alias = dbi_result_get_string_idx( result, 7 );
1187 const char* column_name = dbi_result_get_string_idx( result, 8 );
1189 int left_operand_id;
1190 if( dbi_result_field_is_null_idx( result, 9 ))
1191 left_operand_id = -1;
1193 left_operand_id = dbi_result_get_int_idx( result, 9 );
1195 const char* operator = dbi_result_get_string_idx( result, 10 );
1197 int right_operand_id;
1198 if( dbi_result_field_is_null_idx( result, 11 ))
1199 right_operand_id = -1;
1201 right_operand_id = dbi_result_get_int_idx( result, 11 );
1204 if( dbi_result_field_is_null_idx( result, 12 ))
1207 subquery_id = dbi_result_get_int_idx( result, 12 );
1210 if( dbi_result_field_is_null_idx( result, 13 ))
1213 cast_type_id = dbi_result_get_int_idx( result, 13 );
1215 int negate = oils_result_get_bool_idx( result, 14 );
1216 const char* bind_variable = dbi_result_get_string_idx( result, 15 );
1217 const char* function_name = dbi_result_get_string_idx( result, 16 );
1219 Expression* left_operand = NULL;
1220 Expression* right_operand = NULL;
1221 StoredQ* subquery = NULL;
1222 BindVar* bind = NULL;
1223 Expression* subexp_list = NULL;
1225 if( EXP_BETWEEN == type ) {
1226 // Get the left operand
1227 if( -1 == left_operand_id ) {
1228 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1229 "No left operand defined for BETWEEN expression # %d", id ));
1233 left_operand = getExpression( state, left_operand_id );
1234 if( !left_operand ) {
1235 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1236 "Unable to get left operand in BETWEEN expression # %d", id ));
1242 // Get the end points of the BETWEEN range
1243 subexp_list = getExpressionList( state, id );
1244 if( state->error ) {
1245 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1246 "Unable to get subexpressions for BETWEEN expression # %d", id ));
1247 expressionFree( left_operand );
1249 } else if( !subexp_list ) {
1250 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1251 "BETWEEN range is empty in expression # %d", id ));
1253 expressionFree( left_operand );
1255 } else if( !subexp_list->next ) {
1256 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1257 "BETWEEN range has only one end point in expression # %d", id ));
1259 expressionListFree( subexp_list );
1260 expressionFree( left_operand );
1262 } else if( subexp_list->next->next ) {
1263 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1264 "BETWEEN range has more than two subexpressions in expression # %d", id ));
1266 expressionListFree( subexp_list );
1267 expressionFree( left_operand );
1271 } else if( EXP_BIND == type ) {
1272 if( bind_variable ) {
1273 // To do: Build a BindVar
1274 bind = getBindVar( state, bind_variable );
1276 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1277 "Unable to load bind variable \"%s\" for expression # %d",
1278 bind_variable, id ));
1282 PRINT( "\tBind variable is \"%s\"\n", bind_variable );
1284 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1285 "No variable specified for bind variable expression # %d",
1286 bind_variable, id ));
1290 if( right_operand_id != -1 ) {
1291 right_operand = getExpression( state, right_operand_id );
1292 if( !right_operand ) {
1293 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1294 "Unable to get right operand in expression # %d", id ));
1296 expressionFree( left_operand );
1301 } else if( EXP_EXIST == type ) {
1302 if( -1 == subquery_id ) {
1303 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1304 "Internal error: No subquery found for EXIST expression # %d", id ));
1308 subquery = getStoredQuery( state, subquery_id );
1310 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1311 "Unable to load subquery for EXIST expression # %d", id ));
1317 } else if( EXP_FUNCTION == type ) {
1318 if( !function_name ) {
1319 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1320 "Function call expression # %d provides no function name", id ));
1324 subexp_list = getExpressionList( state, id );
1325 if( state->error ) {
1326 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1327 "Unable to get parameter list for function expression # %d", id ));
1332 } else if( EXP_IN == type ) {
1333 if( -1 == left_operand_id ) {
1334 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1335 "IN condition has no left operand in expression # %d", id ));
1339 left_operand = getExpression( state, left_operand_id );
1340 if( !left_operand ) {
1341 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1342 "Unable to get left operand for IN condition in expression # %d", id ));
1348 if( -1 == subquery_id ) {
1349 // Load an IN list of subexpressions
1350 subexp_list = getExpressionList( state, id );
1351 if( state->error ) {
1352 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1353 "Unable to get subexpressions for IN list" ));
1355 } else if( !subexp_list ) {
1356 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1357 "IN list is empty in expression # %d", id ));
1363 subquery = getStoredQuery( state, subquery_id );
1365 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1366 "Unable to load subquery for IN expression # %d", id ));
1372 } else if( EXP_ISNULL == type ) {
1373 if( -1 == left_operand_id ) {
1374 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1375 "Expression # %d IS NULL has no left operand", id ));
1380 if( left_operand_id != -1 ) {
1381 left_operand = getExpression( state, left_operand_id );
1382 if( !left_operand ) {
1383 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1384 "Unable to get left operand in expression # %d", id ));
1390 } else if( EXP_NUMBER == type ) {
1392 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1393 "Numeric expression # %d provides no numeric value", id ));
1398 } else if( EXP_OPERATOR == type ) {
1399 // Load left and/or right operands
1400 if( -1 == left_operand_id && -1 == right_operand_id ) {
1401 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1402 "Expression # %d is an operator with no operands", id ));
1407 if( left_operand_id != -1 ) {
1408 left_operand = getExpression( state, left_operand_id );
1409 if( !left_operand ) {
1410 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1411 "Unable to get left operand in expression # %d", id ));
1417 if( right_operand_id != -1 ) {
1418 right_operand = getExpression( state, right_operand_id );
1419 if( !right_operand ) {
1420 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1421 "Unable to get right operand in expression # %d", id ));
1427 } else if( EXP_SERIES == type ) {
1428 subexp_list = getExpressionList( state, id );
1429 if( state->error ) {
1430 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1431 "Unable to get subexpressions for expression series using operator \"%s\"",
1432 operator ? operator : "," ));
1434 } else if( !subexp_list ) {
1435 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1436 "Series expression is empty in expression # %d", id ));
1441 } else if( EXP_STRING == type ) {
1443 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1444 "String expression # %d provides no string value", id ));
1449 } else if( EXP_SUBQUERY == type ) {
1450 if( -1 == subquery_id ) {
1451 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1452 "Subquery expression # %d has no query id", id ));
1456 // Load a subquery, if there is one
1457 subquery = getStoredQuery( state, subquery_id );
1459 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1460 "Unable to load subquery for expression # %d", id ));
1464 if( subquery->select_list && subquery->select_list->next ) {
1465 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
1466 "Subquery # %d as expression returns more than one column", subquery_id ));
1470 PRINT( "\tExpression is subquery %d\n", subquery_id );
1474 // Allocate an Expression: from the free list if possible, from the heap if necessary
1475 Expression* exp = NULL;
1476 if( free_expression_list ) {
1477 exp = free_expression_list;
1478 free_expression_list = free_expression_list->next;
1480 exp = safe_malloc( sizeof( Expression ) );
1482 // Populate the Expression
1486 exp->parenthesize = parenthesize;
1487 exp->parent_expr_id = parent_expr_id;
1488 exp->seq_no = seq_no;
1489 exp->literal = literal ? strdup( literal ) : NULL;
1490 exp->table_alias = table_alias ? strdup( table_alias ) : NULL;
1491 exp->column_name = column_name ? strdup( column_name ) : NULL;
1492 exp->left_operand = left_operand;
1493 exp->op = operator ? strdup( operator ) : NULL;
1494 exp->right_operand = right_operand;
1495 exp->subquery_id = subquery_id;
1496 exp->subquery = subquery;
1497 exp->cast_type_id = subquery_id;
1498 exp->negate = negate;
1500 exp->subexp_list = subexp_list;
1501 exp->function_name = function_name ? strdup( function_name ) : NULL;
1507 @brief Free all the Expressions in a linked list of Expressions.
1508 @param exp Pointer to the first Expression in the list.
1510 static void expressionListFree( Expression* exp ) {
1512 Expression* next = exp->next;
1513 expressionFree( exp );
1519 @brief Deallocate an Expression.
1520 @param exp Pointer to the Expression to be deallocated.
1522 Free the strings owned by the Expression. Put the Expression itself, and any
1523 subexpressions that it owns, into a free list.
1525 static void expressionFree( Expression* exp ) {
1527 free( exp->literal );
1528 exp->literal = NULL;
1529 free( exp->table_alias );
1530 exp->table_alias = NULL;
1531 free( exp->column_name );
1532 exp->column_name = NULL;
1533 if( exp->left_operand ) {
1534 expressionFree( exp->left_operand );
1535 exp->left_operand = NULL;
1539 if( exp->right_operand ) {
1540 expressionFree( exp->right_operand );
1541 exp->right_operand = NULL;
1543 if( exp->subquery ) {
1544 storedQFree( exp->subquery );
1545 exp->subquery = NULL;
1548 // We don't free the bind member here because the Expression doesn't own it;
1549 // the bindvar_list hash owns it, so that multiple Expressions can reference it.
1551 if( exp->subexp_list ) {
1552 // Free the linked list of subexpressions
1553 expressionListFree( exp->subexp_list );
1554 exp->subexp_list = NULL;
1557 if( exp->function_name ) {
1558 free( exp->function_name );
1559 exp->function_name = NULL;
1562 // Prepend to the free list
1563 exp->next = free_expression_list;
1564 free_expression_list = exp;
1569 @brief Build a list of subexpressions.
1570 @param state Pointer to the query-building context.
1571 @param id ID of the parent Expression.
1572 @return A pointer to the first in a linked list of Expressions, if there are any; or
1573 NULL if there aren't any, or in case of an error.
1575 static Expression* getExpressionList( BuildSQLState* state, int id ) {
1576 Expression* exp_list = NULL;
1578 // The ORDER BY is in descending order so that we can build the list by adding to
1579 // the head, and it will wind up in the right order.
1580 dbi_result result = dbi_conn_queryf( state->dbhandle,
1581 "SELECT exp.id, exp.type, exp.parenthesize, exp.parent_expr, exp.seq_no, "
1582 "exp.literal, exp.table_alias, exp.column_name, exp.left_operand, exp.operator, "
1583 "exp.right_operand, exp.subquery, exp.cast_type, exp.negate, exp.bind_variable, "
1584 "func.function_name "
1585 "FROM query.expression AS exp LEFT JOIN query.function_sig AS func "
1586 "ON (exp.function_id = func.id) "
1587 "WHERE exp.parent_expr = %d "
1588 "ORDER BY exp.seq_no desc;", id );
1591 if( dbi_result_first_row( result ) ) {
1593 Expression* exp = constructExpression( state, result );
1595 PRINT( "Found a subexpression\n" );
1596 exp->next = exp_list;
1599 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
1600 "Unable to build subexpression list for expression id #%d", id ));
1601 expressionListFree( exp_list );
1605 if( !dbi_result_next_row( result ) )
1611 int errnum = dbi_conn_error( state->dbhandle, &msg );
1612 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
1613 "Unable to query query.expression table for expression list: #%d %s",
1614 errnum, msg ? msg : "No description available" ));
1622 @brief Build a list of ORDER BY items as a linked list of OrderItems.
1623 @param state Pointer to the query-building context.
1624 @param query_id ID for the query to which the ORDER BY belongs.
1625 @return Pointer to the first node in a linked list of OrderItems.
1627 The calling code is responsible for freeing the list by calling orderItemListFree().
1629 static OrderItem* getOrderByList( BuildSQLState* state, int query_id ) {
1630 OrderItem* ord_list = NULL;
1632 // The ORDER BY is in descending order so that we can build the list by adding to
1633 // the head, and it will wind up in the right order.
1634 dbi_result result = dbi_conn_queryf( state->dbhandle,
1635 "SELECT id, stored_query, seq_no, expression "
1636 "FROM query.order_by_item WHERE stored_query = %d ORDER BY seq_no DESC", query_id );
1638 if( dbi_result_first_row( result ) ) {
1640 OrderItem* item = constructOrderItem( state, result );
1642 PRINT( "Found an ORDER BY item\n" );
1644 item->next = ord_list;
1647 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
1648 "Unable to build ORDER BY item for query id #%d", query_id ));
1649 orderItemListFree( ord_list );
1653 if( !dbi_result_next_row( result ) )
1659 int errnum = dbi_conn_error( state->dbhandle, &msg );
1660 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
1661 "Unable to query query.order_by_list table: #%d %s",
1662 errnum, msg ? msg : "No description available" ));
1670 @brief Construct an OrderItem.
1671 @param Pointer to the query-building context.
1672 @param result Database cursor positioned at a row in query.order_by_item.
1673 @return Pointer to a newly constructed OrderItem, if successful, or NULL if not.
1675 The calling code is responsible for freeing the OrderItems by calling orderItemListFree().
1677 static OrderItem* constructOrderItem( BuildSQLState* state, dbi_result result ) {
1678 int id = dbi_result_get_int_idx( result, 1 );
1679 int stored_query_id = dbi_result_get_int_idx( result, 2 );
1680 int seq_no = dbi_result_get_int_idx( result, 3 );
1681 int expression_id = dbi_result_get_int_idx( result, 4 );
1682 // Allocate a SelectItem: from the free list if possible, from the heap if necessary
1684 // Construct an Expression
1685 Expression* expression = getExpression( state, expression_id );
1687 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
1688 "Unable to fetch ORDER BY expression for id = %d", expression_id ));
1693 // Allocate an OrderItem; from the free list if possible, or from the heap if necessary.
1695 if( free_order_item_list ) {
1696 ord = free_order_item_list;
1697 free_order_item_list = free_order_item_list->next;
1699 ord = safe_malloc( sizeof( OrderItem ));
1703 ord->stored_query_id = stored_query_id;
1704 ord->seq_no = seq_no;
1705 ord->expression = expression;
1711 @brief Deallocate a linked list of OrderItems.
1712 @param exp Pointer to the first OrderItem in the list to be deallocated.
1714 Deallocate the memory owned by the OrderItems. Put the items themselves into a free list.
1716 static void orderItemListFree( OrderItem* ord ) {
1718 return; // Nothing to free
1720 OrderItem* first = ord;
1722 expressionFree( ord->expression );
1723 ord->expression = NULL;
1725 if( NULL == ord->next ) {
1726 ord->next = free_order_item_list;
1732 // Transfer the entire list to the free list
1733 free_order_item_list = first;
1737 @brief Build a list of column names for a specified query.
1738 @param state Pointer to the query-building context.
1739 @param query Pointer to the specified query.
1740 @return Pointer to a newly-allocated JSON_ARRAY of column names.
1742 In the resulting array, each entry is either a JSON_STRING or (when no column name is
1743 available) a JSON_NULL.
1745 The calling code is responsible for freeing the list by calling jsonObjectFree().
1747 jsonObject* oilsGetColNames( BuildSQLState* state, StoredQ* query ) {
1748 if( !state || !query )
1751 // Save the outermost query id for possible use in an error message
1754 while( query->type != QT_SELECT ) {
1755 // If the query is a UNION, INTERSECT, or EXCEPT, there must be a SELECT in
1756 // there somewhere. Find the first one, and use the SELECT list from that.
1757 QSeq* child_list = query->child_list;
1762 query = child_list->child_query;
1767 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
1768 "Unable to find first SELECT in query # %d", id ));
1772 // Get the SELECT list for the first SELECT
1773 SelectItem* col = query->select_list;
1776 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
1777 "First SELECT in query # %d has empty SELECT list", id ));
1781 jsonObject* col_list = jsonNewObjectType( JSON_ARRAY );
1783 // Traverse the list, adding an entry for each
1785 const char* alias = NULL;
1786 if( col->column_alias )
1787 alias = col->column_alias;
1789 Expression* expression = col->expression;
1790 if( expression && EXP_COLUMN == expression->type && expression->column_name )
1791 alias = expression->column_name;
1794 jsonObjectPush( col_list, jsonNewObject( alias ) );
1802 @brief Push an IdNode onto a stack of IdNodes.
1803 @param stack Pointer to the stack.
1804 @param id Id of the new node.
1805 @param alias Alias, if any, of the new node.
1807 static void push_id( IdNode** stack, int id, const char* alias ) {
1810 // Allocate a node; from the free list if possible, from the heap if necessary.
1811 IdNode* node = NULL;
1812 if( free_id_node_list ) {
1813 node = free_id_node_list;
1814 free_id_node_list = free_id_node_list->next;
1816 node = safe_malloc( sizeof( IdNode ));
1819 node->next = *stack;
1822 node->alias = strdup( alias );
1832 @brief Remove the node at the top of an IdNode stack.
1833 @param stack Pointer to the IdNode stack.
1835 void pop_id( IdNode** stack ) {
1837 IdNode* node = *stack;
1838 *stack = node->next;
1841 free( node->alias );
1845 node->next = free_id_node_list;
1846 free_id_node_list = node;
1851 @brief Search a stack of IDs for a match by either ID or, optionally, by alias.
1852 @param stack Pointer to the stack.
1853 @param id The id to search for.
1854 @param alias (Optional) the alias to search for.
1855 @return A pointer to the matching node if one is found, or NULL if not.
1857 This search is used to detect cases where a query, expression, or FROM clause is nested
1858 inside itself, in order to avoid infinite recursion; or in order to avoid conflicting
1859 table references in a FROM clause.
1861 static const IdNode* searchIdStack( const IdNode* stack, int id, const char* alias ) {
1863 const IdNode* node = stack;
1865 if( node->id == id )
1866 return node; // Matched on id
1867 else if( alias && node->alias && !strcmp( alias, node->alias ))
1868 return node; // Matched on alias
1873 return NULL; // No match found
1877 @brief Free up any resources held by the StoredQ module.
1879 void storedQCleanup( void ) {
1881 // Free all the nodes in the free state list
1882 StoredQ* sq = free_storedq_list;
1884 free_storedq_list = sq->next;
1886 sq = free_storedq_list;
1889 // Free all the nodes in the free from_relation list
1890 FromRelation* fr = free_from_relation_list;
1892 free_from_relation_list = fr->next;
1894 fr = free_from_relation_list;
1897 // Free all the nodes in the free expression list
1898 Expression* exp = free_expression_list;
1900 free_expression_list = exp->next;
1902 exp = free_expression_list;
1905 // Free all the nodes in the free select item list
1906 SelectItem* sel = free_select_item_list;
1908 free_select_item_list = sel->next;
1910 sel = free_select_item_list;
1913 // Free all the nodes in the free select item list
1914 IdNode* node = free_id_node_list;
1916 free_id_node_list = node->next;
1918 node = free_id_node_list;
1921 // Free all the nodes in the free query sequence list
1922 QSeq* seq = free_qseq_list;
1924 free_qseq_list = seq->next;
1926 seq = free_qseq_list;
1929 // Free all the nodes in the free order item list
1930 OrderItem* ord = free_order_item_list;
1932 free_order_item_list = ord->next;
1934 ord = free_order_item_list;
1937 // Free all the nodes in the bind variable free list
1938 BindVar* bind = free_bindvar_list;
1940 free_bindvar_list = bind->next;
1942 bind = free_bindvar_list;
1947 @brief Return a boolean value from a database result.
1948 @param result The database result.
1949 @param i Index of the column in the result, starting with 1 );
1950 @return 1 if true, or 0 for false.
1952 Null values and error conditions are interpreted as FALSE.
1954 static int oils_result_get_bool_idx( dbi_result result, int i ) {
1956 const char* str = dbi_result_get_string_idx( result, i );
1957 return (str && *str == 't' ) ? 1 : 0;
1963 @brief Enable verbose messages.
1965 The messages are written to standard output, which for a server is /dev/null. Hence this
1966 option is useful only for a non-server. It is intended only as a convenience for
1967 development and debugging.
1969 void oilsStoredQSetVerbose( void ) {