state->error = 1;
return;
}
- //else
- //buffer_add_char( state->sql, ' ' );
decr_indent( state );
}
- // Build WHERE clause, if there is one
+ // To do: build GROUP BY clause, if there is one
+
+ // Build HAVING clause, if there is one
+ if( query->having_clause ) {
+ add_newline( state );
+ buffer_add( state->sql, "HAVING" );
+ incr_indent( state );
+ add_newline( state );
+ buildExpression( state, query->having_clause );
+ if( state->error ) {
+ sqlAddMsg( state, "Unable to build HAVING clause for query # %d", query->id );
+ state->error = 1;
+ return;
+ }
+ decr_indent( state );
+ }
+
+ // Build ORDER BY clause, if there is one
if( query->order_by_list ) {
buildOrderBy( state, query->order_by_list );
if( state->error ) {
return;
}
}
-
+
+ // To do: Build LIMIT clause, if there is one
+
+ // To do: Build OFFSET clause, if there is one
+
state->error = 0;
}
buffer_add( state->sql, effective_alias );
buffer_add_char( state->sql, '\"' );
}
-
+
if( join->on_clause ) {
incr_indent( state );
add_newline( state );
}
static void buildSelectList( BuildSQLState* state, SelectItem* item ) {
-
+
int first = 1;
while( item ) {
if( !first )
switch( expr->type ) {
case EXP_BETWEEN :
+ if( expr->negate )
+ buffer_add( state->sql, "NOT " );
+
sqlAddMsg( state, "BETWEEN expressions not yet supported" );
state->error = 1;
break;
case EXP_BOOL :
+ if( expr->negate )
+ buffer_add( state->sql, "NOT " );
+
if( expr->literal ) {
buffer_add( state->sql, expr->literal );
buffer_add_char( state->sql, ' ' );
buffer_add( state->sql, "FALSE " );
break;
case EXP_CASE :
+ if( expr->negate )
+ buffer_add( state->sql, "NOT " );
+
sqlAddMsg( state, "CASE expressions not yet supported" );
state->error = 1;
break;
- case EXP_CAST : // Type cast
+ case EXP_CAST : // Type cast
sqlAddMsg( state, "Cast expressions not yet supported" );
state->error = 1;
break;
case EXP_COLUMN : // Table column
+ if( expr->negate )
+ buffer_add( state->sql, "NOT " );
+
if( expr->table_alias ) {
buffer_add_char( state->sql, '\"' );
buffer_add( state->sql, expr->table_alias );
"No subquery found for EXIST expression # %d", expr->id ));
state->error = 1;
} else {
+ if( expr->negate )
+ buffer_add( state->sql, "NOT " );
+
buffer_add( state->sql, "EXISTS (" );
incr_indent( state );
build_Query( state, expr->subquery );
}
break;
case EXP_FIELD :
+ sqlAddMsg( state, "Field expressions not yet supported" );
+ state->error = 1;
+ break;
case EXP_FUNCTION :
- sqlAddMsg( state, "Expression type not yet supported" );
+ if( expr->negate )
+ buffer_add( state->sql, "NOT " );
+
+ sqlAddMsg( state, "Function expressions not yet supported" );
state->error = 1;
break;
case EXP_IN :
if( expr->left_operand ) {
buildExpression( state, expr->left_operand );
if( !state->error ) {
+ if( expr->negate )
+ buffer_add( state->sql, "NOT " );
+
if( expr->subquery ) {
buffer_add( state->sql, " IN (" );
incr_indent( state );
}
}
break;
- case EXP_NOT_BETWEEN :
- case EXP_NOT_EXIST :
- case EXP_NOT_IN :
- sqlAddMsg( state, "Expression type not yet supported" );
- state->error = 1;
- break;
case EXP_NULL :
+ if( expr->negate )
+ buffer_add( state->sql, "NOT " );
+
buffer_add( state->sql, "NULL" );
break;
case EXP_NUMBER : // Numeric literal
}
break;
case EXP_OPERATOR :
+ if( expr->negate )
+ buffer_add( state->sql, "NOT (" );
+
if( expr->left_operand ) {
buildExpression( state, expr->left_operand );
if( state->error ) {
break;
}
}
+
+ if( expr->negate )
+ buffer_add_char( state->sql, ')' );
+
break;
case EXP_STRING : // String literal
if( !expr->literal ) {
}
break;
case EXP_SUBQUERY :
+ if( expr->negate )
+ buffer_add( state->sql, "NOT " );
+
if( expr->subquery ) {
buffer_add_char( state->sql, '(' );
incr_indent( state );
}
break;
}
-
+
if( expr->parenthesize )
buffer_add_char( state->sql, ')' );
}
}
}
+ Expression* having_clause = NULL;
+ if( having_clause_id != -1 ) {
+ having_clause = getExpression( state, having_clause_id );
+ if( ! having_clause ) {
+ // shouldn't happen due to foreign key constraint
+ osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
+ "Unable to fetch HAVING expression for query id = %d", id ));
+ expressionFree( where_clause );
+ freeQSeqList( child_list );
+ fromRelationFree( from_clause );
+ selectListFree( select_list );
+ return NULL;
+ }
+ }
+
// Get the ORDER BY clause, if there is one
OrderItem* order_by_list = getOrderByList( state, id );
if( state->error ) {
osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
"Unable to load ORDER BY clause for query %d", id ));
+ expressionFree( having_clause );
expressionFree( where_clause );
freeQSeqList( child_list );
fromRelationFree( from_clause );
selectListFree( select_list );
return NULL;
}
-
+
// Allocate a StoredQ: from the free list if possible, from the heap if necessary
StoredQ* sq;
sq->where_clause = where_clause;
sq->select_list = select_list;
sq->child_list = child_list;
+ sq->having_clause = having_clause;
sq->order_by_list = order_by_list;
return sq;
orderItemListFree( sq->order_by_list );
sq->order_by_list = NULL;
}
+ if( sq->having_clause )
+ expressionFree( sq->having_clause );
// Stick the empty husk on the free list for potential reuse
sq->next = free_storedq_list;
Expression* exp = NULL;
dbi_result result = dbi_conn_queryf( state->dbhandle,
- "SELECT id, type, parenthesize, parent_expr, seq_no, literal, table_alias, "
- "column_name, left_operand, operator, right_operand, function_id, subquery, cast_type "
+ "SELECT id, type, parenthesize, parent_expr, seq_no, literal, table_alias, column_name, "
+ "left_operand, operator, right_operand, function_id, subquery, cast_type, negate "
"FROM query.expression WHERE id = %d;", id );
if( result ) {
if( dbi_result_first_row( result ) ) {
type = EXP_FUNCTION;
else if( !strcmp( type_str, "xin" ))
type = EXP_IN;
- else if( !strcmp( type_str, "xnbet" ))
- type = EXP_NOT_BETWEEN;
- else if( !strcmp( type_str, "xnex" ))
- type = EXP_NOT_EXIST;
- else if( !strcmp( type_str, "xnin" ))
- type = EXP_NOT_IN;
else if( !strcmp( type_str, "xnull" ))
type = EXP_NULL;
else if( !strcmp( type_str, "xnum" ))
else
cast_type_id = dbi_result_get_int_idx( result, 14 );
+ int negate = oils_result_get_bool_idx( result, 15 );
+
Expression* left_operand = NULL;
Expression* right_operand = NULL;
StoredQ* subquery = NULL;
exp->subquery_id = subquery_id;
exp->subquery = subquery;
exp->cast_type_id = subquery_id;
+ exp->negate = negate;
return exp;
}