static inline void decr_indent( BuildSQLState* state );
/**
+ @brief Create a jsonObject representing the current list of bind variables.
+ @param bindvar_list Pointer to the bindvar_list member of a BuildSQLState.
+ @return Pointer to the newly created jsonObject.
+
+ The returned jsonObject is a (possibly empty) JSON_HASH, keyed on the names of the bind
+ variables. The data for each is another level of JSON_HASH with a fixed set of tags:
+ - "label"
+ - "type"
+ - "description"
+ - "default_value" (as a jsonObject)
+ - "actual_value" (as a jsonObject)
+
+ Any non-existent values are represented as JSON_NULLs.
+
+ The calling code is responsible for freeing the returned jsonOjbect by calling
+ jsonObjectFree().
+*/
+jsonObject* oilsBindVarList( osrfHash* bindvar_list ) {
+ jsonObject* list = jsonNewObjectType( JSON_HASH );
+
+ if( bindvar_list && osrfHashGetCount( bindvar_list )) {
+ // Traverse our internal list of bind variables
+ BindVar* bind = NULL;
+ osrfHashIterator* iter = osrfNewHashIterator( bindvar_list );
+ while(( bind = osrfHashIteratorNext( iter ))) {
+ // Create an hash to represent the bind variable
+ jsonObject* bind_obj = jsonNewObjectType( JSON_HASH );
+
+ // Add an entry for each attribute
+ jsonObject* attr = jsonNewObject( bind->label );
+ jsonObjectSetKey( bind_obj, "label", attr );
+
+ const char* type = NULL;
+ switch( bind->type ) {
+ case BIND_STR :
+ type = "string";
+ break;
+ case BIND_NUM :
+ type = "number";
+ break;
+ case BIND_STR_LIST :
+ type = "string_list";
+ break;
+ case BIND_NUM_LIST :
+ type = "number_list";
+ break;
+ default :
+ type = "(invalid)";
+ break;
+ }
+ attr = jsonNewObject( type );
+ jsonObjectSetKey( bind_obj, "type", attr );
+
+ attr = jsonNewObject( bind->description );
+ jsonObjectSetKey( bind_obj, "description", attr );
+
+ attr = jsonObjectClone( bind->default_value );
+ jsonObjectSetKey( bind_obj, "default_value", attr );
+
+ attr = jsonObjectClone( bind->actual_value );
+ jsonObjectSetKey( bind_obj, "actual_value", attr );
+
+ // Add the bind variable to the list
+ jsonObjectSetKey( list, osrfHashIteratorKey( iter ), bind_obj );
+ }
+ osrfHashIteratorFree( iter );
+ }
+
+ return list;
+}
+
+/**
@brief Apply values to bind variables, overriding the defaults, if any.
@param state Pointer to the query-building context.
@param bindings A JSON_HASH of values.
const char* var_name = iter->key;
BindVar* bind = osrfHashGet( state->bindvar_list, var_name );
if( bind ) {
- ;
+ // Apply or replace the value for the specified variable
+ if( bind->actual_value )
+ jsonObjectFree( bind->actual_value );
+ bind->actual_value = jsonObjectClone( value );
} else {
osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
"Can't assign value to bind variable \"%s\": no such variable", var_name ));
decr_indent( state );
}
- // To do: build GROUP BY clause, if there is one
+ // To do: build GROUP BY clause, if there is one
- // Build HAVING clause, if there is one
+ // Build HAVING clause, if there is one
if( query->having_clause ) {
add_newline( state );
buffer_add( state->sql, "HAVING" );
}
decr_indent( state );
}
-
+
// Build ORDER BY clause, if there is one
if( query->order_by_list ) {
buildOrderBy( state, query->order_by_list );
OSRF_BUFFER_ADD( method_name, modulename );
OSRF_BUFFER_ADD( method_name, ".prepare" );
osrfAppRegisterMethod( modulename, OSRF_BUFFER_C_STR( method_name ),
- "doPrepare", "", 1, 0 );
+ "doPrepare", "", 1, 0 );
buffer_reset( method_name );
OSRF_BUFFER_ADD( method_name, modulename );
OSRF_BUFFER_ADD( method_name, ".columns" );
osrfAppRegisterMethod( modulename, OSRF_BUFFER_C_STR( method_name ),
- "doColumns", "", 1, 0 );
+ "doColumns", "", 1, 0 );
+
+ buffer_reset( method_name );
+ OSRF_BUFFER_ADD( method_name, modulename );
+ OSRF_BUFFER_ADD( method_name, ".param_list" );
+ osrfAppRegisterMethod( modulename, OSRF_BUFFER_C_STR( method_name ),
+ "doParamList", "", 1, 0 );
buffer_reset( method_name );
OSRF_BUFFER_ADD( method_name, modulename );
OSRF_BUFFER_ADD( method_name, ".bind_param" );
osrfAppRegisterMethod( modulename, OSRF_BUFFER_C_STR( method_name ),
- "doBindParam", "", 2, 0 );
+ "doBindParam", "", 2, 0 );
buffer_reset( method_name );
OSRF_BUFFER_ADD( method_name, modulename );
OSRF_BUFFER_ADD( method_name, ".execute" );
osrfAppRegisterMethod( modulename, OSRF_BUFFER_C_STR( method_name ),
- "doExecute", "", 1, OSRF_METHOD_STREAMING );
+ "doExecute", "", 1, OSRF_METHOD_STREAMING );
buffer_reset( method_name );
OSRF_BUFFER_ADD( method_name, modulename );
OSRF_BUFFER_ADD( method_name, ".sql" );
osrfAppRegisterMethod( modulename, OSRF_BUFFER_C_STR( method_name ),
- "doSql", "", 1, OSRF_METHOD_STREAMING );
+ "doSql", "", 1, OSRF_METHOD_STREAMING );
buffer_reset( method_name );
OSRF_BUFFER_ADD( method_name, modulename );
OSRF_BUFFER_ADD( method_name, ".finish" );
osrfAppRegisterMethod( modulename, OSRF_BUFFER_C_STR( method_name ),
- "doFinish", "", 1, 0 );
+ "doFinish", "", 1, 0 );
buffer_reset( method_name );
OSRF_BUFFER_ADD( method_name, modulename );
OSRF_BUFFER_ADD( method_name, ".messages" );
osrfAppRegisterMethod( modulename, OSRF_BUFFER_C_STR( method_name ),
- "doMessages", "", 1, 0 );
+ "doMessages", "", 1, 0 );
return 0;
}
}
}
+int doParamList( osrfMethodContext* ctx ) {
+ if(osrfMethodVerifyContext( ctx )) {
+ osrfLogError( OSRF_LOG_MARK, "Invalid method context" );
+ return -1;
+ }
+
+ // Get the query token from a method parameter
+ const jsonObject* token_obj = jsonObjectGetIndex( ctx->params, 0 );
+ if( token_obj->type != JSON_STRING ) {
+ osrfAppSessionStatus( ctx->session, OSRF_STATUS_BADREQUEST, "osrfMethodException",
+ ctx->request, "Invalid parameter; query token must be a string" );
+ return -1;
+ }
+ const char* token = jsonObjectGetString( token_obj );
+
+ // Look up the query token in the session-level userData
+ CachedQuery* query = search_token( ctx, token );
+ if( !query ) {
+ osrfAppSessionStatus( ctx->session, OSRF_STATUS_BADREQUEST, "osrfMethodException",
+ ctx->request, "Invalid query token" );
+ return -1;
+ }
+
+ osrfLogInfo( OSRF_LOG_MARK, "Returning list of bind variables for token %s", token );
+
+ osrfAppRespondComplete( ctx, oilsBindVarList( query->state->bindvar_list ) );
+ return 0;
+}
+
+/**
+ @brief Implement the bind_param method.
+ @param ctx Pointer to the current method context.
+ @return Zero if successful, or -1 if not.
+
+ Method parameters:
+ - query token, as previously returned by the .prepare method.
+ - hash of bind variable values, keyed on bind variable names.
+
+ Returns: Nothing.
+*/
int doBindParam( osrfMethodContext* ctx ) {
if(osrfMethodVerifyContext( ctx )) {
osrfLogError( OSRF_LOG_MARK, "Invalid method context" );