static QSeq* constructQSeq( BuildSQLState* state, dbi_result result ) { int id = dbi_result_get_int_idx( result, 1 ); int parent_query_id = dbi_result_get_int_idx( result, 2 ); int seq_no = dbi_result_get_int_idx( result, 3 ); int child_query_id = dbi_result_get_int_idx( result, 4 ); StoredQ* child_query = getStoredQuery( state, child_query_id ); if( !child_query ) { osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state, "Unable to load child query # %d for parent query %d", child_query_id, parent_query_id )); state->error = 1; return NULL; } // Allocate a QSeq; from the free list if possible, from the heap if necessary QSeq* seq = NULL; if( free_qseq_list ) { seq = free_qseq_list; free_qseq_list = free_qseq_list->next; } else seq = safe_malloc( sizeof( QSeq )); seq->next = NULL; seq->id = id; seq->parent_query_id = parent_query_id; seq->seq_no = seq_no; seq->child_query = child_query; return seq; }
/** @brief Load a specified query from the database query tables. @param ctx Pointer to the current method context. @return Zero if successful, or -1 if not. Method parameters: - query id (key of query.stored_query table) Returns: a hash with two entries: - "token": A character string serving as a token for future references to the query. - "bind_variables" A hash of bind variables; see notes for doParamList(). */ int doPrepare( osrfMethodContext* ctx ) { if(osrfMethodVerifyContext( ctx )) { osrfLogError( OSRF_LOG_MARK, "Invalid method context" ); return -1; } // Get the query id from a method parameter const jsonObject* query_id_obj = jsonObjectGetIndex( ctx->params, 0 ); if( query_id_obj->type != JSON_NUMBER ) { osrfAppSessionStatus( ctx->session, OSRF_STATUS_BADREQUEST, "osrfMethodException", ctx->request, "Invalid parameter; query id must be a number" ); return -1; } int query_id = atoi( jsonObjectGetString( query_id_obj )); if( query_id <= 0 ) { osrfAppSessionStatus( ctx->session, OSRF_STATUS_BADREQUEST, "osrfMethodException", ctx->request, "Invalid parameter: query id must be greater than zero" ); return -1; } osrfLogInfo( OSRF_LOG_MARK, "Loading query for id # %d", query_id ); BuildSQLState* state = buildSQLStateNew( dbhandle ); state->defaults_usable = 1; state->values_required = 0; StoredQ* query = getStoredQuery( state, query_id ); if( state->error ) { osrfLogWarning( OSRF_LOG_MARK, "Unable to load stored query # %d", query_id ); osrfAppSessionStatus( ctx->session, OSRF_STATUS_BADREQUEST, "osrfMethodException", ctx->request, "Unable to load stored query" ); if( state->panic ) { osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state, "Database connection isn't working" )); osrfAppSessionPanic( ctx->session ); } return -1; } const char* token = save_query( ctx, state, query ); osrfLogInfo( OSRF_LOG_MARK, "Token for query id # %d is \"%s\"", query_id, token ); // Build an object to return. It will be a hash containing the query token and a // list of bind variables. jsonObject* returned_obj = jsonNewObjectType( JSON_HASH ); jsonObjectSetKey( returned_obj, "token", jsonNewObject( token )); jsonObjectSetKey( returned_obj, "bind_variables", oilsBindVarList( state->bindvar_list )); osrfAppRespondComplete( ctx, returned_obj ); return 0; }
static Expression* constructExpression( BuildSQLState* state, dbi_result result ) { int id = dbi_result_get_int_idx( result, 1 ); const char* type_str = dbi_result_get_string_idx( result, 2 ); ExprType type; if( !strcmp( type_str, "xbet" )) type = EXP_BETWEEN; else if( !strcmp( type_str, "xbool" )) type = EXP_BOOL; else if( !strcmp( type_str, "xcase" )) type = EXP_CASE; else if( !strcmp( type_str, "xcast" )) type = EXP_CAST; else if( !strcmp( type_str, "xcol" )) type = EXP_COLUMN; else if( !strcmp( type_str, "xex" )) type = EXP_EXIST; else if( !strcmp( type_str, "xfld" )) type = EXP_FIELD; else if( !strcmp( type_str, "xfunc" )) 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" )) type = EXP_NUMBER; else if( !strcmp( type_str, "xop" )) type = EXP_OPERATOR; else if( !strcmp( type_str, "xstr" )) type = EXP_STRING; else if( !strcmp( type_str, "xsubq" )) type = EXP_SUBQUERY; else type = EXP_NULL; // shouldn't happen due to database constraint int parenthesize = oils_result_get_bool_idx( result, 3 ); int parent_expr_id; if( dbi_result_field_is_null_idx( result, 4 )) parent_expr_id = -1; else parent_expr_id = dbi_result_get_int_idx( result, 4 ); int seq_no = dbi_result_get_int_idx( result, 5 ); const char* literal = dbi_result_get_string_idx( result, 6 ); const char* table_alias = dbi_result_get_string_idx( result, 7 ); const char* column_name = dbi_result_get_string_idx( result, 8 ); int left_operand_id; if( dbi_result_field_is_null_idx( result, 9 )) left_operand_id = -1; else left_operand_id = dbi_result_get_int_idx( result, 9 ); const char* operator = dbi_result_get_string_idx( result, 10 ); int right_operand_id; if( dbi_result_field_is_null_idx( result, 11 )) right_operand_id = -1; else right_operand_id = dbi_result_get_int_idx( result, 11 ); int function_id; if( dbi_result_field_is_null_idx( result, 12 )) function_id = -1; else function_id = dbi_result_get_int_idx( result, 12 ); int subquery_id; if( dbi_result_field_is_null_idx( result, 13 )) subquery_id = -1; else subquery_id = dbi_result_get_int_idx( result, 13 ); int cast_type_id; if( dbi_result_field_is_null_idx( result, 14 )) cast_type_id = -1; else cast_type_id = dbi_result_get_int_idx( result, 14 ); Expression* left_operand = NULL; Expression* right_operand = NULL; StoredQ* subquery = NULL; if( EXP_OPERATOR == type ) { // Load left and/or right operands if( -1 == left_operand_id && -1 == right_operand_id ) { osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state, "Expression # %d is an operator with no operands", id )); state->error = 1; return NULL; } if( left_operand_id != -1 ) { left_operand = getExpression( state, left_operand_id ); if( !left_operand ) { osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state, "Unable to get left operand in expression # %d", id )); state->error = 1; return NULL; } } if( right_operand_id != -1 ) { right_operand = getExpression( state, right_operand_id ); if( !right_operand ) { osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state, "Unable to get right operand in expression # %d", id )); state->error = 1; expressionFree( left_operand ); return NULL; } } } else if( EXP_IN == type ) { if( -1 == left_operand_id ) { osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state, "IN condition has no left operand in expression # %d", id )); state->error = 1; return NULL; } else { left_operand = getExpression( state, left_operand_id ); if( !left_operand ) { osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state, "Unable to get left operand for IN condition in expression # %d", id )); state->error = 1; return NULL; } } if( -1 == subquery_id ) { // To do: load IN list of subexpressions osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state, "IN lists not yet supported for expression # %d", id )); state->error = 1; return NULL; } else { subquery = getStoredQuery( state, subquery_id ); if( !subquery ) { osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state, "Unable to load subquery for IN expression # %d", id )); state->error = 1; return NULL; } } } else if( EXP_EXIST == type ) { if( -1 == subquery_id ) { osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state, "Internal error: No subquery found for EXIST expression # %d", id )); state->error = 1; return NULL; } else { subquery = getStoredQuery( state, subquery_id ); if( !subquery ) { osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state, "Unable to load subquery for EXIST expression # %d", id )); state->error = 1; return NULL; } } } else if( EXP_SUBQUERY == type ) { if( -1 == subquery_id ) { osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state, "Subquery expression # %d has no query id", id )); state->error = 1; return NULL; } else { // Load a subquery, if there is one subquery = getStoredQuery( state, subquery_id ); if( !subquery ) { osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state, "Unable to load subquery for expression # %d", id )); state->error = 1; return NULL; } if( subquery->select_list && subquery->select_list->next ) { osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state, "Subquery # %d as expression returns more than one column", subquery_id )); state->error = 1; return NULL; } PRINT( "\tExpression is subquery %d\n", subquery_id ); } } // Allocate an Expression: from the free list if possible, from the heap if necessary Expression* exp = NULL; if( free_expression_list ) { exp = free_expression_list; free_expression_list = free_expression_list->next; } else exp = safe_malloc( sizeof( Expression ) ); // Populate the Expression exp->next = NULL; exp->id = id; exp->type = type; exp->parenthesize = parenthesize; exp->parent_expr_id = parent_expr_id; exp->seq_no = seq_no; exp->literal = literal ? strdup( literal ) : NULL; exp->table_alias = table_alias ? strdup( table_alias ) : NULL; exp->column_name = column_name ? strdup( column_name ) : NULL; exp->left_operand = left_operand; exp->op = operator ? strdup( operator ) : NULL; exp->right_operand = right_operand; exp->function_id = function_id; exp->subquery_id = subquery_id; exp->subquery = subquery; exp->cast_type_id = subquery_id; return exp; }
static FromRelation* constructFromRelation( BuildSQLState* state, dbi_result result ) { // Get the column values from the result int id = dbi_result_get_int_idx( result, 1 ); const char* type_str = dbi_result_get_string_idx( result, 2 ); FromRelationType type; if( !strcmp( type_str, "RELATION" )) type = FRT_RELATION; else if( !strcmp( type_str, "SUBQUERY" )) type = FRT_SUBQUERY; else if( !strcmp( type_str, "FUNCTION" )) type = FRT_FUNCTION; else type = FRT_RELATION; // shouldn't happen due to database constraint const char* table_name = dbi_result_get_string_idx( result, 3 ); const char* class_name = dbi_result_get_string_idx( result, 4 ); int subquery_id; if( dbi_result_field_is_null_idx( result, 5 ) ) subquery_id = -1; else subquery_id = dbi_result_get_int_idx( result, 5 ); int function_call_id; if( dbi_result_field_is_null_idx( result, 6 ) ) function_call_id = -1; else function_call_id = dbi_result_get_int_idx( result, 6 ); const char* table_alias = dbi_result_get_string_idx( result, 7 ); int parent_relation_id; if( dbi_result_field_is_null_idx( result, 8 ) ) parent_relation_id = -1; else parent_relation_id = dbi_result_get_int_idx( result, 8 ); int seq_no = dbi_result_get_int_idx( result, 9 ); JoinType join_type; const char* join_type_str = dbi_result_get_string_idx( result, 10 ); if( !join_type_str ) join_type = JT_NONE; else if( !strcmp( join_type_str, "INNER" ) ) join_type = JT_INNER; else if( !strcmp( join_type_str, "LEFT" ) ) join_type = JT_LEFT; else if( !strcmp( join_type_str, "RIGHT" ) ) join_type = JT_RIGHT; else if( !strcmp( join_type_str, "FULL" ) ) join_type = JT_FULL; else join_type = JT_NONE; // shouldn't happen due to database constraint int on_clause_id; if( dbi_result_field_is_null_idx( result, 11 ) ) on_clause_id = -1; else on_clause_id = dbi_result_get_int_idx( result, 11 ); StoredQ* subquery = NULL; switch ( type ) { case FRT_RELATION : break; case FRT_SUBQUERY : if( -1 == subquery_id ) { osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state, "Internal error: no subquery specified for FROM relation # %d", id )); state->error = 1; return NULL; } if( ! table_alias ) { osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state, "Subquery needs alias in FROM relation # %d", id )); state->error = 1; return NULL; } subquery = getStoredQuery( state, subquery_id ); if( ! subquery ) { osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state, "Unable to load subquery for FROM relation # %d", id )); state->error = 1; return NULL; } break; case FRT_FUNCTION : osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state, "Functions in FROM clause not yet supported" )); state->error = 1; return NULL; } FromRelation* join_list = getJoinList( state, id ); if( state->error ) { osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state, "Unable to load join list for FROM relation # %d", id )); return NULL; } Expression* on_clause = NULL; if( on_clause_id != -1 ) { on_clause = getExpression( state, on_clause_id ); if( !on_clause ) { osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state, "Unable to load ON condition for FROM relation # %d", id )); joinListFree( join_list ); return NULL; } else PRINT( "\tGot an ON condition\n" ); } // Allocate a FromRelation: from the free list if possible, from the heap if necessary FromRelation* fr; if( free_from_relation_list ) { fr = free_from_relation_list; free_from_relation_list = free_from_relation_list->next; } else fr = safe_malloc( sizeof( FromRelation ) ); // Populate the FromRelation fr->next = NULL; fr->id = id; fr->type = type; fr->table_name = table_name ? strdup( table_name ) : NULL; fr->class_name = class_name ? strdup( class_name ) : NULL; fr->subquery_id = subquery_id; fr->subquery = subquery; fr->function_call_id = function_call_id; fr->table_alias = table_alias ? strdup( table_alias ) : NULL; fr->parent_relation_id = parent_relation_id; fr->seq_no = seq_no; fr->join_type = join_type; fr->on_clause = on_clause; fr->join_list = join_list; return fr; }