[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