[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