[open-ils-commits] r12200 - trunk/Open-ILS/src/c-apps (scottmk)

svn at svn.open-ils.org svn at svn.open-ils.org
Tue Feb 17 09:03:37 EST 2009


Author: scottmk
Date: 2009-02-17 09:03:35 -0500 (Tue, 17 Feb 2009)
New Revision: 12200

Added:
   trunk/Open-ILS/src/c-apps/test_json_query.c
Modified:
   trunk/Open-ILS/src/c-apps/oils_cstore.c
Log:
Opened a window into the innards of oils_cstore.c.

1. Gave external linkage to the SELECT function.

2. Added a new test_json_query.c, which calls the newly extern
SELECT() to translate a JSON query into SQL.  To be used for
testing, debugging, and troubleshooting.  Note that this
utility calls SELECT() by normal linkage, not by dynamic
loading.


Modified: trunk/Open-ILS/src/c-apps/oils_cstore.c
===================================================================
--- trunk/Open-ILS/src/c-apps/oils_cstore.c	2009-02-17 05:00:41 UTC (rev 12199)
+++ trunk/Open-ILS/src/c-apps/oils_cstore.c	2009-02-17 14:03:35 UTC (rev 12200)
@@ -68,7 +68,7 @@
 static char* searchWHERE ( const jsonObject*, osrfHash*, int, osrfMethodContext* );
 static char* buildSELECT ( jsonObject*, jsonObject*, osrfHash*, osrfMethodContext* );
 
-static char* SELECT ( osrfMethodContext*, jsonObject*, jsonObject*, jsonObject*, jsonObject*, jsonObject*, jsonObject*, jsonObject*, int );
+char* SELECT ( osrfMethodContext*, jsonObject*, jsonObject*, jsonObject*, jsonObject*, jsonObject*, jsonObject*, jsonObject*, int );
 
 void userDataFree( void* );
 static void sessionDataFree( char*, void* );
@@ -2322,7 +2322,7 @@
 	return buffer_release(sql_buf);
 }
 
-static char* SELECT (
+char* SELECT (
 		/* method context */ osrfMethodContext* ctx,
 		
 		/* SELECT   */ jsonObject* selhash,

Added: trunk/Open-ILS/src/c-apps/test_json_query.c
===================================================================
--- trunk/Open-ILS/src/c-apps/test_json_query.c	                        (rev 0)
+++ trunk/Open-ILS/src/c-apps/test_json_query.c	2009-02-17 14:03:35 UTC (rev 12200)
@@ -0,0 +1,261 @@
+/*
+Copyright (C) 2009  Georgia Public Library Service 
+Scott McKellar <scott at esilibrary.com>
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	Description : Translates a JSON query into SQL and writes the
+	results to standard output.  Synopsis:
+
+	test_json_query [-i IDL_file] [-f file_name] [-v] query
+	
+	-i supplies the name of the IDL file.  If no IDL file is specified,
+	   json_test_query uses the value of the environmental variable
+	   OILS_IDL_FILENAME, if it is defined, or defaults to
+	   "/openils/conf/fm_IDL.xml".
+
+	-f supplies the name of a text file containing the JSON query to
+	   be translated.  A file name constisting of a single hyphen
+	   denotes standard input.  If this option is present, all
+	   non-option arguments are ignored.
+
+	-v verbose; outputs the name of the IDL file and the text of the
+	   JSON query.
+
+	If there is no -f option supplied, json_query translates the 
+	first non-option parameter.  This parameter is subject to the
+	usual mangling by the shell.  In most cases it will be sufficient
+	to enclose it in single quotes, but of course any single quotes
+	embedded within the query will need to be escaped.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <opensrf/utils.h>
+#include <opensrf/osrf_json.h>
+#include <opensrf/osrf_application.h>
+#include <opensrf/osrf_app_session.h>
+#include <openils/oils_idl.h>
+
+#define DISABLE_I18N	2
+#define SELECT_DISTINCT 1
+
+// Prototype for SELECT(), which is not in any header
+char* SELECT (
+		/* method context */ osrfMethodContext* ctx,
+		
+		/* SELECT   */ jsonObject* selhash,
+		/* FROM     */ jsonObject* join_hash,
+		/* WHERE    */ jsonObject* search_hash,
+		/* HAVING   */ jsonObject* having_hash,
+		/* ORDER BY */ jsonObject* order_hash,
+		/* LIMIT    */ jsonObject* limit,
+		/* OFFSET   */ jsonObject* offset,
+		/* flags    */ int flags
+);
+
+static int obj_is_true( const jsonObject* obj );
+static int test_json_query( const char* json_query );
+static char* load_query( const char* filename );
+
+int main( int argc, char* argv[] ) {
+
+	// Parse command line
+
+	const char* idl_file_name = NULL;
+	const char* query_file_name = NULL;
+	int verbose = 0;                        // boolean
+
+	int opt;
+	opterr = 0;
+	const char optstring[] = ":f:i:v";
+
+	while( ( opt = getopt( argc, argv, optstring ) ) != -1 ) {
+		switch( opt )
+		{
+			case 'f' :  // get file name of query
+				if( query_file_name ) {
+					fprintf( stderr, "Multiple input files not allowed\n" );
+					return EXIT_FAILURE;
+				}
+				else
+					query_file_name = optarg;
+				break;
+			case 'i' :  // get name of IDL file
+				if( idl_file_name ) {
+					fprintf( stderr, "Multiple IDL file names not allowed\n" );
+					return EXIT_FAILURE;
+				}
+				else
+					idl_file_name = optarg;
+				break;
+			case 'v' :  // Verbose
+				verbose = 1;
+				break;
+			case '?' :  // Invalid option
+				fprintf( stderr, "Invalid option '-%c' on command line\n",
+						 (char) optopt );
+				return EXIT_FAILURE;
+			default :  // Huh?
+				fprintf( stderr, "Internal error: unexpected value '%c'"
+						"for optopt", (char) optopt );
+				return EXIT_FAILURE;
+
+		}
+	}
+
+	// If the command line doesn't specify an IDL file, get it
+	// from an environmental variable, or apply a default
+	if( NULL == idl_file_name ) {
+		idl_file_name = getenv( "OILS_IDL_FILENAME" );
+		if( NULL == idl_file_name )
+			idl_file_name = "/openils/conf/fm_IDL.xml";
+	}
+
+	if( verbose )
+		printf( "IDL file: %s\n", idl_file_name );
+
+	char* loaded_json = NULL;
+	const char* json_query = NULL;
+
+	// Get the JSON query into a string
+	if( query_file_name ) {   // Got a file?  Load it
+		if( optind < argc )
+			fprintf( stderr, "Extra parameter(s) ignored\n" );
+		loaded_json = load_query( query_file_name );
+		if( !loaded_json ) 
+			return EXIT_FAILURE;
+		json_query = loaded_json;
+	} else {                  // No file?  Use command line parameter
+		if ( optind == argc ) {
+			fprintf( stderr, "No JSON query specified\n" );
+			return EXIT_FAILURE;
+		} else
+			json_query = argv[ optind ];
+	}
+
+	if( verbose )
+		printf( "JSON query: %s\n", json_query );
+
+	osrfLogSetLevel( OSRF_LOG_WARNING );    // Suppress informational messages
+	(void) oilsIDLInit( idl_file_name );    // Load IDL into memory
+
+	// Translate the JSON into SQL
+	int rc = test_json_query( json_query );
+
+	if( loaded_json )
+		free( loaded_json );
+
+	return rc ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
+static int test_json_query( const char* json_query ) {
+
+	jsonObject* hash = jsonParseString( json_query );
+	if( !hash ) {
+		fprintf( stderr, "Invalid JSON\n" );
+		return -1;
+	}
+	
+	int flags = 0;
+
+	if ( obj_is_true( jsonObjectGetKey( hash, "distinct" ) ) )
+		flags |= SELECT_DISTINCT;
+
+	if ( obj_is_true( jsonObjectGetKey( hash, "no_i18n" ) ) )
+		flags |= DISABLE_I18N;
+
+	char* sql_query = SELECT(
+		NULL,
+		jsonObjectGetKey( hash, "select" ),
+		jsonObjectGetKey( hash, "from" ),
+		jsonObjectGetKey( hash, "where" ),
+		jsonObjectGetKey( hash, "having" ),
+		jsonObjectGetKey( hash, "order_by" ),
+		jsonObjectGetKey( hash, "limit" ),
+		jsonObjectGetKey( hash, "offset" ),
+		flags
+	);
+
+	if ( !sql_query ) {
+		fprintf( stderr, "Invalid query\n" );
+		return -1;
+	}
+	else
+		printf( "%s\n", sql_query );
+
+	free( sql_query );
+	jsonObjectFree( hash );
+	return 0;
+}
+
+// Interpret a jsonObject as true or false
+static int obj_is_true( const jsonObject* obj ) {
+	if( !obj )
+		return 0;
+	else switch( obj->type )
+	{
+		case JSON_BOOL :
+			if( obj->value.b )
+				return 1;
+			else
+				return 0;
+		case JSON_STRING :
+			if( strcasecmp( obj->value.s, "true" ) )
+				return 0;
+			else
+				return 1;
+			case JSON_NUMBER :          // Support 1/0 for perl's sake
+				if( jsonObjectGetNumber( obj ) == 1.0 )
+					return 1;
+				else
+					return 0;
+		default :
+			return 0;
+	}
+}
+
+static char* load_query( const char* filename ) {
+	FILE* fp;
+
+	// Sanity check
+	if( ! filename || ! *filename ) {
+		fprintf( stderr, "Name of query file is empty or missing\n" );
+		return NULL;
+	}
+
+	// Open query file, or use standard input
+	if( ! strcmp( filename, "-" ) )
+		fp = stdin;
+	else {
+		fp = fopen( filename, "r" );
+		if( !fp ) {
+			fprintf( stderr, "Unable to open query file \"%s\"\n", filename );
+			return NULL;
+		}
+	}
+
+	// Load file into a growing_buffer
+	size_t num_read;
+	char buf[ BUFSIZ + 1 ];
+	growing_buffer* gb = buffer_init( sizeof( buf ) );
+
+    while( ( num_read = fread( buf, 1, sizeof( buf ) - 1, fp ) ) ) {
+		buf[ num_read ] = '\0';
+		buffer_add( gb, buf );
+	}
+
+	if( fp != stdin )
+		fclose( fp );
+
+	return buffer_release( gb );
+}



More information about the open-ils-commits mailing list