[open-ils-commits] r18325 - branches/rel_2_0/Open-ILS/src/c-apps (scottmk)
svn at svn.open-ils.org
svn at svn.open-ils.org
Wed Oct 13 17:12:18 EDT 2010
Author: scottmk
Date: 2010-10-13 17:12:12 -0400 (Wed, 13 Oct 2010)
New Revision: 18325
Modified:
branches/rel_2_0/Open-ILS/src/c-apps/oils_sql.c
Log:
Change the treatment of ORDER BY. Except as noted, these changes
apply only to methods other than json_query.
1. Allow the use of array syntax for specifying an ORDER BY clause
as an array of field specifications, such as can be used in json_query.
The older syntax, using a hash based on class name, is still
available.
2. For json_query, using the array syntax: relax the requirement that a
class be in scope. A field from an out-of-scope class will now be
silently ignored. This change avoids certain problems with fleshing
queries, which use the same order_by array at multiple levels.
3. For the hash syntax: relax the requirement that the class be
referenced in the SELECT clause. Now it suffices that it be in
scope in the generated SQL. As a result, you can now sort by a
column in a joined class without artificially including that column
in the SELECT list.
4. When all or part of an ORDER BY clause is expressed as a string
literal: require that the string not contain any semicolons, in order
to block certain kinds of SQL injection. This measure could create
problems if a semicolon appears within a quoted string -- which is
possible in theory but highly improbable in practice.
5. Don't include a virtual field in an ORDER BY clause. If one is
specified, silently ignore it.
M Open-ILS/src/c-apps/oils_sql.c
Modified: branches/rel_2_0/Open-ILS/src/c-apps/oils_sql.c
===================================================================
--- branches/rel_2_0/Open-ILS/src/c-apps/oils_sql.c 2010-10-13 20:18:23 UTC (rev 18324)
+++ branches/rel_2_0/Open-ILS/src/c-apps/oils_sql.c 2010-10-13 21:12:12 UTC (rev 18325)
@@ -90,8 +90,11 @@
jsonObject*, const char*, osrfMethodContext* );
static char* searchPredicate ( const ClassInfo*, osrfHash*, jsonObject*, osrfMethodContext* );
static char* searchJOIN ( const jsonObject*, const ClassInfo* left_info );
-static char* searchWHERE ( const jsonObject*, const ClassInfo*, int, osrfMethodContext* );
-static char* buildSELECT ( jsonObject*, jsonObject*, osrfHash*, osrfMethodContext* );
+static char* searchWHERE ( const jsonObject* search_hash, const ClassInfo*, int, osrfMethodContext* );
+static char* buildSELECT( const jsonObject*, jsonObject* rest_of_query,
+ osrfHash* meta, osrfMethodContext* ctx );
+static char* buildOrderByFromArray( osrfMethodContext* ctx, const jsonObject* order_array );
+
char* buildQuery( osrfMethodContext* ctx, jsonObject* query, int flags );
char* SELECT ( osrfMethodContext*, jsonObject*, const jsonObject*, const jsonObject*,
@@ -4277,7 +4280,6 @@
jsonIteratorFree( selclass_itr );
}
-
char* col_list = buffer_release( select_buf );
// Make sure the SELECT list isn't empty. This can happen, for example,
@@ -4392,172 +4394,23 @@
}
}
- growing_buffer* order_buf = NULL; // to collect ORDER BY list
-
// Build an ORDER BY clause, if there is one
if( NULL == order_hash )
; // No ORDER BY? do nothing
else if( JSON_ARRAY == order_hash->type ) {
- // Array of field specifications, each specification being a
- // hash to define the class, field, and other details
- int order_idx = 0;
- jsonObject* order_spec;
- while( (order_spec = jsonObjectGetIndex( order_hash, order_idx++ ) ) ) {
-
- if( JSON_HASH != order_spec->type ) {
- osrfLogError( OSRF_LOG_MARK,
- "%s: Malformed field specification in ORDER BY clause; expected JSON_HASH, found %s",
- modulename, json_type( order_spec->type ) );
- if( ctx )
- osrfAppSessionStatus(
- ctx->session,
- OSRF_STATUS_INTERNALSERVERERROR,
- "osrfMethodException",
- ctx->request,
- "Malformed ORDER BY clause -- see error log for more details"
- );
- buffer_free( order_buf );
- free( having_buf );
- buffer_free( group_buf );
- buffer_free( sql_buf );
- if( defaultselhash )
- jsonObjectFree( defaultselhash );
- return NULL;
- }
-
- const char* class_alias =
- jsonObjectGetString( jsonObjectGetKeyConst( order_spec, "class" ) );
- const char* field =
- jsonObjectGetString( jsonObjectGetKeyConst( order_spec, "field" ) );
-
- if( order_buf )
- OSRF_BUFFER_ADD( order_buf, ", " );
- else
- order_buf = buffer_init( 128 );
-
- if( !field || !class_alias ) {
- osrfLogError( OSRF_LOG_MARK,
- "%s: Missing class or field name in field specification "
- "of ORDER BY clause",
- modulename );
- if( ctx )
- osrfAppSessionStatus(
- ctx->session,
- OSRF_STATUS_INTERNALSERVERERROR,
- "osrfMethodException",
- ctx->request,
- "Malformed ORDER BY clause -- see error log for more details"
- );
- buffer_free( order_buf );
- free( having_buf );
- buffer_free( group_buf );
- buffer_free( sql_buf );
- if( defaultselhash )
- jsonObjectFree( defaultselhash );
- return NULL;
- }
-
- ClassInfo* order_class_info = search_alias( class_alias );
- if( ! order_class_info ) {
- osrfLogError( OSRF_LOG_MARK, "%s: ORDER BY clause references class \"%s\" "
- "not in FROM clause", modulename, class_alias );
- if( ctx )
- osrfAppSessionStatus(
- ctx->session,
- OSRF_STATUS_INTERNALSERVERERROR,
- "osrfMethodException",
- ctx->request,
- "Invalid class referenced in ORDER BY clause -- "
- "see error log for more details"
- );
- free( having_buf );
- buffer_free( group_buf );
- buffer_free( sql_buf );
- if( defaultselhash )
- jsonObjectFree( defaultselhash );
- return NULL;
- }
-
- osrfHash* field_def = osrfHashGet( order_class_info->fields, field );
- if( !field_def ) {
- osrfLogError( OSRF_LOG_MARK,
- "%s: Invalid field \"%s\".%s referenced in ORDER BY clause",
- modulename, class_alias, field );
- if( ctx )
- osrfAppSessionStatus(
- ctx->session,
- OSRF_STATUS_INTERNALSERVERERROR,
- "osrfMethodException",
- ctx->request,
- "Invalid field referenced in ORDER BY clause -- "
- "see error log for more details"
- );
- free( having_buf );
- buffer_free( group_buf );
- buffer_free( sql_buf );
- if( defaultselhash )
- jsonObjectFree( defaultselhash );
- return NULL;
- } else if( str_is_true( osrfHashGet( field_def, "virtual" ) ) ) {
- osrfLogError( OSRF_LOG_MARK, "%s: Virtual field \"%s\" in ORDER BY clause",
- modulename, field );
- if( ctx )
- osrfAppSessionStatus(
- ctx->session,
- OSRF_STATUS_INTERNALSERVERERROR,
- "osrfMethodException",
- ctx->request,
- "Virtual field in ORDER BY clause -- see error log for more details"
- );
- buffer_free( order_buf );
- free( having_buf );
- buffer_free( group_buf );
- buffer_free( sql_buf );
- if( defaultselhash )
- jsonObjectFree( defaultselhash );
- return NULL;
- }
-
- if( jsonObjectGetKeyConst( order_spec, "transform" ) ) {
- char* transform_str = searchFieldTransform(
- class_alias, field_def, order_spec );
- if( ! transform_str ) {
- if( ctx )
- osrfAppSessionStatus(
- ctx->session,
- OSRF_STATUS_INTERNALSERVERERROR,
- "osrfMethodException",
- ctx->request,
- "Severe query error in ORDER BY clause -- "
- "see error log for more details"
- );
- buffer_free( order_buf );
- free( having_buf );
- buffer_free( group_buf );
- buffer_free( sql_buf );
- if( defaultselhash )
- jsonObjectFree( defaultselhash );
- return NULL;
- }
-
- OSRF_BUFFER_ADD( order_buf, transform_str );
- free( transform_str );
- }
- else
- buffer_fadd( order_buf, "\"%s\".%s", class_alias, field );
-
- const char* direction =
- jsonObjectGetString( jsonObjectGetKeyConst( order_spec, "direction" ) );
- if( direction ) {
- if( direction[ 0 ] || 'D' == direction[ 0 ] )
- OSRF_BUFFER_ADD( order_buf, " DESC" );
- else
- OSRF_BUFFER_ADD( order_buf, " ASC" );
- }
+ order_by_list = buildOrderByFromArray( ctx, order_hash );
+ if( !order_by_list ) {
+ free( having_buf );
+ buffer_free( group_buf );
+ buffer_free( sql_buf );
+ if( defaultselhash )
+ jsonObjectFree( defaultselhash );
+ return NULL;
}
} else if( JSON_HASH == order_hash->type ) {
// This hash is keyed on class alias. Each class has either
// an array of field names or a hash keyed on field name.
+ growing_buffer* order_buf = NULL; // to collect ORDER BY list
jsonIterator* class_itr = jsonNewIterator( order_hash );
while( (snode = jsonIteratorNext( class_itr )) ) {
@@ -4573,7 +4426,7 @@
"osrfMethodException",
ctx->request,
"Invalid class referenced in ORDER BY clause -- "
- "see error log for more details"
+ "see error log for more details"
);
jsonIteratorFree( class_itr );
buffer_free( order_buf );
@@ -4820,6 +4673,8 @@
}
} // end while
jsonIteratorFree( class_itr );
+ if( order_buf )
+ order_by_list = buffer_release( order_buf );
} else {
osrfLogError( OSRF_LOG_MARK,
"%s: Malformed ORDER BY clause; expected JSON_HASH or JSON_ARRAY, found %s",
@@ -4832,7 +4687,6 @@
ctx->request,
"Malformed ORDER BY clause -- see error log for more details"
);
- buffer_free( order_buf );
free( having_buf );
buffer_free( group_buf );
buffer_free( sql_buf );
@@ -4840,12 +4694,8 @@
jsonObjectFree( defaultselhash );
return NULL;
}
-
- if( order_buf )
- order_by_list = buffer_release( order_buf );
}
-
string = buffer_release( group_buf );
if( *string && ( aggregate_found || (flags & SELECT_DISTINCT) ) ) {
@@ -4891,26 +4741,199 @@
} // end of SELECT()
-static char* buildSELECT ( jsonObject* search_hash, jsonObject* order_hash, osrfHash* meta, osrfMethodContext* ctx ) {
+/**
+ @brief Build a list of ORDER BY expressions.
+ @param ctx Pointer to the method context.
+ @param order_array Pointer to a JSON_ARRAY of field specifications.
+ @return Pointer to a string containing a comma-separated list of ORDER BY expressions.
+ Each expression may be either a column reference or a function call whose first parameter
+ is a column reference.
+ Each entry in @a order_array must be a JSON_HASH with values for "class" and "field".
+ It may optionally include entries for "direction" and/or "transform".
+
+ The calling code is responsible for freeing the returned string.
+*/
+static char* buildOrderByFromArray( osrfMethodContext* ctx, const jsonObject* order_array ) {
+ if( ! order_array ) {
+ osrfLogError( OSRF_LOG_MARK, "%s: Logic error: NULL pointer for ORDER BY clause",
+ modulename );
+ if( ctx )
+ osrfAppSessionStatus(
+ ctx->session,
+ OSRF_STATUS_INTERNALSERVERERROR,
+ "osrfMethodException",
+ ctx->request,
+ "Logic error: ORDER BY clause expected, not found; "
+ "see error log for more details"
+ );
+ return NULL;
+ } else if( order_array->type != JSON_ARRAY ) {
+ osrfLogError( OSRF_LOG_MARK,
+ "%s: Logic error: Expected JSON_ARRAY for ORDER BY clause, not found", modulename );
+ if( ctx )
+ osrfAppSessionStatus(
+ ctx->session,
+ OSRF_STATUS_INTERNALSERVERERROR,
+ "osrfMethodException",
+ ctx->request,
+ "Logic error: Unexpected format for ORDER BY clause; see error log for more details" );
+ return NULL;
+ }
+
+ growing_buffer* order_buf = buffer_init( 128 );
+ int first = 1; // boolean
+ int order_idx = 0;
+ jsonObject* order_spec;
+ while( (order_spec = jsonObjectGetIndex( order_array, order_idx++ ))) {
+
+ if( JSON_HASH != order_spec->type ) {
+ osrfLogError( OSRF_LOG_MARK,
+ "%s: Malformed field specification in ORDER BY clause; "
+ "expected JSON_HASH, found %s",
+ modulename, json_type( order_spec->type ) );
+ if( ctx )
+ osrfAppSessionStatus(
+ ctx->session,
+ OSRF_STATUS_INTERNALSERVERERROR,
+ "osrfMethodException",
+ ctx->request,
+ "Malformed ORDER BY clause -- see error log for more details"
+ );
+ buffer_free( order_buf );
+ return NULL;
+ }
+
+ const char* class_alias =
+ jsonObjectGetString( jsonObjectGetKeyConst( order_spec, "class" ));
+ const char* field =
+ jsonObjectGetString( jsonObjectGetKeyConst( order_spec, "field" ));
+
+ if( !field || !class_alias ) {
+ osrfLogError( OSRF_LOG_MARK,
+ "%s: Missing class or field name in field specification of ORDER BY clause",
+ modulename );
+ if( ctx )
+ osrfAppSessionStatus(
+ ctx->session,
+ OSRF_STATUS_INTERNALSERVERERROR,
+ "osrfMethodException",
+ ctx->request,
+ "Malformed ORDER BY clause -- see error log for more details"
+ );
+ buffer_free( order_buf );
+ return NULL;
+ }
+
+ const ClassInfo* order_class_info = search_alias( class_alias );
+ if( ! order_class_info ) {
+ osrfLogInternal( OSRF_LOG_MARK, "%s: ORDER BY clause references class \"%s\" "
+ "not in FROM clause, skipping it", modulename, class_alias );
+ continue;
+ }
+
+ // Add a separating comma, except at the beginning
+ if( first )
+ first = 0;
+ else
+ OSRF_BUFFER_ADD( order_buf, ", " );
+
+ osrfHash* field_def = osrfHashGet( order_class_info->fields, field );
+ if( !field_def ) {
+ osrfLogError( OSRF_LOG_MARK,
+ "%s: Invalid field \"%s\".%s referenced in ORDER BY clause",
+ modulename, class_alias, field );
+ if( ctx )
+ osrfAppSessionStatus(
+ ctx->session,
+ OSRF_STATUS_INTERNALSERVERERROR,
+ "osrfMethodException",
+ ctx->request,
+ "Invalid field referenced in ORDER BY clause -- "
+ "see error log for more details"
+ );
+ free( order_buf );
+ return NULL;
+ } else if( str_is_true( osrfHashGet( field_def, "virtual" ) ) ) {
+ osrfLogError( OSRF_LOG_MARK, "%s: Virtual field \"%s\" in ORDER BY clause",
+ modulename, field );
+ if( ctx )
+ osrfAppSessionStatus(
+ ctx->session,
+ OSRF_STATUS_INTERNALSERVERERROR,
+ "osrfMethodException",
+ ctx->request,
+ "Virtual field in ORDER BY clause -- see error log for more details"
+ );
+ buffer_free( order_buf );
+ return NULL;
+ }
+
+ if( jsonObjectGetKeyConst( order_spec, "transform" )) {
+ char* transform_str = searchFieldTransform( class_alias, field_def, order_spec );
+ if( ! transform_str ) {
+ if( ctx )
+ osrfAppSessionStatus(
+ ctx->session,
+ OSRF_STATUS_INTERNALSERVERERROR,
+ "osrfMethodException",
+ ctx->request,
+ "Severe query error in ORDER BY clause -- "
+ "see error log for more details"
+ );
+ buffer_free( order_buf );
+ return NULL;
+ }
+
+ OSRF_BUFFER_ADD( order_buf, transform_str );
+ free( transform_str );
+ }
+ else
+ buffer_fadd( order_buf, "\"%s\".%s", class_alias, field );
+
+ const char* direction =
+ jsonObjectGetString( jsonObjectGetKeyConst( order_spec, "direction" ) );
+ if( direction ) {
+ if( direction[ 0 ] || 'D' == direction[ 0 ] )
+ OSRF_BUFFER_ADD( order_buf, " DESC" );
+ else
+ OSRF_BUFFER_ADD( order_buf, " ASC" );
+ }
+ }
+
+ return buffer_release( order_buf );
+}
+
+/**
+ @brief Build a SELECT statement.
+ @param search_hash Pointer to a JSON_HASH or JSON_ARRAY encoding the WHERE clause.
+ @param rest_of_query Pointer to a JSON_HASH containing any other SQL clauses.
+ @param meta Pointer to the class metadata for the core class.
+ @param ctx Pointer to the method context.
+ @return Pointer to a character string containing the WHERE clause; or NULL upon error.
+
+ Within the rest_of_query hash, the meaningful keys are "join", "select", "no_i18n",
+ "order_by", "limit", and "offset".
+
+ The SELECT statements built here are distinct from those built for the json_query method.
+*/
+static char* buildSELECT ( const jsonObject* search_hash, jsonObject* rest_of_query,
+ osrfHash* meta, osrfMethodContext* ctx ) {
+
const char* locale = osrf_message_get_last_locale();
osrfHash* fields = osrfHashGet( meta, "fields" );
- char* core_class = osrfHashGet( meta, "classname" );
+ const char* core_class = osrfHashGet( meta, "classname" );
- const jsonObject* join_hash = jsonObjectGetKeyConst( order_hash, "join" );
+ const jsonObject* join_hash = jsonObjectGetKeyConst( rest_of_query, "join" );
- jsonObject* node = NULL;
- jsonObject* snode = NULL;
- jsonObject* onode = NULL;
- const jsonObject* _tmp = NULL;
jsonObject* selhash = NULL;
jsonObject* defaultselhash = NULL;
growing_buffer* sql_buf = buffer_init( 128 );
growing_buffer* select_buf = buffer_init( 128 );
- if( !(selhash = jsonObjectGetKey( order_hash, "select" )) ) {
+ if( !(selhash = jsonObjectGetKey( rest_of_query, "select" )) ) {
defaultselhash = jsonNewObjectType( JSON_HASH );
selhash = defaultselhash;
}
@@ -4932,20 +4955,24 @@
jsonObjectSetKey( selhash, core_class, field_list );
}
+ // Build a list of columns for the SELECT clause
int first = 1;
+ const jsonObject* snode = NULL;
jsonIterator* class_itr = jsonNewIterator( selhash );
- while( (snode = jsonIteratorNext( class_itr )) ) {
+ while( (snode = jsonIteratorNext( class_itr )) ) { // For each class
+ // If the class isn't in the IDL, ignore it
const char* cname = class_itr->key;
osrfHash* idlClass = osrfHashGet( oilsIDL(), cname );
if( !idlClass )
continue;
- if( strcmp(core_class,class_itr->key )) {
+ // If the class isn't the core class, and isn't in the JOIN clause, ignore it
+ if( strcmp( core_class, class_itr->key )) {
if( !join_hash )
continue;
- jsonObject* found = jsonObjectFindPath( join_hash, "//%s", class_itr->key );
+ jsonObject* found = jsonObjectFindPath( join_hash, "//%s", class_itr->key );
if( !found->size ) {
jsonObjectFree( found );
continue;
@@ -4954,6 +4981,7 @@
jsonObjectFree( found );
}
+ const jsonObject* node = NULL;
jsonIterator* select_itr = jsonNewIterator( snode );
while( (node = jsonIteratorNext( select_itr )) ) {
const char* item_str = jsonObjectGetString( node );
@@ -4971,7 +4999,7 @@
if( locale ) {
const char* i18n;
- const jsonObject* no_i18n_obj = jsonObjectGetKeyConst( order_hash, "no_i18n" );
+ const jsonObject* no_i18n_obj = jsonObjectGetKeyConst( rest_of_query, "no_i18n" );
if( obj_is_true( no_i18n_obj ) ) // Suppress internationalization?
i18n = NULL;
else
@@ -5019,9 +5047,13 @@
ctx->request,
"Unable to build query frame for core class"
);
+ buffer_free( sql_buf );
+ if( defaultselhash )
+ jsonObjectFree( defaultselhash );
return NULL;
}
+ // Add the JOIN clauses, if any
if( join_hash ) {
char* join_clause = searchJOIN( join_hash, &curr_query->core );
OSRF_BUFFER_ADD_CHAR( sql_buf, ' ' );
@@ -5030,10 +5062,11 @@
}
osrfLogDebug( OSRF_LOG_MARK, "%s pre-predicate SQL = %s",
- modulename, OSRF_BUFFER_C_STR( sql_buf ));
+ modulename, OSRF_BUFFER_C_STR( sql_buf ));
OSRF_BUFFER_ADD( sql_buf, " WHERE " );
+ // Add the conditions in the WHERE clause
char* pred = searchWHERE( search_hash, &curr_query->core, AND_OP_JOIN, ctx );
if( !pred ) {
osrfAppSessionStatus(
@@ -5053,112 +5086,168 @@
free( pred );
}
- if( order_hash ) {
- char* string = NULL;
- if( (_tmp = jsonObjectGetKeyConst( order_hash, "order_by" )) ){
+ // Add the ORDER BY, LIMIT, and/or OFFSET clauses, if present
+ if( rest_of_query ) {
+ const jsonObject* order_by = NULL;
+ if( ( order_by = jsonObjectGetKeyConst( rest_of_query, "order_by" )) ){
- growing_buffer* order_buf = buffer_init( 128 );
+ char* order_by_list = NULL;
- first = 1;
- jsonIterator* class_itr = jsonNewIterator( _tmp );
- while( (snode = jsonIteratorNext( class_itr )) ) {
+ if( JSON_ARRAY == order_by->type ) {
+ order_by_list = buildOrderByFromArray( ctx, order_by );
+ if( !order_by_list ) {
+ buffer_free( sql_buf );
+ if( defaultselhash )
+ jsonObjectFree( defaultselhash );
+ clear_query_stack();
+ return NULL;
+ }
+ } else if( JSON_HASH == order_by->type ) {
+ // We expect order_by to be a JSON_HASH keyed on class names. Traverse it
+ // and build a list of ORDER BY expressions.
+ growing_buffer* order_buf = buffer_init( 128 );
+ first = 1;
+ jsonIterator* class_itr = jsonNewIterator( order_by );
+ while( (snode = jsonIteratorNext( class_itr )) ) { // For each class:
- if( !jsonObjectGetKeyConst( selhash,class_itr->key ))
- continue;
+ ClassInfo* order_class_info = search_alias( class_itr->key );
+ if( ! order_class_info )
+ continue; // class not referenced by FROM clause? Ignore it.
- if( snode->type == JSON_HASH ) {
+ if( JSON_HASH == snode->type ) {
- jsonIterator* order_itr = jsonNewIterator( snode );
- while( (onode = jsonIteratorNext( order_itr )) ) {
+ // If the data for the current class is a JSON_HASH, then it is
+ // keyed on field name.
- osrfHash* field_def = oilsIDLFindPath( "/%s/fields/%s",
- class_itr->key, order_itr->key );
- if( !field_def )
- continue;
+ const jsonObject* onode = NULL;
+ jsonIterator* order_itr = jsonNewIterator( snode );
+ while( (onode = jsonIteratorNext( order_itr )) ) { // For each field
- char* direction = NULL;
- if( onode->type == JSON_HASH ) {
- if( jsonObjectGetKeyConst( onode, "transform" ) ) {
- string = searchFieldTransform( class_itr->key, field_def, onode );
- if( ! string ) {
- osrfAppSessionStatus(
- ctx->session,
- OSRF_STATUS_INTERNALSERVERERROR,
- "osrfMethodException",
- ctx->request,
- "Severe query error in ORDER BY clause -- "
- "see error log for more details"
- );
- jsonIteratorFree( order_itr );
- jsonIteratorFree( class_itr );
- buffer_free( order_buf );
- buffer_free( sql_buf );
- if( defaultselhash )
- jsonObjectFree( defaultselhash );
- clear_query_stack();
- return NULL;
+ //osrfHash* field_def = oilsIDLFindPath( "/%s/fields/%s",
+ // class_itr->key, order_itr->key );
+ osrfHash* field_def = osrfHashGet(
+ order_class_info->fields, order_itr->key );
+ if( !field_def )
+ continue; // Field not defined in IDL? Ignore it.
+ if( str_is_true( osrfHashGet( field_def, "virtual")))
+ continue; // Field is virtual? Ignore it.
+
+ char* field_str = NULL;
+ char* direction = NULL;
+ if( onode->type == JSON_HASH ) {
+ if( jsonObjectGetKeyConst( onode, "transform" ) ) {
+ field_str = searchFieldTransform(
+ class_itr->key, field_def, onode );
+ if( ! field_str ) {
+ osrfAppSessionStatus(
+ ctx->session,
+ OSRF_STATUS_INTERNALSERVERERROR,
+ "osrfMethodException",
+ ctx->request,
+ "Severe query error in ORDER BY clause -- "
+ "see error log for more details"
+ );
+ jsonIteratorFree( order_itr );
+ jsonIteratorFree( class_itr );
+ buffer_free( order_buf );
+ buffer_free( sql_buf );
+ if( defaultselhash )
+ jsonObjectFree( defaultselhash );
+ clear_query_stack();
+ return NULL;
+ }
+ } else {
+ growing_buffer* field_buf = buffer_init( 16 );
+ buffer_fadd( field_buf, "\"%s\".%s",
+ class_itr->key, order_itr->key );
+ field_str = buffer_release( field_buf );
}
+
+ if( ( order_by = jsonObjectGetKeyConst( onode, "direction" )) ) {
+ const char* dir = jsonObjectGetString( order_by );
+ if(!strncasecmp( dir, "d", 1 )) {
+ direction = " DESC";
+ }
+ }
} else {
- growing_buffer* field_buf = buffer_init( 16 );
- buffer_fadd( field_buf, "\"%s\".%s",
- class_itr->key, order_itr->key );
- string = buffer_release( field_buf );
- }
-
- if( (_tmp = jsonObjectGetKeyConst( onode, "direction" )) ) {
- const char* dir = jsonObjectGetString( _tmp );
- if(!strncasecmp( dir, "d", 1 )) {
+ field_str = strdup( order_itr->key );
+ const char* dir = jsonObjectGetString( onode );
+ if( !strncasecmp( dir, "d", 1 )) {
direction = " DESC";
+ } else {
+ direction = " ASC";
}
}
- } else {
- string = strdup( order_itr->key );
- const char* dir = jsonObjectGetString( onode );
- if( !strncasecmp( dir, "d", 1 )) {
- direction = " DESC";
+
+ if( first ) {
+ first = 0;
} else {
- direction = " ASC";
+ buffer_add( order_buf, ", " );
}
- }
- if( first ) {
- first = 0;
- } else {
- buffer_add( order_buf, ", " );
- }
+ buffer_add( order_buf, field_str );
+ free( field_str );
- buffer_add( order_buf, string );
- free( string );
+ if( direction ) {
+ buffer_add( order_buf, direction );
+ }
+ } // end while; looping over ORDER BY expressions
- if( direction ) {
- buffer_add( order_buf, direction );
+ jsonIteratorFree( order_itr );
+
+ } else if( JSON_STRING == snode->type ) {
+ // We expect a comma-separated list of sort fields.
+ const char* str = jsonObjectGetString( snode );
+ if( strchr( str, ';' )) {
+ // No semicolons allowed. It is theoretically possible for a
+ // legitimate semicolon to occur within quotes, but it's not likely
+ // to occur in practice in the context of an ORDER BY list.
+ osrfLogError( OSRF_LOG_MARK, "%s: Possible attempt at SOL injection -- "
+ "semicolon found in ORDER BY list: \"%s\"", modulename, str );
+ if( ctx ) {
+ osrfAppSessionStatus(
+ ctx->session,
+ OSRF_STATUS_INTERNALSERVERERROR,
+ "osrfMethodException",
+ ctx->request,
+ "Possible attempt at SOL injection -- "
+ "semicolon found in ORDER BY list"
+ );
+ }
+ jsonIteratorFree( class_itr );
+ buffer_free( order_buf );
+ buffer_free( sql_buf );
+ if( defaultselhash )
+ jsonObjectFree( defaultselhash );
+ clear_query_stack();
+ return NULL;
}
+ buffer_add( order_buf, str );
+ break;
}
- jsonIteratorFree( order_itr );
+ } // end while; looping over order_by classes
- } else {
- const char* str = jsonObjectGetString( snode );
- buffer_add( order_buf, str );
- break;
- }
+ jsonIteratorFree( class_itr );
+ order_by_list = buffer_release( order_buf );
+ } else {
+ osrfLogWarning( OSRF_LOG_MARK,
+ "\"order_by\" object in a query is not a JSON_HASH or JSON_ARRAY;"
+ "no ORDER BY generated" );
}
- jsonIteratorFree( class_itr );
-
- string = buffer_release( order_buf );
-
- if( *string ) {
+ if( order_by_list && *order_by_list ) {
OSRF_BUFFER_ADD( sql_buf, " ORDER BY " );
- OSRF_BUFFER_ADD( sql_buf, string );
+ OSRF_BUFFER_ADD( sql_buf, order_by_list );
}
- free( string );
+ free( order_by_list );
}
- if( (_tmp = jsonObjectGetKeyConst( order_hash, "limit" )) ) {
- const char* str = jsonObjectGetString( _tmp );
+ const jsonObject* limit = jsonObjectGetKeyConst( rest_of_query, "limit" );
+ if( limit ) {
+ const char* str = jsonObjectGetString( limit );
buffer_fadd(
sql_buf,
" LIMIT %d",
@@ -5166,9 +5255,9 @@
);
}
- _tmp = jsonObjectGetKeyConst( order_hash, "offset" );
- if( _tmp ) {
- const char* str = jsonObjectGetString( _tmp );
+ const jsonObject* offset = jsonObjectGetKeyConst( rest_of_query, "offset" );
+ if( offset ) {
+ const char* str = jsonObjectGetString( offset );
buffer_fadd(
sql_buf,
" OFFSET %d",
More information about the open-ils-commits
mailing list