3 @brief Translate an abstract representation of a query into an SQL statement.
10 #include "opensrf/utils.h"
11 #include "opensrf/string_array.h"
12 #include "opensrf/osrf_hash.h"
13 #include "opensrf/osrf_application.h"
14 #include "openils/oils_idl.h"
15 #include "openils/oils_sql.h"
16 #include "openils/oils_buildq.h"
18 static void build_Query( BuildSQLState* state, const StoredQ* query );
19 static void buildCombo( BuildSQLState* state, const StoredQ* query, const char* type_str );
20 static void buildSelect( BuildSQLState* state, const StoredQ* query );
21 static void buildFrom( BuildSQLState* state, const FromRelation* core_from );
22 static void buildJoin( BuildSQLState* state, const FromRelation* join );
23 static void buildSelectList( BuildSQLState* state, const SelectItem* item );
24 static void buildOrderBy( BuildSQLState* state, const OrderItem* ord_list );
25 static void buildExpression( BuildSQLState* state, const Expression* expr );
26 static void buildSeries( BuildSQLState* state, const Expression* subexp_list, const char* op );
27 static void buildBindVar( BuildSQLState* state, const BindVar* bind );
28 static void buildScalar( BuildSQLState* state, int numeric, const jsonObject* obj );
30 static void add_newline( BuildSQLState* state );
31 static inline void incr_indent( BuildSQLState* state );
32 static inline void decr_indent( BuildSQLState* state );
35 @brief Create a jsonObject representing the current list of bind variables.
36 @param bindvar_list Pointer to the bindvar_list member of a BuildSQLState.
37 @return Pointer to the newly created jsonObject.
39 The returned jsonObject is a (possibly empty) JSON_HASH, keyed on the names of the bind
40 variables. The data for each is another level of JSON_HASH with a fixed set of tags:
44 - "default_value" (as a jsonObject)
45 - "actual_value" (as a jsonObject)
47 Any non-existent values are represented as JSON_NULLs.
49 The calling code is responsible for freeing the returned jsonOjbect by calling
52 jsonObject* oilsBindVarList( osrfHash* bindvar_list ) {
53 jsonObject* list = jsonNewObjectType( JSON_HASH );
55 if( bindvar_list && osrfHashGetCount( bindvar_list )) {
56 // Traverse our internal list of bind variables
58 osrfHashIterator* iter = osrfNewHashIterator( bindvar_list );
59 while(( bind = osrfHashIteratorNext( iter ))) {
60 // Create an hash to represent the bind variable
61 jsonObject* bind_obj = jsonNewObjectType( JSON_HASH );
63 // Add an entry for each attribute
64 jsonObject* attr = jsonNewObject( bind->label );
65 jsonObjectSetKey( bind_obj, "label", attr );
67 const char* type = NULL;
68 switch( bind->type ) {
85 attr = jsonNewObject( type );
86 jsonObjectSetKey( bind_obj, "type", attr );
88 attr = jsonNewObject( bind->description );
89 jsonObjectSetKey( bind_obj, "description", attr );
91 attr = jsonObjectClone( bind->default_value );
92 jsonObjectSetKey( bind_obj, "default_value", attr );
94 attr = jsonObjectClone( bind->actual_value );
95 jsonObjectSetKey( bind_obj, "actual_value", attr );
97 // Add the bind variable to the list
98 jsonObjectSetKey( list, osrfHashIteratorKey( iter ), bind_obj );
100 osrfHashIteratorFree( iter );
107 @brief Apply values to bind variables, overriding the defaults, if any.
108 @param state Pointer to the query-building context.
109 @param bindings A JSON_HASH of values.
110 @return 0 if successful, or 1 if not.
112 The @a bindings parameter must be a JSON_HASH. The keys are the names of bind variables.
113 The values are the corresponding values for the variables.
115 int oilsApplyBindValues( BuildSQLState* state, const jsonObject* bindings ) {
117 osrfLogError( OSRF_LOG_MARK, "NULL pointer to state" );
119 } else if( !bindings ) {
120 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
121 "Internal error: No pointer to bindings" ));
123 } else if( bindings->type != JSON_HASH ) {
124 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
125 "Internal error: bindings parameter is not a JSON_HASH" ));
130 jsonObject* value = NULL;
131 jsonIterator* iter = jsonNewIterator( bindings );
132 while(( value = jsonIteratorNext( iter ))) {
133 const char* var_name = iter->key;
134 BindVar* bind = osrfHashGet( state->bindvar_list, var_name );
136 // Apply or replace the value for the specified variable
137 if( bind->actual_value )
138 jsonObjectFree( bind->actual_value );
139 bind->actual_value = jsonObjectClone( value );
141 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
142 "Can't assign value to bind variable \"%s\": no such variable", var_name ));
146 jsonIteratorFree( iter );
152 @brief Build an SQL query.
153 @param state Pointer to the query-building context.
154 @param query Pointer to the query to be built.
155 @return Zero if successful, or 1 if not.
157 Clear the output buffer, call build_Query() to do the work, and add a closing semicolon.
159 int buildSQL( BuildSQLState* state, const StoredQ* query ) {
161 buffer_reset( state->sql );
163 build_Query( state, query );
164 if( ! state->error ) {
165 // Remove the trailing space, if there is one, and add a semicolon.
166 char c = buffer_chomp( state->sql );
168 buffer_add_char( state->sql, c ); // oops, not a space; put it back
169 buffer_add( state->sql, ";\n" );
175 @brief Build an SQL query, appending it to what has been built so far.
176 @param state Pointer to the query-building context.
177 @param query Pointer to the query to be built.
179 Look at the query type and branch to the corresponding routine.
181 static void build_Query( BuildSQLState* state, const StoredQ* query ) {
182 if( buffer_length( state->sql ))
183 add_newline( state );
185 switch( query->type ) {
187 buildSelect( state, query );
190 buildCombo( state, query, "UNION" );
193 buildCombo( state, query, "INTERSECT" );
196 buildCombo( state, query, "EXCEPT" );
199 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
200 "Internal error: invalid query type %d in query # %d",
201 query->type, query->id ));
208 @brief Build a UNION, INTERSECT, or EXCEPT query.
209 @param state Pointer to the query-building context.
210 @param query Pointer to the query to be built.
211 @param type_str The query type, as a string.
213 static void buildCombo( BuildSQLState* state, const StoredQ* query, const char* type_str ) {
215 QSeq* seq = query->child_list;
217 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
218 "Internal error: No child queries within %s query # %d",
219 type_str, query->id ));
224 // Traverse the list of child queries
226 build_Query( state, seq->child_query );
228 sqlAddMsg( state, "Unable to build child query # %d within %s query %d",
229 seq->child_query->id, type_str, query->id );
234 add_newline( state );
235 buffer_add( state->sql, type_str );
236 buffer_add_char( state->sql, ' ' );
238 buffer_add( state->sql, "ALL " );
246 @brief Build a SELECT statement.
247 @param state Pointer to the query-building context.
248 @param query Pointer to the StoredQ structure that represents the query.
250 static void buildSelect( BuildSQLState* state, const StoredQ* query ) {
252 FromRelation* from_clause = query->from_clause;
254 sqlAddMsg( state, "SELECT has no FROM clause in query # %d", query->id );
259 // To do: get SELECT list; just a stub here
260 buffer_add( state->sql, "SELECT" );
261 incr_indent( state );
262 buildSelectList( state, query->select_list );
264 sqlAddMsg( state, "Unable to build SELECT list for query # %d", query->id );
268 decr_indent( state );
270 // Build FROM clause, if there is one
271 if( query->from_clause ) {
272 buildFrom( state, query->from_clause );
274 sqlAddMsg( state, "Unable to build FROM clause for query # %d", query->id );
280 // Build WHERE clause, if there is one
281 if( query->where_clause ) {
282 add_newline( state );
283 buffer_add( state->sql, "WHERE" );
284 incr_indent( state );
285 add_newline( state );
286 buildExpression( state, query->where_clause );
288 sqlAddMsg( state, "Unable to build WHERE clause for query # %d", query->id );
292 decr_indent( state );
295 // To do: build GROUP BY clause, if there is one
297 // Build HAVING clause, if there is one
298 if( query->having_clause ) {
299 add_newline( state );
300 buffer_add( state->sql, "HAVING" );
301 incr_indent( state );
302 add_newline( state );
303 buildExpression( state, query->having_clause );
305 sqlAddMsg( state, "Unable to build HAVING clause for query # %d", query->id );
309 decr_indent( state );
312 // Build ORDER BY clause, if there is one
313 if( query->order_by_list ) {
314 buildOrderBy( state, query->order_by_list );
316 sqlAddMsg( state, "Unable to build ORDER BY clause for query # %d", query->id );
322 // To do: Build LIMIT clause, if there is one
324 // To do: Build OFFSET clause, if there is one
330 @brief Build a FROM clause.
331 @param Pointer to the query-building context.
332 @param Pointer to the StoredQ query to which the FROM clause belongs.
334 static void buildFrom( BuildSQLState* state, const FromRelation* core_from ) {
336 add_newline( state );
337 buffer_add( state->sql, "FROM" );
338 incr_indent( state );
339 add_newline( state );
341 switch( core_from->type ) {
342 case FRT_RELATION : {
343 char* relation = core_from->table_name;
345 if( !core_from->class_name ) {
346 sqlAddMsg( state, "No relation specified for core relation # %d",
352 // Look up table name, view name, or source_definition in the IDL
353 osrfHash* class_hash = osrfHashGet( oilsIDL(), core_from->class_name );
354 relation = oilsGetRelation( class_hash );
358 buffer_add( state->sql, relation );
359 if( !core_from->table_name )
360 free( relation ); // In this case we strdup'd it, must free it
364 buffer_add_char( state->sql, '(' );
365 incr_indent( state );
366 build_Query( state, core_from->subquery );
367 decr_indent( state );
368 add_newline( state );
369 buffer_add_char( state->sql, ')' );
372 sqlAddMsg( state, "Functions in FROM clause not yet supported" );
377 // Add a table alias, if possible
378 if( core_from->table_alias ) {
379 buffer_add( state->sql, " AS \"" );
380 buffer_add( state->sql, core_from->table_alias );
381 buffer_add( state->sql, "\" " );
383 else if( core_from->class_name ) {
384 buffer_add( state->sql, " AS \"" );
385 buffer_add( state->sql, core_from->class_name );
386 buffer_add( state->sql, "\" " );
388 buffer_add_char( state->sql, ' ' );
390 incr_indent( state );
391 FromRelation* join = core_from->join_list;
393 buildJoin( state, join );
395 sqlAddMsg( state, "Unable to build JOIN clause(s) for relation # %d",
401 decr_indent( state );
402 decr_indent( state );
405 static void buildJoin( BuildSQLState* state, const FromRelation* join ) {
406 add_newline( state );
407 switch( join->join_type ) {
409 sqlAddMsg( state, "Non-join relation # %d in JOIN clause", join->id );
413 buffer_add( state->sql, "INNER JOIN " );
416 buffer_add( state->sql, "LEFT JOIN " );
419 buffer_add( state->sql, "RIGHT JOIN " );
422 buffer_add( state->sql, "FULL JOIN " );
425 sqlAddMsg( state, "Unrecognized join type in relation # %d", join->id );
430 switch( join->type ) {
433 if( !join->table_name || ! *join->table_name ) {
434 sqlAddMsg( state, "No relation designated for relation # %d", join->id );
438 buffer_add( state->sql, join->table_name );
442 if( !join->subquery ) {
443 sqlAddMsg( state, "Subquery expected, not found for relation # %d", join->id );
446 } else if( !join->table_alias ) {
447 sqlAddMsg( state, "No table alias for subquery in FROM relation # %d",
452 buffer_add_char( state->sql, '(' );
453 incr_indent( state );
454 build_Query( state, join->subquery );
455 decr_indent( state );
456 add_newline( state );
457 buffer_add_char( state->sql, ')' );
460 if( !join->table_name || ! *join->table_name ) {
461 sqlAddMsg( state, "Joins to functions not yet supported in relation # %d",
469 const char* effective_alias = join->table_alias;
470 if( !effective_alias )
471 effective_alias = join->class_name;
473 if( effective_alias ) {
474 buffer_add( state->sql, " AS \"" );
475 buffer_add( state->sql, effective_alias );
476 buffer_add_char( state->sql, '\"' );
479 if( join->on_clause ) {
480 incr_indent( state );
481 add_newline( state );
482 buffer_add( state->sql, "ON " );
483 buildExpression( state, join->on_clause );
484 decr_indent( state );
487 FromRelation* subjoin = join->join_list;
489 buildJoin( state, subjoin );
491 sqlAddMsg( state, "Unable to build JOIN clause(s) for relation # %d", join->id );
494 subjoin = subjoin->next;
499 @brief Build a SELECT list.
500 @param state Pointer to the query-building context.
501 @param item Pointer to the first in a linked list of SELECT items.
503 static void buildSelectList( BuildSQLState* state, const SelectItem* item ) {
508 buffer_add_char( state->sql, ',' );
509 add_newline( state );
510 buildExpression( state, item->expression );
512 sqlAddMsg( state, "Unable to build an expression for SELECT item # %d", item->id );
517 if( item->column_alias ) {
518 buffer_add( state->sql, " AS \"" );
519 buffer_add( state->sql, item->column_alias );
520 buffer_add_char( state->sql, '\"' );
525 buffer_add_char( state->sql, ' ' );
529 @brief Add an ORDER BY clause to the current query.
530 @param state Pointer to the query-building context.
531 @param ord_list Pointer to the first node in a linked list of OrderItems.
533 static void buildOrderBy( BuildSQLState* state, const OrderItem* ord_list ) {
534 add_newline( state );
535 buffer_add( state->sql, "ORDER BY" );
536 incr_indent( state );
538 int first = 1; // boolean
543 buffer_add_char( state->sql, ',' );
544 add_newline( state );
545 buildExpression( state, ord_list->expression );
547 sqlAddMsg( state, "Unable to add ORDER BY expression # %d", ord_list->id );
551 ord_list = ord_list->next;
554 decr_indent( state );
559 @brief Build an arbitrary expression.
560 @param state Pointer to the query-building context.
561 @param expr Pointer to the Expression representing the expression to be built.
563 static void buildExpression( BuildSQLState* state, const Expression* expr ) {
565 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
566 "Internal error: NULL pointer to Expression" ));
571 if( expr->parenthesize )
572 buffer_add_char( state->sql, '(' );
574 switch( expr->type ) {
577 buffer_add( state->sql, "NOT " );
579 sqlAddMsg( state, "BETWEEN expressions not yet supported" );
583 if( !expr->bind ) { // Sanity check
584 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
585 "Internal error: no variable for bind variable expression" ));
588 buildBindVar( state, expr->bind );
592 buffer_add( state->sql, "NOT " );
594 if( expr->literal ) {
595 buffer_add( state->sql, expr->literal );
596 buffer_add_char( state->sql, ' ' );
598 buffer_add( state->sql, "FALSE " );
602 buffer_add( state->sql, "NOT " );
604 sqlAddMsg( state, "CASE expressions not yet supported" );
607 case EXP_CAST : // Type cast
609 buffer_add( state->sql, "NOT " );
611 sqlAddMsg( state, "Cast expressions not yet supported" );
614 case EXP_COLUMN : // Table column
616 buffer_add( state->sql, "NOT " );
618 if( expr->table_alias ) {
619 buffer_add_char( state->sql, '\"' );
620 buffer_add( state->sql, expr->table_alias );
621 buffer_add( state->sql, "\"." );
623 if( expr->column_name ) {
624 buffer_add( state->sql, expr->column_name );
626 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
627 "Column name not present in expression # %d", expr->id ));
632 if( !expr->subquery ) {
633 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
634 "No subquery found for EXIST expression # %d", expr->id ));
638 buffer_add( state->sql, "NOT " );
640 buffer_add( state->sql, "EXISTS (" );
641 incr_indent( state );
642 build_Query( state, expr->subquery );
643 decr_indent( state );
644 add_newline( state );
645 buffer_add_char( state->sql, ')' );
650 buffer_add( state->sql, "NOT " );
652 sqlAddMsg( state, "Field expressions not yet supported" );
657 buffer_add( state->sql, "NOT " );
659 sqlAddMsg( state, "Function expressions not yet supported" );
663 if( expr->left_operand ) {
664 buildExpression( state, expr->left_operand );
665 if( !state->error ) {
667 buffer_add( state->sql, "NOT " );
669 if( expr->subquery ) {
670 buffer_add( state->sql, " IN (" );
671 incr_indent( state );
672 build_Query( state, expr->subquery );
673 decr_indent( state );
674 add_newline( state );
675 buffer_add_char( state->sql, ')' );
677 sqlAddMsg( state, "IN lists not yet supported" );
684 if( expr->left_operand ) {
685 buildExpression( state, expr->left_operand );
687 sqlAddMsg( state, "Unable to emit left operand in IS NULL expression # %d",
694 buffer_add( state->sql, " IS NOT NULL" );
696 buffer_add( state->sql, " IS NULL" );
700 buffer_add( state->sql, "NOT " );
702 buffer_add( state->sql, "NULL" );
704 case EXP_NUMBER : // Numeric literal
705 if( !expr->literal ) {
706 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
707 "Internal error: No numeric value in string expression # %d", expr->id ));
710 buffer_add( state->sql, expr->literal );
715 buffer_add( state->sql, "NOT (" );
717 if( expr->left_operand ) {
718 buildExpression( state, expr->left_operand );
720 sqlAddMsg( state, "Unable to emit left operand in expression # %d",
725 buffer_add_char( state->sql, ' ' );
726 buffer_add( state->sql, expr->op );
727 buffer_add_char( state->sql, ' ' );
728 if( expr->right_operand ) {
729 buildExpression( state, expr->right_operand );
731 sqlAddMsg( state, "Unable to emit right operand in expression # %d",
738 buffer_add_char( state->sql, ')' );
743 buffer_add( state->sql, "NOT (" );
745 buildSeries( state, expr->subexp_list, expr->op );
747 sqlAddMsg( state, "Unable to build series expression using operator \"%s\"",
748 expr->op ? expr->op : "," );
751 buffer_add_char( state->sql, ')' );
754 case EXP_STRING : // String literal
755 if( !expr->literal ) {
756 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
757 "Internal error: No string value in string expression # %d", expr->id ));
760 // To do: escape special characters in the string
761 buffer_add_char( state->sql, '\'' );
762 buffer_add( state->sql, expr->literal );
763 buffer_add_char( state->sql, '\'' );
768 buffer_add( state->sql, "NOT " );
770 if( expr->subquery ) {
771 buffer_add_char( state->sql, '(' );
772 incr_indent( state );
773 build_Query( state, expr->subquery );
774 decr_indent( state );
775 add_newline( state );
776 buffer_add_char( state->sql, ')' );
778 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
779 "Internal error: No subquery in subquery expression # %d", expr->id ));
785 if( expr->parenthesize )
786 buffer_add_char( state->sql, ')' );
790 @brief Build a series of expressions separated by a specified operator, or by commas.
791 @param state Pointer to the query-building context.
792 @param subexp_list Pointer to the first Expression in a linked list.
793 @param op Pointer to the operator, or NULL for commas.
795 If the operator is AND or OR (in upper, lower, or mixed case), the second and all
796 subsequent operators will begin on a new line.
798 static void buildSeries( BuildSQLState* state, const Expression* subexp_list, const char* op ) {
800 int comma = 0; // Boolean; true if separator is a comma
801 int newline_needed = 0; // Boolean; true if operator is AND or OR
806 } else if( !strcmp( op, "," ))
808 else if( !strcasecmp( op, "AND" ) || !strcasecmp( op, "OR" ))
811 int first = 1; // Boolean; true for first item in list
812 while( subexp_list ) {
814 first = 0; // No separator needed yet
816 // Insert a separator
818 buffer_add( state->sql, ", " );
821 add_newline( state );
823 buffer_add_char( state->sql, ' ' );
825 buffer_add( state->sql, op );
826 buffer_add_char( state->sql, ' ' );
830 buildExpression( state, subexp_list );
831 subexp_list = subexp_list->next;
836 @brief Add the value of a bind variable to an SQL statement.
837 @param state Pointer to the query-building context.
838 @param bind Pointer to the bind variable whose value is to be added to the SQL.
840 The value may be a null, a scalar, or an array of nulls and/or scalars, depending on
841 the type of the bind variable.
843 static void buildBindVar( BuildSQLState* state, const BindVar* bind ) {
845 // Decide where to get the value, if any
846 const jsonObject* value = NULL;
847 if( bind->actual_value )
848 value = bind->actual_value;
849 else if( bind->default_value ) {
850 if( state->defaults_usable )
851 value = bind->default_value;
853 sqlAddMsg( state, "No confirmed value available for bind variable \"%s\"",
858 } else if( state->values_required ) {
859 sqlAddMsg( state, "No value available for bind variable \"%s\"", bind->name );
863 // No value available, and that's okay. Emit the name of the bind variable.
864 buffer_add_char( state->sql, ':' );
865 buffer_add( state->sql, bind->name );
869 // If we get to this point, we know that a value is available. Carry on.
871 int numeric = 0; // Boolean
872 if( BIND_NUM == bind->type || BIND_NUM_LIST == bind->type )
876 switch( bind->type ) {
879 buildScalar( state, numeric, value );
883 if( JSON_ARRAY == value->type ) {
884 // Iterate over array, emit each value
885 int first = 1; // Boolean
886 unsigned long max = value->size;
892 buffer_add( state->sql, ", " );
894 buildScalar( state, numeric, jsonObjectGetIndex( value, i ));
898 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
899 "Invalid value for bind variable; expected a list of values" ));
904 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
905 "Internal error: invalid type for bind variable" ));
911 osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
912 "Unable to emit value of bind variable \"%s\"", bind->name ));
916 @brief Add a number or quoted string to an SQL statement.
917 @param state Pointer to the query-building context.
918 @param numeric Boolean; true if the value is expected to be a number
919 @param obj Pointer to the jsonObject whose value is to be added to the SQL.
921 static void buildScalar( BuildSQLState* state, int numeric, const jsonObject* obj ) {
922 switch( obj->type ) {
924 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
925 "Internal error: hash value for bind variable" ));
929 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
930 "Internal error: array value for bind variable" ));
936 "Invalid value for bind variable: expected a string, found a number" );
939 // To do: escape special characters in the string
940 buffer_add_char( state->sql, '\'' );
941 buffer_add( state->sql, jsonObjectGetString( obj ));
942 buffer_add_char( state->sql, '\'' );
947 buffer_add( state->sql, jsonObjectGetString( obj ));
950 "Invalid value for bind variable: expected a number, found a string" );
955 buffer_add( state->sql, "NULL" );
958 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
959 "Internal error: boolean value for bind variable" ));
963 osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
964 "Internal error: corrupted value for bind variable" ));
971 @brief Start a new line in the output, with the current level of indentation.
972 @param state Pointer to the query-building context.
974 static void add_newline( BuildSQLState* state ) {
975 buffer_add_char( state->sql, '\n' );
978 static const char blanks[] = " "; // 32 blanks
979 static const size_t maxlen = sizeof( blanks ) - 1;
980 const int blanks_per_level = 3;
981 int n = state->indent * blanks_per_level;
983 size_t len = n >= maxlen ? maxlen : n;
984 buffer_add_n( state->sql, blanks, len );
990 @brief Increase the degree of indentation.
991 @param state Pointer to the query-building context.
993 static inline void incr_indent( BuildSQLState* state ) {
998 @brief Reduce the degree of indentation.
999 @param state Pointer to the query-building context.
1001 static inline void decr_indent( BuildSQLState* state ) {