[open-ils-commits] r16346 - in trunk/Open-ILS: include/openils src/c-apps (scottmk)
svn at svn.open-ils.org
svn at svn.open-ils.org
Thu Apr 29 12:55:08 EDT 2010
Author: scottmk
Date: 2010-04-29 12:55:04 -0400 (Thu, 29 Apr 2010)
New Revision: 16346
Modified:
trunk/Open-ILS/include/openils/oils_buildq.h
trunk/Open-ILS/src/c-apps/oils_qstore.c
trunk/Open-ILS/src/c-apps/oils_storedq.c
Log:
Implement .columns method of qstore server, to return a list
of column names.
Also: add several doxygen-style comments to oils_storedq.c.
M Open-ILS/include/openils/oils_buildq.h
M Open-ILS/src/c-apps/oils_qstore.c
M Open-ILS/src/c-apps/oils_storedq.c
Modified: trunk/Open-ILS/include/openils/oils_buildq.h
===================================================================
--- trunk/Open-ILS/include/openils/oils_buildq.h 2010-04-29 15:53:35 UTC (rev 16345)
+++ trunk/Open-ILS/include/openils/oils_buildq.h 2010-04-29 16:55:04 UTC (rev 16346)
@@ -182,6 +182,8 @@
StoredQ* getStoredQuery( BuildSQLState* state, int query_id );
+jsonObject* oilsGetColNames( BuildSQLState* state, StoredQ* query );
+
void pop_id( IdNode** stack );
void storedQFree( StoredQ* sq );
Modified: trunk/Open-ILS/src/c-apps/oils_qstore.c
===================================================================
--- trunk/Open-ILS/src/c-apps/oils_qstore.c 2010-04-29 15:53:35 UTC (rev 16345)
+++ trunk/Open-ILS/src/c-apps/oils_qstore.c 2010-04-29 16:55:04 UTC (rev 16346)
@@ -86,6 +86,12 @@
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 );
+
+ 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 );
@@ -198,6 +204,52 @@
return 0;
}
+/**
+ @brief Execute an SQL query and return a result set.
+ @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.
+
+ Returns: An array of column names; unavailable names are represented as nulls.
+*/
+int doColumns( 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, "Listing column names for token %s", token );
+
+ jsonObject* col_list = oilsGetColNames( query->state, query->query );
+ if( query->state->error ) {
+ osrfAppSessionStatus( ctx->session, OSRF_STATUS_BADREQUEST, "osrfMethodException",
+ ctx->request, "Unable to get column names" );
+ return -1;
+ } else {
+ osrfAppRespondComplete( ctx, col_list );
+ return 0;
+ }
+}
+
int doBindParam( osrfMethodContext* ctx ) {
if(osrfMethodVerifyContext( ctx )) {
osrfLogError( OSRF_LOG_MARK, "Invalid method context" );
Modified: trunk/Open-ILS/src/c-apps/oils_storedq.c
===================================================================
--- trunk/Open-ILS/src/c-apps/oils_storedq.c 2010-04-29 15:53:35 UTC (rev 16345)
+++ trunk/Open-ILS/src/c-apps/oils_storedq.c 2010-04-29 16:55:04 UTC (rev 16346)
@@ -119,6 +119,14 @@
return sq;
}
+/**
+ @brief Construct a StoredQ.
+ @param Pointer to the query-building context.
+ @param result Database cursor positioned at a row in query.stored_query.
+ @return Pointer to a newly constructed StoredQ, if successful, or NULL if not.
+
+ The calling code is responsible for freeing the StoredQ by calling storedQFree().
+*/
static StoredQ* constructStoredQ( BuildSQLState* state, dbi_result result ) {
// Get the column values from the result
@@ -319,6 +327,14 @@
return child_list;
}
+/**
+ @brief Construct a QSeq.
+ @param Pointer to the query-building context.
+ @param result Database cursor positioned at a row in query.query_sequence.
+ @return Pointer to a newly constructed QSeq, if successful, or NULL if not.
+
+ The calling code is responsible for freeing QSeqs by calling freeQSeqList().
+*/
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 );
@@ -367,7 +383,7 @@
seq = NULL;
}
}
-
+
free_qseq_list = first;
}
@@ -462,6 +478,14 @@
return fr;
}
+/**
+ @brief Construct a FromRelation.
+ @param Pointer to the query-building context.
+ @param result Database cursor positioned at a row in query.from_relation.
+ @return Pointer to a newly constructed FromRelation, if successful, or NULL if not.
+
+ The calling code is responsible for freeing FromRelations by calling joinListFree().
+*/
static FromRelation* constructFromRelation( BuildSQLState* state, dbi_result result ) {
// Get the column values from the result
int id = dbi_result_get_int_idx( result, 1 );
@@ -744,6 +768,14 @@
return select_list;
}
+/**
+ @brief Construct a SelectItem.
+ @param Pointer to the query-building context.
+ @param result Database cursor positioned at a row in query.select_item.
+ @return Pointer to a newly constructed SelectItem, if successful, or NULL if not.
+
+ The calling code is responsible for freeing the SelectItems by calling selectListFree().
+*/
static SelectItem* constructSelectItem( BuildSQLState* state, dbi_result result ) {
// Get the column values
@@ -847,6 +879,14 @@
return exp;
}
+/**
+ @brief Construct an Expression.
+ @param Pointer to the query-building context.
+ @param result Database cursor positioned at a row in query.expression.
+ @return Pointer to a newly constructed Expression, if successful, or NULL if not.
+
+ The calling code is responsible for freeing the Expression by calling expressionFree().
+*/
static Expression* constructExpression( BuildSQLState* state, dbi_result result ) {
int id = dbi_result_get_int_idx( result, 1 );
@@ -1102,6 +1142,14 @@
}
}
+/**
+ @brief Build a list of ORDER BY items as a linked list of OrderItems.
+ @param state Pointer to the query-building context.
+ @param query_id ID for the query to which the ORDER BY belongs.
+ @return Pointer to the first node in a linked list of OrderItems.
+
+ The calling code is responsible for freeing the list by calling orderItemListFree().
+*/
static OrderItem* getOrderByList( BuildSQLState* state, int query_id ) {
OrderItem* ord_list = NULL;
@@ -1141,6 +1189,14 @@
return ord_list;
}
+/**
+ @brief Construct an OrderItem.
+ @param Pointer to the query-building context.
+ @param result Database cursor positioned at a row in query.order_by_item.
+ @return Pointer to a newly constructed OrderItem, if successful, or NULL if not.
+
+ The calling code is responsible for freeing the OrderItems by calling orderItemListFree().
+*/
static OrderItem* constructOrderItem( BuildSQLState* state, dbi_result result ) {
int id = dbi_result_get_int_idx( result, 1 );
int stored_query_id = dbi_result_get_int_idx( result, 2 );
@@ -1200,6 +1256,70 @@
}
/**
+ @brief Build a list of column names for a specified query.
+ @param state Pointer to the query-building context.
+ @param query Pointer to the specified query.
+ @return Pointer to a newly-allocated JSON_ARRAY of column names.
+
+ In the resulting array, each entry is either a JSON_STRING or (when no column name is
+ available) a JSON_NULL.
+
+ The calling code is responsible for freeing the list by calling jsonObjectFree().
+*/
+jsonObject* oilsGetColNames( BuildSQLState* state, StoredQ* query ) {
+ if( !state || !query )
+ return NULL;
+
+ // Save the outermost query id for possible use in an error message
+ int id = query->id;
+
+ // Find the first SELECT, from which we will take the column names
+ while( query->type != QT_SELECT ) {
+ QSeq* child_list = query->child_list;
+ if( !child_list ) {
+ query = NULL;
+ break;
+ } else
+ query = child_list->child_query;
+ }
+
+ if( !query ) {
+ state->error = 1;
+ osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
+ "Unable to find first SELECT in query # %d", id ));
+ return NULL;
+ }
+
+ // Get the SELECT list for the first SELECT
+ SelectItem* col = query->select_list;
+ if( !col ) {
+ state->error = 1;
+ osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
+ "First SELECT in query # %d has empty SELECT list", id ));
+ return NULL;
+ }
+
+ jsonObject* col_list = jsonNewObjectType( JSON_ARRAY );
+
+ // Traverse the list, adding an entry for each
+ do {
+ const char* alias = NULL;
+ if( col->column_alias )
+ alias = col->column_alias;
+ else {
+ Expression* expression = col->expression;
+ if( expression && EXP_COLUMN == expression->type && expression->column_name )
+ alias = expression->column_name;
+ }
+
+ jsonObjectPush( col_list, jsonNewObject( alias ) );
+ col = col->next;
+ } while( col );
+
+ return col_list;
+}
+
+/**
@brief Push an IdNode onto a stack of IdNodes.
@param stack Pointer to the stack.
@param id Id of the new node.
@@ -1352,6 +1472,13 @@
return 0;
}
+/**
+ @brief Enable verbose messages.
+
+ The messages are written to standard output, which for a server is /dev/null. Hence this
+ option is useful only for a non-server. It is intended only as a convenience for
+ development and debugging.
+*/
void oilsStoredQSetVerbose( void ) {
verbose = 1;
}
More information about the open-ils-commits
mailing list