1 #include "opensrf/osrf_application.h"
2 #include "opensrf/osrf_settings.h"
3 #include "opensrf/osrf_message.h"
4 #include "opensrf/utils.h"
5 #include "opensrf/osrf_json.h"
6 #include "opensrf/log.h"
7 #include "openils/oils_utils.h"
16 # define MODULENAME "open-ils.reporter-store"
19 # define MODULENAME "open-ils.pcrud"
21 # define MODULENAME "open-ils.cstore"
26 #define DISABLE_I18N 2
27 #define SELECT_DISTINCT 1
31 int osrfAppChildInit();
32 int osrfAppInitialize();
33 void osrfAppChildExit();
35 static int verifyObjectClass ( osrfMethodContext*, const jsonObject* );
37 int beginTransaction ( osrfMethodContext* );
38 int commitTransaction ( osrfMethodContext* );
39 int rollbackTransaction ( osrfMethodContext* );
41 int setSavepoint ( osrfMethodContext* );
42 int releaseSavepoint ( osrfMethodContext* );
43 int rollbackSavepoint ( osrfMethodContext* );
45 int doJSONSearch ( osrfMethodContext* );
47 int dispatchCRUDMethod ( osrfMethodContext* );
48 static jsonObject* doCreate ( osrfMethodContext*, int* );
49 static jsonObject* doRetrieve ( osrfMethodContext*, int* );
50 static jsonObject* doUpdate ( osrfMethodContext*, int* );
51 static jsonObject* doDelete ( osrfMethodContext*, int* );
52 static jsonObject* doFieldmapperSearch ( osrfMethodContext*, osrfHash*,
53 const jsonObject*, int* );
54 static jsonObject* oilsMakeFieldmapperFromResult( dbi_result, osrfHash* );
55 static jsonObject* oilsMakeJSONFromResult( dbi_result );
57 static char* searchWriteSimplePredicate ( const char*, osrfHash*,
58 const char*, const char*, const char* );
59 static char* searchSimplePredicate ( const char*, const char*, osrfHash*, const jsonObject* );
60 static char* searchFunctionPredicate ( const char*, osrfHash*, const jsonObject*, const char* );
61 static char* searchFieldTransform ( const char*, osrfHash*, const jsonObject*);
62 static char* searchFieldTransformPredicate ( const char*, osrfHash*, jsonObject*, const char* );
63 static char* searchBETWEENPredicate ( const char*, osrfHash*, jsonObject* );
64 static char* searchINPredicate ( const char*, osrfHash*, const jsonObject*, const char* );
65 static char* searchPredicate ( const char*, osrfHash*, jsonObject* );
66 static char* searchJOIN ( const jsonObject*, osrfHash* );
67 static char* searchWHERE ( const jsonObject*, osrfHash*, int, osrfMethodContext* );
68 static char* buildSELECT ( jsonObject*, jsonObject*, osrfHash*, osrfMethodContext* );
70 static char* SELECT ( osrfMethodContext*, jsonObject*, jsonObject*, jsonObject*, jsonObject*, jsonObject*, jsonObject*, jsonObject*, int );
72 void userDataFree( void* );
73 static void sessionDataFree( char*, void* );
74 static char* getSourceDefinition( osrfHash* );
77 static jsonObject* verifyUserPCRUD( osrfMethodContext* );
78 static int verifyObjectPCRUD( osrfMethodContext*, const jsonObject* );
81 static dbi_conn writehandle; /* our MASTER db connection */
82 static dbi_conn dbhandle; /* our CURRENT db connection */
83 //static osrfHash * readHandles;
84 static jsonObject* jsonNULL = NULL; //
85 static int max_flesh_depth = 100;
87 /* called when this process is about to exit */
88 void osrfAppChildExit() {
89 osrfLogDebug(OSRF_LOG_MARK, "Child is exiting, disconnecting from database...");
92 if (writehandle == dbhandle) same = 1;
94 dbi_conn_query(writehandle, "ROLLBACK;");
95 dbi_conn_close(writehandle);
98 if (dbhandle && !same)
99 dbi_conn_close(dbhandle);
101 // XXX add cleanup of readHandles whenever that gets used
106 int osrfAppInitialize() {
108 osrfLogInfo(OSRF_LOG_MARK, "Initializing the CStore Server...");
109 osrfLogInfo(OSRF_LOG_MARK, "Finding XML file...");
111 if (!oilsIDLInit( osrf_settings_host_value("/IDL") )) return 1; /* return non-zero to indicate error */
113 growing_buffer* method_name = buffer_init(64);
115 // Generic search thingy
116 buffer_add(method_name, MODULENAME);
117 buffer_add(method_name, ".json_query");
118 osrfAppRegisterMethod( MODULENAME, OSRF_BUFFER_C_STR(method_name),
119 "doJSONSearch", "", 1, OSRF_METHOD_STREAMING );
122 // first we register all the transaction and savepoint methods
123 buffer_reset(method_name);
124 OSRF_BUFFER_ADD(method_name, MODULENAME);
125 OSRF_BUFFER_ADD(method_name, ".transaction.begin");
126 osrfAppRegisterMethod( MODULENAME, OSRF_BUFFER_C_STR(method_name),
127 "beginTransaction", "", 0, 0 );
129 buffer_reset(method_name);
130 OSRF_BUFFER_ADD(method_name, MODULENAME);
131 OSRF_BUFFER_ADD(method_name, ".transaction.commit");
132 osrfAppRegisterMethod( MODULENAME, OSRF_BUFFER_C_STR(method_name),
133 "commitTransaction", "", 0, 0 );
135 buffer_reset(method_name);
136 OSRF_BUFFER_ADD(method_name, MODULENAME);
137 OSRF_BUFFER_ADD(method_name, ".transaction.rollback");
138 osrfAppRegisterMethod( MODULENAME, OSRF_BUFFER_C_STR(method_name),
139 "rollbackTransaction", "", 0, 0 );
141 buffer_reset(method_name);
142 OSRF_BUFFER_ADD(method_name, MODULENAME);
143 OSRF_BUFFER_ADD(method_name, ".savepoint.set");
144 osrfAppRegisterMethod( MODULENAME, OSRF_BUFFER_C_STR(method_name),
145 "setSavepoint", "", 1, 0 );
147 buffer_reset(method_name);
148 OSRF_BUFFER_ADD(method_name, MODULENAME);
149 OSRF_BUFFER_ADD(method_name, ".savepoint.release");
150 osrfAppRegisterMethod( MODULENAME, OSRF_BUFFER_C_STR(method_name),
151 "releaseSavepoint", "", 1, 0 );
153 buffer_reset(method_name);
154 OSRF_BUFFER_ADD(method_name, MODULENAME);
155 OSRF_BUFFER_ADD(method_name, ".savepoint.rollback");
156 osrfAppRegisterMethod( MODULENAME, OSRF_BUFFER_C_STR(method_name),
157 "rollbackSavepoint", "", 1, 0 );
159 buffer_free(method_name);
161 osrfStringArray* global_methods = osrfNewStringArray(6);
163 osrfStringArrayAdd( global_methods, "create" );
164 osrfStringArrayAdd( global_methods, "retrieve" );
165 osrfStringArrayAdd( global_methods, "update" );
166 osrfStringArrayAdd( global_methods, "delete" );
167 osrfStringArrayAdd( global_methods, "search" );
168 osrfStringArrayAdd( global_methods, "id_list" );
172 osrfStringArray* classes = osrfHashKeys( oilsIDL() );
173 osrfLogDebug(OSRF_LOG_MARK, "%d classes loaded", classes->size );
174 osrfLogDebug(OSRF_LOG_MARK, "At least %d methods will be generated", classes->size * global_methods->size);
176 while ( (classname = osrfStringArrayGetString(classes, c_index++)) ) {
177 osrfLogInfo(OSRF_LOG_MARK, "Generating class methods for %s", classname);
179 osrfHash* idlClass = osrfHashGet(oilsIDL(), classname);
181 if (!osrfStringArrayContains( osrfHashGet(idlClass, "controller"), MODULENAME )) {
182 osrfLogInfo(OSRF_LOG_MARK, "%s is not listed as a controller for %s, moving on", MODULENAME, classname);
186 char* virt = osrfHashGet(idlClass, "virtual");
187 if (virt && !strcmp( virt, "true")) {
188 osrfLogDebug(OSRF_LOG_MARK, "Class %s is virtual, skipping", classname );
194 osrfHash* method_meta;
195 while ( (method_type = osrfStringArrayGetString(global_methods, i++)) ) {
196 osrfLogDebug(OSRF_LOG_MARK, "Using files to build %s class methods for %s", method_type, classname);
198 if (!osrfHashGet(idlClass, "fieldmapper")) continue;
201 if (!osrfHashGet(idlClass, "permacrud")) continue;
203 char* tmp_method = strdup(method_type);
204 if ( *tmp_method == 'i' || *tmp_method == 's') {
206 tmp_method = strdup("retrieve");
208 if (!osrfHashGet( osrfHashGet(idlClass, "permacrud"), tmp_method )) continue;
212 char* readonly = osrfHashGet(idlClass, "readonly");
214 !strncasecmp( "true", readonly, 4) &&
215 ( *method_type == 'c' || *method_type == 'u' || *method_type == 'd')
218 method_meta = osrfNewHash();
219 osrfHashSet(method_meta, idlClass, "class");
221 method_name = buffer_init(64);
223 buffer_fadd(method_name, "%s.%s.%s", MODULENAME, method_type, classname);
227 char* _fm = strdup( (char*)osrfHashGet(idlClass, "fieldmapper") );
228 part = strtok_r(_fm, ":", &st_tmp);
230 buffer_fadd(method_name, "%s.direct.%s", MODULENAME, part);
232 while ((part = strtok_r(NULL, ":", &st_tmp))) {
233 OSRF_BUFFER_ADD_CHAR(method_name, '.');
234 OSRF_BUFFER_ADD(method_name, part);
236 OSRF_BUFFER_ADD_CHAR(method_name, '.');
237 OSRF_BUFFER_ADD(method_name, method_type);
241 char* method = buffer_release(method_name);
243 osrfHashSet( method_meta, method, "methodname" );
244 osrfHashSet( method_meta, strdup(method_type), "methodtype" );
247 if (*method_type == 'i' || *method_type == 's') {
248 flags = flags | OSRF_METHOD_STREAMING;
251 osrfAppRegisterExtendedMethod(
254 "dispatchCRUDMethod",
265 osrfStringArrayFree( global_methods );
269 static char* getSourceDefinition( osrfHash* class ) {
271 char* tabledef = osrfHashGet(class, "tablename");
274 growing_buffer* tablebuf = buffer_init(128);
275 tabledef = osrfHashGet(class, "source_definition");
278 buffer_fadd( tablebuf, "(%s)", tabledef );
279 tabledef = buffer_release(tablebuf);
281 tabledef = strdup(tabledef);
288 * Connects to the database
290 int osrfAppChildInit() {
292 osrfLogDebug(OSRF_LOG_MARK, "Attempting to initialize libdbi...");
293 dbi_initialize(NULL);
294 osrfLogDebug(OSRF_LOG_MARK, "... libdbi initialized.");
296 char* driver = osrf_settings_host_value("/apps/%s/app_settings/driver", MODULENAME);
297 char* user = osrf_settings_host_value("/apps/%s/app_settings/database/user", MODULENAME);
298 char* host = osrf_settings_host_value("/apps/%s/app_settings/database/host", MODULENAME);
299 char* port = osrf_settings_host_value("/apps/%s/app_settings/database/port", MODULENAME);
300 char* db = osrf_settings_host_value("/apps/%s/app_settings/database/db", MODULENAME);
301 char* pw = osrf_settings_host_value("/apps/%s/app_settings/database/pw", MODULENAME);
302 char* md = osrf_settings_host_value("/apps/%s/app_settings/max_query_recursion", MODULENAME);
304 osrfLogDebug(OSRF_LOG_MARK, "Attempting to load the database driver [%s]...", driver);
305 writehandle = dbi_conn_new(driver);
308 osrfLogError(OSRF_LOG_MARK, "Error loading database driver [%s]", driver);
311 osrfLogDebug(OSRF_LOG_MARK, "Database driver [%s] seems OK", driver);
313 osrfLogInfo(OSRF_LOG_MARK, "%s connecting to database. host=%s, "
314 "port=%s, user=%s, pw=%s, db=%s", MODULENAME, host, port, user, pw, db );
316 if(host) dbi_conn_set_option(writehandle, "host", host );
317 if(port) dbi_conn_set_option_numeric( writehandle, "port", atoi(port) );
318 if(user) dbi_conn_set_option(writehandle, "username", user);
319 if(pw) dbi_conn_set_option(writehandle, "password", pw );
320 if(db) dbi_conn_set_option(writehandle, "dbname", db );
322 if(md) max_flesh_depth = atoi(md);
323 if(max_flesh_depth < 0) max_flesh_depth = 1;
324 if(max_flesh_depth > 1000) max_flesh_depth = 1000;
333 if (dbi_conn_connect(writehandle) < 0) {
335 if (dbi_conn_connect(writehandle) < 0) {
336 dbi_conn_error(writehandle, &err);
337 osrfLogError( OSRF_LOG_MARK, "Error connecting to database: %s", err);
342 osrfLogInfo(OSRF_LOG_MARK, "%s successfully connected to the database", MODULENAME);
348 osrfStringArray* classes = osrfHashKeys( oilsIDL() );
350 while ( (classname = osrfStringArrayGetString(classes, i++)) ) {
351 osrfHash* class = osrfHashGet( oilsIDL(), classname );
352 osrfHash* fields = osrfHashGet( class, "fields" );
354 char* virt = osrfHashGet(class, "virtual");
355 if (virt && !strcmp( virt, "true")) {
356 osrfLogDebug(OSRF_LOG_MARK, "Class %s is virtual, skipping", classname );
360 char* tabledef = getSourceDefinition(class);
362 growing_buffer* sql_buf = buffer_init(32);
363 buffer_fadd( sql_buf, "SELECT * FROM %s AS x WHERE 1=0;", tabledef );
367 char* sql = buffer_release(sql_buf);
368 osrfLogDebug(OSRF_LOG_MARK, "%s Investigatory SQL = %s", MODULENAME, sql);
370 dbi_result result = dbi_conn_query(writehandle, sql);
376 const char* columnName;
378 while( (columnName = dbi_result_get_field_name(result, columnIndex++)) ) {
380 osrfLogInternal(OSRF_LOG_MARK, "Looking for column named [%s]...", (char*)columnName);
382 /* fetch the fieldmapper index */
383 if( (_f = osrfHashGet(fields, (char*)columnName)) ) {
385 osrfLogDebug(OSRF_LOG_MARK, "Found [%s] in IDL hash...", (char*)columnName);
387 /* determine the field type and storage attributes */
388 type = dbi_result_get_field_type(result, columnName);
389 attr = dbi_result_get_field_attribs(result, columnName);
393 case DBI_TYPE_INTEGER :
395 if ( !osrfHashGet(_f, "primitive") )
396 osrfHashSet(_f,"number", "primitive");
398 if( attr & DBI_INTEGER_SIZE8 )
399 osrfHashSet(_f,"INT8", "datatype");
401 osrfHashSet(_f,"INT", "datatype");
404 case DBI_TYPE_DECIMAL :
405 if ( !osrfHashGet(_f, "primitive") )
406 osrfHashSet(_f,"number", "primitive");
408 osrfHashSet(_f,"NUMERIC", "datatype");
411 case DBI_TYPE_STRING :
412 if ( !osrfHashGet(_f, "primitive") )
413 osrfHashSet(_f,"string", "primitive");
414 osrfHashSet(_f,"TEXT", "datatype");
417 case DBI_TYPE_DATETIME :
418 if ( !osrfHashGet(_f, "primitive") )
419 osrfHashSet(_f,"string", "primitive");
421 osrfHashSet(_f,"TIMESTAMP", "datatype");
424 case DBI_TYPE_BINARY :
425 if ( !osrfHashGet(_f, "primitive") )
426 osrfHashSet(_f,"string", "primitive");
428 osrfHashSet(_f,"BYTEA", "datatype");
433 "Setting [%s] to primitive [%s] and datatype [%s]...",
435 osrfHashGet(_f, "primitive"),
436 osrfHashGet(_f, "datatype")
440 dbi_result_free(result);
442 osrfLogDebug(OSRF_LOG_MARK, "No data found for class [%s]...", (char*)classname);
446 osrfStringArrayFree(classes);
451 void userDataFree( void* blob ) {
452 osrfHashFree( (osrfHash*)blob );
456 static void sessionDataFree( char* key, void* item ) {
457 if (!(strcmp(key,"xact_id"))) {
459 dbi_conn_query(writehandle, "ROLLBACK;");
466 int beginTransaction ( osrfMethodContext* ctx ) {
467 OSRF_METHOD_VERIFY_CONTEXT(ctx);
470 jsonObject* user = verifyUserPCRUD( ctx );
471 if (!user) return -1;
472 jsonObjectFree(user);
475 dbi_result result = dbi_conn_query(writehandle, "START TRANSACTION;");
477 osrfLogError(OSRF_LOG_MARK, "%s: Error starting transaction", MODULENAME );
478 osrfAppSessionStatus( ctx->session, OSRF_STATUS_INTERNALSERVERERROR, "osrfMethodException", ctx->request, "Error starting transaction" );
481 jsonObject* ret = jsonNewObject(ctx->session->session_id);
482 osrfAppRespondComplete( ctx, ret );
485 if (!ctx->session->userData) {
486 ctx->session->userData = osrfNewHash();
487 osrfHashSetCallback((osrfHash*)ctx->session->userData, &sessionDataFree);
490 osrfHashSet( (osrfHash*)ctx->session->userData, strdup( ctx->session->session_id ), "xact_id" );
491 ctx->session->userDataFree = &userDataFree;
497 int setSavepoint ( osrfMethodContext* ctx ) {
498 OSRF_METHOD_VERIFY_CONTEXT(ctx);
503 jsonObject* user = verifyUserPCRUD( ctx );
504 if (!user) return -1;
505 jsonObjectFree(user);
508 if (!osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" )) {
509 osrfAppSessionStatus(
511 OSRF_STATUS_INTERNALSERVERERROR,
512 "osrfMethodException",
514 "No active transaction -- required for savepoints"
519 char* spName = jsonObjectToSimpleString(jsonObjectGetIndex(ctx->params, spNamePos));
521 dbi_result result = dbi_conn_queryf(writehandle, "SAVEPOINT \"%s\";", spName);
525 "%s: Error creating savepoint %s in transaction %s",
528 osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" )
530 osrfAppSessionStatus( ctx->session, OSRF_STATUS_INTERNALSERVERERROR, "osrfMethodException", ctx->request, "Error creating savepoint" );
534 jsonObject* ret = jsonNewObject(spName);
535 osrfAppRespondComplete( ctx, ret );
542 int releaseSavepoint ( osrfMethodContext* ctx ) {
543 OSRF_METHOD_VERIFY_CONTEXT(ctx);
548 jsonObject* user = verifyUserPCRUD( ctx );
549 if (!user) return -1;
550 jsonObjectFree(user);
553 if (!osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" )) {
554 osrfAppSessionStatus(
556 OSRF_STATUS_INTERNALSERVERERROR,
557 "osrfMethodException",
559 "No active transaction -- required for savepoints"
564 char* spName = jsonObjectToSimpleString(jsonObjectGetIndex(ctx->params, spNamePos));
566 dbi_result result = dbi_conn_queryf(writehandle, "RELEASE SAVEPOINT \"%s\";", spName);
570 "%s: Error releasing savepoint %s in transaction %s",
573 osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" )
575 osrfAppSessionStatus( ctx->session, OSRF_STATUS_INTERNALSERVERERROR, "osrfMethodException", ctx->request, "Error releasing savepoint" );
579 jsonObject* ret = jsonNewObject(spName);
580 osrfAppRespondComplete( ctx, ret );
587 int rollbackSavepoint ( osrfMethodContext* ctx ) {
588 OSRF_METHOD_VERIFY_CONTEXT(ctx);
593 jsonObject* user = verifyUserPCRUD( ctx );
594 if (!user) return -1;
595 jsonObjectFree(user);
598 if (!osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" )) {
599 osrfAppSessionStatus(
601 OSRF_STATUS_INTERNALSERVERERROR,
602 "osrfMethodException",
604 "No active transaction -- required for savepoints"
609 char* spName = jsonObjectToSimpleString(jsonObjectGetIndex(ctx->params, spNamePos));
611 dbi_result result = dbi_conn_queryf(writehandle, "ROLLBACK TO SAVEPOINT \"%s\";", spName);
615 "%s: Error rolling back savepoint %s in transaction %s",
618 osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" )
620 osrfAppSessionStatus( ctx->session, OSRF_STATUS_INTERNALSERVERERROR, "osrfMethodException", ctx->request, "Error rolling back savepoint" );
624 jsonObject* ret = jsonNewObject(spName);
625 osrfAppRespondComplete( ctx, ret );
632 int commitTransaction ( osrfMethodContext* ctx ) {
633 OSRF_METHOD_VERIFY_CONTEXT(ctx);
636 jsonObject* user = verifyUserPCRUD( ctx );
637 if (!user) return -1;
638 jsonObjectFree(user);
641 if (!osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" )) {
642 osrfAppSessionStatus( ctx->session, OSRF_STATUS_INTERNALSERVERERROR, "osrfMethodException", ctx->request, "No active transaction to commit" );
646 dbi_result result = dbi_conn_query(writehandle, "COMMIT;");
648 osrfLogError(OSRF_LOG_MARK, "%s: Error committing transaction", MODULENAME );
649 osrfAppSessionStatus( ctx->session, OSRF_STATUS_INTERNALSERVERERROR, "osrfMethodException", ctx->request, "Error committing transaction" );
652 osrfHashRemove(ctx->session->userData, "xact_id");
653 jsonObject* ret = jsonNewObject(ctx->session->session_id);
654 osrfAppRespondComplete( ctx, ret );
660 int rollbackTransaction ( osrfMethodContext* ctx ) {
661 OSRF_METHOD_VERIFY_CONTEXT(ctx);
664 jsonObject* user = verifyUserPCRUD( ctx );
665 if (!user) return -1;
666 jsonObjectFree(user);
669 if (!osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" )) {
670 osrfAppSessionStatus( ctx->session, OSRF_STATUS_INTERNALSERVERERROR, "osrfMethodException", ctx->request, "No active transaction to roll back" );
674 dbi_result result = dbi_conn_query(writehandle, "ROLLBACK;");
676 osrfLogError(OSRF_LOG_MARK, "%s: Error rolling back transaction", MODULENAME );
677 osrfAppSessionStatus( ctx->session, OSRF_STATUS_INTERNALSERVERERROR, "osrfMethodException", ctx->request, "Error rolling back transaction" );
680 osrfHashRemove(ctx->session->userData, "xact_id");
681 jsonObject* ret = jsonNewObject(ctx->session->session_id);
682 osrfAppRespondComplete( ctx, ret );
688 int dispatchCRUDMethod ( osrfMethodContext* ctx ) {
689 OSRF_METHOD_VERIFY_CONTEXT(ctx);
691 osrfHash* meta = (osrfHash*) ctx->method->userData;
692 osrfHash* class_obj = osrfHashGet( meta, "class" );
696 const char* methodtype = osrfHashGet(meta, "methodtype");
697 jsonObject * obj = NULL;
699 if (!strcmp(methodtype, "create")) {
700 obj = doCreate(ctx, &err);
701 osrfAppRespondComplete( ctx, obj );
703 else if (!strcmp(methodtype, "retrieve")) {
704 obj = doRetrieve(ctx, &err);
705 osrfAppRespondComplete( ctx, obj );
707 else if (!strcmp(methodtype, "update")) {
708 obj = doUpdate(ctx, &err);
709 osrfAppRespondComplete( ctx, obj );
711 else if (!strcmp(methodtype, "delete")) {
712 obj = doDelete(ctx, &err);
713 osrfAppRespondComplete( ctx, obj );
715 else if (!strcmp(methodtype, "search")) {
717 jsonObject* _p = jsonObjectClone( ctx->params );
720 _p = jsonParseString("[]");
721 jsonObjectPush(_p, jsonObjectClone(jsonObjectGetIndex(ctx->params, 1)));
722 jsonObjectPush(_p, jsonObjectClone(jsonObjectGetIndex(ctx->params, 2)));
725 obj = doFieldmapperSearch(ctx, class_obj, _p, &err);
731 jsonIterator* itr = jsonNewIterator( obj );
732 while ((cur = jsonIteratorNext( itr ))) {
734 if(!verifyObjectPCRUD(ctx, cur)) continue;
736 osrfAppRespond( ctx, cur );
738 jsonIteratorFree(itr);
739 osrfAppRespondComplete( ctx, NULL );
741 } else if (!strcmp(methodtype, "id_list")) {
743 jsonObject* _p = jsonObjectClone( ctx->params );
746 _p = jsonParseString("[]");
747 jsonObjectPush(_p, jsonObjectClone(jsonObjectGetIndex(ctx->params, 1)));
748 jsonObjectPush(_p, jsonObjectClone(jsonObjectGetIndex(ctx->params, 2)));
751 if (jsonObjectGetIndex( _p, 1 )) {
752 jsonObjectRemoveKey( jsonObjectGetIndex( _p, 1 ), "select" );
753 jsonObjectRemoveKey( jsonObjectGetIndex( _p, 1 ), "no_i18n" );
754 jsonObjectRemoveKey( jsonObjectGetIndex( _p, 1 ), "flesh" );
755 jsonObjectRemoveKey( jsonObjectGetIndex( _p, 1 ), "flesh_columns" );
757 jsonObjectSetIndex( _p, 1, jsonNewObjectType(JSON_HASH) );
760 jsonObjectSetKey( jsonObjectGetIndex( _p, 1 ), "no_i18n", jsonParseString("true") );
763 jsonObjectGetIndex( _p, 1 ),
766 "{ \"%s\":[\"%s\"] }",
767 osrfHashGet( class_obj, "classname" ),
768 osrfHashGet( class_obj, "primarykey" )
772 obj = doFieldmapperSearch(ctx, class_obj, _p, &err);
778 jsonIterator* itr = jsonNewIterator( obj );
779 while ((cur = jsonIteratorNext( itr ))) {
781 if(!verifyObjectPCRUD(ctx, cur)) continue;
785 oilsFMGetObject( cur, osrfHashGet( class_obj, "primarykey" ) )
788 jsonIteratorFree(itr);
789 osrfAppRespondComplete( ctx, NULL );
792 osrfAppRespondComplete( ctx, obj );
800 static int verifyObjectClass ( osrfMethodContext* ctx, const jsonObject* param ) {
803 osrfHash* meta = (osrfHash*) ctx->method->userData;
804 osrfHash* class = osrfHashGet( meta, "class" );
806 if (!param->classname || (strcmp( osrfHashGet(class, "classname"), param->classname ))) {
808 growing_buffer* msg = buffer_init(128);
811 "%s: %s method for type %s was passed a %s",
813 osrfHashGet(meta, "methodtype"),
814 osrfHashGet(class, "classname"),
818 char* m = buffer_release(msg);
819 osrfAppSessionStatus( ctx->session, OSRF_STATUS_BADREQUEST, "osrfMethodException", ctx->request, m );
827 ret = verifyObjectPCRUD( ctx, param );
835 static jsonObject* verifyUserPCRUD( osrfMethodContext* ctx ) {
836 char* auth = jsonObjectToSimpleString( jsonObjectGetIndex( ctx->params, 0 ) );
837 jsonObject* auth_object = jsonNewObject(auth);
838 jsonObject* user = oilsUtilsQuickReq("open-ils.auth","open-ils.auth.session.retrieve", auth_object);
839 jsonObjectFree(auth_object);
841 if (!user->classname || strcmp(user->classname, "au")) {
843 growing_buffer* msg = buffer_init(128);
846 "%s: permacrud received a bad auth token: %s",
851 char* m = buffer_release(msg);
852 osrfAppSessionStatus( ctx->session, OSRF_STATUS_UNAUTHORIZED, "osrfMethodException", ctx->request, m );
855 jsonObjectFree(user);
864 static int verifyObjectPCRUD ( osrfMethodContext* ctx, const jsonObject* obj ) {
866 dbhandle = writehandle;
868 osrfHash* meta = (osrfHash*) ctx->method->userData;
869 osrfHash* class = osrfHashGet( meta, "class" );
870 char* method_type = strdup( osrfHashGet(meta, "methodtype") );
873 if ( ( *method_type == 's' || *method_type == 'i' ) ) {
875 method_type = strdup("retrieve");
876 fetch = 0; // don't go to the db for the object for retrieve-type methods
879 osrfHash* pcrud = osrfHashGet( osrfHashGet(class, "permacrud"), method_type );
883 // No permacrud for this method type on this class
885 growing_buffer* msg = buffer_init(128);
888 "%s: %s on class %s has no permacrud IDL entry",
890 osrfHashGet(meta, "methodtype"),
891 osrfHashGet(class, "classname")
894 char* m = buffer_release(msg);
895 osrfAppSessionStatus( ctx->session, OSRF_STATUS_FORBIDDEN, "osrfMethodException", ctx->request, m );
902 jsonObject* user = verifyUserPCRUD( ctx );
905 int userid = atoi( oilsFMGetString( user, "id" ) );
906 jsonObjectFree(user);
908 osrfStringArray* permission = osrfHashGet(pcrud, "permission");
909 char* global_required = osrfHashGet(pcrud, "global_required");
910 osrfStringArray* local_context = osrfHashGet(pcrud, "local_context");
911 osrfHash* foreign_context = osrfHashGet(pcrud, "foreign_context");
913 osrfStringArray* context_org_array = osrfNewStringArray(1);
916 char* pkey_value = NULL;
917 if (global_required && !strcmp( "true", global_required )) {
918 osrfLogDebug( OSRF_LOG_MARK, "global-level permissions required, fetching top of the org tree" );
920 // check for perm at top of org tree
921 jsonObject* _tmp_params = jsonParseString("[{\"parent_ou\":null}]");
922 jsonObject* _list = doFieldmapperSearch(ctx, osrfHashGet( oilsIDL(), "aou" ), _tmp_params, &err);
924 jsonObject* _tree_top = jsonObjectGetIndex(_list, 0);
927 jsonObjectFree(_tmp_params);
928 jsonObjectFree(_list);
930 growing_buffer* msg = buffer_init(128);
931 OSRF_BUFFER_ADD( msg, MODULENAME );
932 OSRF_BUFFER_ADD( msg,
933 ": Internal error, could not find the top of the org tree (parent_ou = NULL)" );
935 char* m = buffer_release(msg);
936 osrfAppSessionStatus( ctx->session, OSRF_STATUS_INTERNALSERVERERROR, "osrfMethodException", ctx->request, m );
942 osrfStringArrayAdd( context_org_array, oilsFMGetString( _tree_top, "id" ) );
943 osrfLogDebug( OSRF_LOG_MARK, "top of the org tree is %s", osrfStringArrayGetString(context_org_array, 0) );
945 jsonObjectFree(_tmp_params);
946 jsonObjectFree(_list);
949 osrfLogDebug( OSRF_LOG_MARK, "global-level permissions not required, fetching context org ids" );
950 char* pkey = osrfHashGet(class, "primarykey");
951 jsonObject *param = NULL;
953 if (obj->classname) {
954 pkey_value = oilsFMGetString( obj, pkey );
955 if (!fetch) param = jsonObjectClone(obj);
956 osrfLogDebug( OSRF_LOG_MARK, "Object supplied, using primary key value of %s", pkey_value );
958 pkey_value = jsonObjectToSimpleString( obj );
960 osrfLogDebug( OSRF_LOG_MARK, "Object not supplied, using primary key value of %s and retrieving from the database", pkey_value );
964 jsonObject* _tmp_params = jsonParseStringFmt("[{\"%s\":\"%s\"}]", pkey, pkey_value);
965 jsonObject* _list = doFieldmapperSearch(
972 param = jsonObjectClone(jsonObjectGetIndex(_list, 0));
974 jsonObjectFree(_tmp_params);
975 jsonObjectFree(_list);
979 osrfLogDebug( OSRF_LOG_MARK, "Object not found in the database with primary key %s of %s", pkey, pkey_value );
981 growing_buffer* msg = buffer_init(128);
984 "%s: no object found with primary key %s of %s",
990 char* m = buffer_release(msg);
991 osrfAppSessionStatus(
993 OSRF_STATUS_INTERNALSERVERERROR,
994 "osrfMethodException",
1000 if (pkey_value) free(pkey_value);
1005 if (local_context->size > 0) {
1006 osrfLogDebug( OSRF_LOG_MARK, "%d class-local context field(s) specified", local_context->size);
1008 char* lcontext = NULL;
1009 while ( (lcontext = osrfStringArrayGetString(local_context, i++)) ) {
1010 osrfStringArrayAdd( context_org_array, oilsFMGetString( param, lcontext ) );
1013 "adding class-local field %s (value: %s) to the context org list",
1015 osrfStringArrayGetString(context_org_array, context_org_array->size - 1)
1020 osrfStringArray* class_list;
1022 if (foreign_context) {
1023 class_list = osrfHashKeys( foreign_context );
1024 osrfLogDebug( OSRF_LOG_MARK, "%d foreign context classes(s) specified", class_list->size);
1026 if (class_list->size > 0) {
1029 char* class_name = NULL;
1030 while ( (class_name = osrfStringArrayGetString(class_list, i++)) ) {
1031 osrfHash* fcontext = osrfHashGet(foreign_context, class_name);
1035 "%d foreign context fields(s) specified for class %s",
1036 ((osrfStringArray*)osrfHashGet(fcontext,"context"))->size,
1040 char* foreign_pkey = osrfHashGet(fcontext, "field");
1041 char* foreign_pkey_value = oilsFMGetString(param, osrfHashGet(fcontext, "fkey"));
1043 jsonObject* _tmp_params = jsonParseStringFmt(
1044 "[{\"%s\":\"%s\"}]",
1049 jsonObject* _list = doFieldmapperSearch(
1051 osrfHashGet( oilsIDL(), class_name ),
1056 jsonObject* _fparam = jsonObjectGetIndex(_list, 0);
1059 jsonObjectFree(_tmp_params);
1060 jsonObjectFree(_list);
1062 growing_buffer* msg = buffer_init(128);
1065 "%s: no object found with primary key %s of %s",
1071 char* m = buffer_release(msg);
1072 osrfAppSessionStatus(
1074 OSRF_STATUS_INTERNALSERVERERROR,
1075 "osrfMethodException",
1081 osrfStringArrayFree(class_list);
1082 free(foreign_pkey_value);
1083 jsonObjectFree(param);
1088 jsonObjectFree(_tmp_params);
1089 free(foreign_pkey_value);
1092 char* foreign_field = NULL;
1093 while ( (foreign_field = osrfStringArrayGetString(osrfHashGet(fcontext,"context"), j++)) ) {
1094 osrfStringArrayAdd( context_org_array, oilsFMGetString( _fparam, foreign_field ) );
1097 "adding foreign class %s field %s (value: %s) to the context org list",
1100 osrfStringArrayGetString(context_org_array, context_org_array->size - 1)
1104 jsonObjectFree(_list);
1107 osrfStringArrayFree(class_list);
1111 jsonObjectFree(param);
1114 char* context_org = NULL;
1118 if (permission->size == 0) {
1119 osrfLogDebug( OSRF_LOG_MARK, "No permission specified for this action, passing through" );
1124 while ( (perm = osrfStringArrayGetString(permission, i++)) ) {
1126 while ( (context_org = osrfStringArrayGetString(context_org_array, j++)) ) {
1132 "Checking object permission [%s] for user %d on object %s (class %s) at org %d",
1136 osrfHashGet(class, "classname"),
1140 result = dbi_conn_queryf(
1142 "SELECT permission.usr_has_object_perm(%d, '%s', '%s', '%s', %d) AS has_perm;",
1145 osrfHashGet(class, "classname"),
1153 "Recieved a result for object permission [%s] for user %d on object %s (class %s) at org %d",
1157 osrfHashGet(class, "classname"),
1161 if (dbi_result_first_row(result)) {
1162 jsonObject* return_val = oilsMakeJSONFromResult( result );
1163 char* has_perm = jsonObjectToSimpleString( jsonObjectGetKeyConst(return_val, "has_perm") );
1167 "Status of object permission [%s] for user %d on object %s (class %s) at org %d is %s",
1171 osrfHashGet(class, "classname"),
1176 if ( *has_perm == 't' ) OK = 1;
1178 jsonObjectFree(return_val);
1181 dbi_result_free(result);
1186 osrfLogDebug( OSRF_LOG_MARK, "Checking non-object permission [%s] for user %d at org %d", perm, userid, atoi(context_org) );
1187 result = dbi_conn_queryf(
1189 "SELECT permission.usr_has_perm(%d, '%s', %d) AS has_perm;",
1196 osrfLogDebug( OSRF_LOG_MARK, "Recieved a result for permission [%s] for user %d at org %d", perm, userid, atoi(context_org) );
1197 if (dbi_result_first_row(result)) {
1198 jsonObject* return_val = oilsMakeJSONFromResult( result );
1199 char* has_perm = jsonObjectToSimpleString( jsonObjectGetKeyConst(return_val, "has_perm") );
1200 osrfLogDebug( OSRF_LOG_MARK, "Status of permission [%s] for user %d at org %d is [%s]", perm, userid, atoi(context_org), has_perm );
1201 if ( *has_perm == 't' ) OK = 1;
1203 jsonObjectFree(return_val);
1206 dbi_result_free(result);
1214 if (pkey_value) free(pkey_value);
1215 osrfStringArrayFree(context_org_array);
1222 static jsonObject* doCreate(osrfMethodContext* ctx, int* err ) {
1224 osrfHash* meta = osrfHashGet( (osrfHash*) ctx->method->userData, "class" );
1226 jsonObject* target = jsonObjectGetIndex( ctx->params, 1 );
1227 jsonObject* options = jsonObjectGetIndex( ctx->params, 2 );
1229 jsonObject* target = jsonObjectGetIndex( ctx->params, 0 );
1230 jsonObject* options = jsonObjectGetIndex( ctx->params, 1 );
1233 if (!verifyObjectClass(ctx, target)) {
1238 osrfLogDebug( OSRF_LOG_MARK, "Object seems to be of the correct type" );
1240 if (!ctx->session || !ctx->session->userData || !osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" )) {
1241 osrfLogError( OSRF_LOG_MARK, "No active transaction -- required for CREATE" );
1243 osrfAppSessionStatus(
1245 OSRF_STATUS_BADREQUEST,
1246 "osrfMethodException",
1248 "No active transaction -- required for CREATE"
1254 if (osrfHashGet( meta, "readonly" ) && strncasecmp("true", osrfHashGet( meta, "readonly" ), 4)) {
1255 osrfAppSessionStatus(
1257 OSRF_STATUS_BADREQUEST,
1258 "osrfMethodException",
1260 "Cannot INSERT readonly class"
1267 char* trans_id = osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" );
1269 // Set the last_xact_id
1270 int index = oilsIDL_ntop( target->classname, "last_xact_id" );
1272 osrfLogDebug(OSRF_LOG_MARK, "Setting last_xact_id to %s on %s at position %d", trans_id, target->classname, index);
1273 jsonObjectSetIndex(target, index, jsonNewObject(trans_id));
1276 osrfLogDebug( OSRF_LOG_MARK, "There is a transaction running..." );
1278 dbhandle = writehandle;
1280 osrfHash* fields = osrfHashGet(meta, "fields");
1281 char* pkey = osrfHashGet(meta, "primarykey");
1282 char* seq = osrfHashGet(meta, "sequence");
1284 growing_buffer* table_buf = buffer_init(128);
1285 growing_buffer* col_buf = buffer_init(128);
1286 growing_buffer* val_buf = buffer_init(128);
1288 OSRF_BUFFER_ADD(table_buf, "INSERT INTO ");
1289 OSRF_BUFFER_ADD(table_buf, osrfHashGet(meta, "tablename"));
1290 OSRF_BUFFER_ADD_CHAR( col_buf, '(' );
1291 buffer_add(val_buf,"VALUES (");
1297 osrfStringArray* field_list = osrfHashKeys( fields );
1298 while ( (field_name = osrfStringArrayGetString(field_list, i++)) ) {
1300 osrfHash* field = osrfHashGet( fields, field_name );
1302 if(!( strcmp( osrfHashGet(osrfHashGet(fields,field_name), "virtual"), "true" ) )) continue;
1304 const jsonObject* field_object = oilsFMGetObject( target, field_name );
1307 if (field_object && field_object->classname) {
1308 value = oilsFMGetString(
1310 (char*)oilsIDLFindPath("/%s/primarykey", field_object->classname)
1313 value = jsonObjectToSimpleString( field_object );
1320 OSRF_BUFFER_ADD_CHAR( col_buf, ',' );
1321 OSRF_BUFFER_ADD_CHAR( val_buf, ',' );
1324 buffer_add(col_buf, field_name);
1326 if (!field_object || field_object->type == JSON_NULL) {
1327 buffer_add( val_buf, "DEFAULT" );
1329 } else if ( !strcmp(osrfHashGet(field, "primitive"), "number") ) {
1330 if ( !strcmp(osrfHashGet(field, "datatype"), "INT8") ) {
1331 buffer_fadd( val_buf, "%lld", atoll(value) );
1333 } else if ( !strcmp(osrfHashGet(field, "datatype"), "INT") ) {
1334 buffer_fadd( val_buf, "%d", atoi(value) );
1336 } else if ( !strcmp(osrfHashGet(field, "datatype"), "NUMERIC") ) {
1337 buffer_fadd( val_buf, "%f", atof(value) );
1340 if ( dbi_conn_quote_string(writehandle, &value) ) {
1341 OSRF_BUFFER_ADD( val_buf, value );
1344 osrfLogError(OSRF_LOG_MARK, "%s: Error quoting string [%s]", MODULENAME, value);
1345 osrfAppSessionStatus(
1347 OSRF_STATUS_INTERNALSERVERERROR,
1348 "osrfMethodException",
1350 "Error quoting string -- please see the error log for more details"
1353 buffer_free(table_buf);
1354 buffer_free(col_buf);
1355 buffer_free(val_buf);
1366 OSRF_BUFFER_ADD_CHAR( col_buf, ')' );
1367 OSRF_BUFFER_ADD_CHAR( val_buf, ')' );
1369 char* table_str = buffer_release(table_buf);
1370 char* col_str = buffer_release(col_buf);
1371 char* val_str = buffer_release(val_buf);
1372 growing_buffer* sql = buffer_init(128);
1373 buffer_fadd( sql, "%s %s %s;", table_str, col_str, val_str );
1378 char* query = buffer_release(sql);
1380 osrfLogDebug(OSRF_LOG_MARK, "%s: Insert SQL [%s]", MODULENAME, query);
1383 dbi_result result = dbi_conn_query(writehandle, query);
1385 jsonObject* obj = NULL;
1388 obj = jsonNewObject(NULL);
1391 "%s ERROR inserting %s object using query [%s]",
1393 osrfHashGet(meta, "fieldmapper"),
1396 osrfAppSessionStatus(
1398 OSRF_STATUS_INTERNALSERVERERROR,
1399 "osrfMethodException",
1401 "INSERT error -- please see the error log for more details"
1406 char* id = oilsFMGetString(target, pkey);
1408 unsigned long long new_id = dbi_conn_sequence_last(writehandle, seq);
1409 growing_buffer* _id = buffer_init(10);
1410 buffer_fadd(_id, "%lld", new_id);
1411 id = buffer_release(_id);
1414 // Find quietness specification, if present
1415 char* quiet_str = NULL;
1417 const jsonObject* quiet_obj = jsonObjectGetKeyConst( options, "quiet" );
1419 quiet_str = jsonObjectToSimpleString( quiet_obj );
1422 if( quiet_str && !strcmp( quiet_str, "true" )) { // if quietness is specified
1423 obj = jsonNewObject(id);
1427 jsonObject* fake_params = jsonNewObjectType(JSON_ARRAY);
1428 jsonObjectPush(fake_params, jsonNewObjectType(JSON_HASH));
1431 jsonObjectGetIndex(fake_params, 0),
1436 jsonObject* list = doFieldmapperSearch( ctx,meta, fake_params, err);
1439 jsonObjectFree( fake_params );
1442 obj = jsonObjectClone( jsonObjectGetIndex(list, 0) );
1445 jsonObjectFree( list );
1446 jsonObjectFree( fake_params );
1449 if(quiet_str) free(quiet_str);
1460 static jsonObject* doRetrieve(osrfMethodContext* ctx, int* err ) {
1470 osrfHash* meta = osrfHashGet( (osrfHash*) ctx->method->userData, "class" );
1474 char* id = jsonObjectToSimpleString(jsonObjectGetIndex(ctx->params, id_pos));
1475 jsonObject* order_hash = jsonObjectGetIndex(ctx->params, order_pos);
1479 "%s retrieving %s object with primary key value of %s",
1481 osrfHashGet(meta, "fieldmapper"),
1486 jsonObject* fake_params = jsonNewObjectType(JSON_ARRAY);
1487 jsonObjectPush(fake_params, jsonNewObjectType(JSON_HASH));
1490 jsonObjectGetIndex(fake_params, 0),
1491 osrfHashGet(meta, "primarykey"),
1492 jsonObjectClone(jsonObjectGetIndex(ctx->params, id_pos))
1496 if (order_hash) jsonObjectPush(fake_params, jsonObjectClone(order_hash) );
1498 jsonObject* list = doFieldmapperSearch( ctx,meta, fake_params, err);
1501 jsonObjectFree( fake_params );
1505 obj = jsonObjectClone( jsonObjectGetIndex(list, 0) );
1507 jsonObjectFree( list );
1508 jsonObjectFree( fake_params );
1511 if(!verifyObjectPCRUD(ctx, obj)) {
1512 jsonObjectFree(obj);
1515 growing_buffer* msg = buffer_init(128);
1516 OSRF_BUFFER_ADD( msg, MODULENAME );
1517 OSRF_BUFFER_ADD( msg, ": Insufficient permissions to retrieve object" );
1519 char* m = buffer_release(msg);
1520 osrfAppSessionStatus( ctx->session, OSRF_STATUS_NOTALLOWED, "osrfMethodException", ctx->request, m );
1531 static char* jsonNumberToDBString ( osrfHash* field, const jsonObject* value ) {
1532 growing_buffer* val_buf = buffer_init(32);
1534 if ( !strncmp(osrfHashGet(field, "datatype"), "INT", (size_t)3) ) {
1535 if (value->type == JSON_NUMBER) buffer_fadd( val_buf, "%ld", (long)jsonObjectGetNumber(value) );
1537 char* val_str = jsonObjectToSimpleString(value);
1538 buffer_fadd( val_buf, "%ld", atol(val_str) );
1542 } else if ( !strcmp(osrfHashGet(field, "datatype"), "NUMERIC") ) {
1543 if (value->type == JSON_NUMBER) buffer_fadd( val_buf, "%f", jsonObjectGetNumber(value) );
1545 char* val_str = jsonObjectToSimpleString(value);
1546 buffer_fadd( val_buf, "%f", atof(val_str) );
1551 return buffer_release(val_buf);
1554 static char* searchINPredicate (const char* class, osrfHash* field,
1555 const jsonObject* node, const char* op) {
1556 growing_buffer* sql_buf = buffer_init(32);
1562 osrfHashGet(field, "name")
1566 buffer_add(sql_buf, "IN (");
1567 } else if (!(strcasecmp(op,"not in"))) {
1568 buffer_add(sql_buf, "NOT IN (");
1570 buffer_add(sql_buf, "IN (");
1573 int in_item_index = 0;
1574 int in_item_first = 1;
1575 jsonObject* in_item;
1576 while ( (in_item = jsonObjectGetIndex(node, in_item_index++)) ) {
1581 buffer_add(sql_buf, ", ");
1583 if ( !strcmp(osrfHashGet(field, "primitive"), "number") ) {
1584 char* val = jsonNumberToDBString( field, in_item );
1585 OSRF_BUFFER_ADD( sql_buf, val );
1589 char* key_string = jsonObjectToSimpleString(in_item);
1590 if ( dbi_conn_quote_string(dbhandle, &key_string) ) {
1591 OSRF_BUFFER_ADD( sql_buf, key_string );
1594 osrfLogError(OSRF_LOG_MARK, "%s: Error quoting key string [%s]", MODULENAME, key_string);
1596 buffer_free(sql_buf);
1602 OSRF_BUFFER_ADD_CHAR( sql_buf, ')' );
1604 return buffer_release(sql_buf);
1607 static char* searchValueTransform( const jsonObject* array ) {
1608 growing_buffer* sql_buf = buffer_init(32);
1611 int func_item_index = 0;
1612 int func_item_first = 2;
1613 jsonObject* func_item;
1614 while ( (func_item = jsonObjectGetIndex(array, func_item_index++)) ) {
1616 val = jsonObjectToSimpleString(func_item);
1618 if (func_item_first == 2) {
1619 OSRF_BUFFER_ADD(sql_buf, val);
1620 OSRF_BUFFER_ADD(sql_buf, "( ");
1626 if (func_item_first)
1629 buffer_add(sql_buf, ", ");
1631 if (func_item->type == JSON_NULL) {
1632 buffer_add( sql_buf, "NULL" );
1633 } else if ( dbi_conn_quote_string(dbhandle, &val) ) {
1634 OSRF_BUFFER_ADD( sql_buf, val );
1636 osrfLogError(OSRF_LOG_MARK, "%s: Error quoting key string [%s]", MODULENAME, val);
1638 buffer_free(sql_buf);
1645 buffer_add( sql_buf, " )" );
1647 return buffer_release(sql_buf);
1650 static char* searchFunctionPredicate (const char* class, osrfHash* field,
1651 const jsonObject* node, const char* node_key) {
1652 growing_buffer* sql_buf = buffer_init(32);
1654 char* val = searchValueTransform(node);
1660 osrfHashGet(field, "name"),
1667 return buffer_release(sql_buf);
1670 static char* searchFieldTransform (const char* class, osrfHash* field, const jsonObject* node) {
1671 growing_buffer* sql_buf = buffer_init(32);
1673 char* field_transform = jsonObjectToSimpleString( jsonObjectGetKeyConst( node, "transform" ) );
1674 char* transform_subcolumn = jsonObjectToSimpleString( jsonObjectGetKeyConst( node, "result_field" ) );
1676 if (field_transform) {
1677 buffer_fadd( sql_buf, "%s(\"%s\".%s", field_transform, class, osrfHashGet(field, "name"));
1678 const jsonObject* array = jsonObjectGetKeyConst( node, "params" );
1681 int func_item_index = 0;
1682 jsonObject* func_item;
1683 while ( (func_item = jsonObjectGetIndex(array, func_item_index++)) ) {
1685 char* val = jsonObjectToSimpleString(func_item);
1688 buffer_add( sql_buf, ",NULL" );
1689 } else if ( dbi_conn_quote_string(dbhandle, &val) ) {
1690 OSRF_BUFFER_ADD_CHAR( sql_buf, ',' );
1691 OSRF_BUFFER_ADD( sql_buf, val );
1693 osrfLogError(OSRF_LOG_MARK, "%s: Error quoting key string [%s]", MODULENAME, val);
1694 free(field_transform);
1696 buffer_free(sql_buf);
1710 buffer_fadd( sql_buf, "\"%s\".%s", class, osrfHashGet(field, "name"));
1713 if (transform_subcolumn) {
1714 char * tmp = buffer_release(sql_buf);
1715 sql_buf = buffer_init(32);
1725 if (field_transform) free(field_transform);
1726 if (transform_subcolumn) free(transform_subcolumn);
1728 return buffer_release(sql_buf);
1731 static char* searchFieldTransformPredicate (const char* class, osrfHash* field, jsonObject* node, const char* node_key) {
1732 char* field_transform = searchFieldTransform( class, field, node );
1735 if (!jsonObjectGetKeyConst( node, "value" )) {
1736 value = searchWHERE( node, osrfHashGet( oilsIDL(), class ), AND_OP_JOIN, NULL );
1737 } else if (jsonObjectGetKeyConst( node, "value" )->type == JSON_ARRAY) {
1738 value = searchValueTransform(jsonObjectGetKeyConst( node, "value" ));
1739 } else if (jsonObjectGetKeyConst( node, "value" )->type == JSON_HASH) {
1740 value = searchWHERE( jsonObjectGetKeyConst( node, "value" ), osrfHashGet( oilsIDL(), class ), AND_OP_JOIN, NULL );
1741 } else if (jsonObjectGetKeyConst( node, "value" )->type != JSON_NULL) {
1742 if ( !strcmp(osrfHashGet(field, "primitive"), "number") ) {
1743 value = jsonNumberToDBString( field, jsonObjectGetKeyConst( node, "value" ) );
1745 value = jsonObjectToSimpleString(jsonObjectGetKeyConst( node, "value" ));
1746 if ( !dbi_conn_quote_string(dbhandle, &value) ) {
1747 osrfLogError(OSRF_LOG_MARK, "%s: Error quoting key string [%s]", MODULENAME, value);
1749 free(field_transform);
1755 growing_buffer* sql_buf = buffer_init(32);
1766 free(field_transform);
1768 return buffer_release(sql_buf);
1771 static char* searchSimplePredicate (const char* orig_op, const char* class,
1772 osrfHash* field, const jsonObject* node) {
1776 if (node->type != JSON_NULL) {
1777 if ( !strcmp(osrfHashGet(field, "primitive"), "number") ) {
1778 val = jsonNumberToDBString( field, node );
1780 val = jsonObjectToSimpleString(node);
1784 char* pred = searchWriteSimplePredicate( class, field, osrfHashGet(field, "name"), orig_op, val );
1791 static char* searchWriteSimplePredicate ( const char* class, osrfHash* field,
1792 const char* left, const char* orig_op, const char* right ) {
1796 if (right == NULL) {
1797 val = strdup("NULL");
1799 if (strcmp( orig_op, "=" ))
1800 op = strdup("IS NOT");
1804 } else if ( !strcmp(osrfHashGet(field, "primitive"), "number") ) {
1805 val = strdup(right);
1806 op = strdup(orig_op);
1809 val = strdup(right);
1810 if ( !dbi_conn_quote_string(dbhandle, &val) ) {
1811 osrfLogError(OSRF_LOG_MARK, "%s: Error quoting key string [%s]", MODULENAME, val);
1815 op = strdup(orig_op);
1818 growing_buffer* sql_buf = buffer_init(16);
1819 buffer_fadd( sql_buf, "\"%s\".%s %s %s", class, left, op, val );
1823 return buffer_release(sql_buf);
1826 static char* searchBETWEENPredicate (const char* class, osrfHash* field, jsonObject* node) {
1831 if ( !strcmp(osrfHashGet(field, "primitive"), "number") ) {
1832 x_string = jsonNumberToDBString(field, jsonObjectGetIndex(node,0));
1833 y_string = jsonNumberToDBString(field, jsonObjectGetIndex(node,1));
1836 x_string = jsonObjectToSimpleString(jsonObjectGetIndex(node,0));
1837 y_string = jsonObjectToSimpleString(jsonObjectGetIndex(node,1));
1838 if ( !(dbi_conn_quote_string(dbhandle, &x_string) && dbi_conn_quote_string(dbhandle, &y_string)) ) {
1839 osrfLogError(OSRF_LOG_MARK, "%s: Error quoting key strings [%s] and [%s]", MODULENAME, x_string, y_string);
1846 growing_buffer* sql_buf = buffer_init(32);
1847 buffer_fadd( sql_buf, "%s BETWEEN %s AND %s", osrfHashGet(field, "name"), x_string, y_string );
1851 return buffer_release(sql_buf);
1854 static char* searchPredicate ( const char* class, osrfHash* field, jsonObject* node ) {
1857 if (node->type == JSON_ARRAY) { // equality IN search
1858 pred = searchINPredicate( class, field, node, NULL );
1859 } else if (node->type == JSON_HASH) { // non-equality search
1860 jsonObject* pred_node;
1861 jsonIterator* pred_itr = jsonNewIterator( node );
1862 while ( (pred_node = jsonIteratorNext( pred_itr )) ) {
1863 if ( !(strcasecmp( pred_itr->key,"between" )) )
1864 pred = searchBETWEENPredicate( class, field, pred_node );
1865 else if ( !(strcasecmp( pred_itr->key,"in" )) || !(strcasecmp( pred_itr->key,"not in" )) )
1866 pred = searchINPredicate( class, field, pred_node, pred_itr->key );
1867 else if ( pred_node->type == JSON_ARRAY )
1868 pred = searchFunctionPredicate( class, field, pred_node, pred_itr->key );
1869 else if ( pred_node->type == JSON_HASH )
1870 pred = searchFieldTransformPredicate( class, field, pred_node, pred_itr->key );
1872 pred = searchSimplePredicate( pred_itr->key, class, field, pred_node );
1876 jsonIteratorFree(pred_itr);
1877 } else if (node->type == JSON_NULL) { // IS NULL search
1878 growing_buffer* _p = buffer_init(64);
1881 "\"%s\".%s IS NULL",
1883 osrfHashGet(field, "name")
1885 pred = buffer_release(_p);
1886 } else { // equality search
1887 pred = searchSimplePredicate( "=", class, field, node );
1906 field : call_number,
1922 static char* searchJOIN ( const jsonObject* join_hash, osrfHash* leftmeta ) {
1924 const jsonObject* working_hash;
1925 jsonObject* freeable_hash = NULL;
1927 if (join_hash->type == JSON_STRING) {
1928 // create a wrapper around a copy of the original
1929 char* _tmp = jsonObjectToSimpleString( join_hash );
1930 freeable_hash = jsonNewObjectType(JSON_HASH);
1931 jsonObjectSetKey(freeable_hash, _tmp, NULL);
1933 working_hash = freeable_hash;
1936 working_hash = join_hash;
1938 growing_buffer* join_buf = buffer_init(128);
1939 char* leftclass = osrfHashGet(leftmeta, "classname");
1941 jsonObject* snode = NULL;
1942 jsonIterator* search_itr = jsonNewIterator( working_hash );
1944 jsonObjectFree(freeable_hash);
1946 while ( (snode = jsonIteratorNext( search_itr )) ) {
1947 osrfHash* idlClass = osrfHashGet( oilsIDL(), search_itr->key );
1949 char* class = osrfHashGet(idlClass, "classname");
1951 char* fkey = jsonObjectToSimpleString( jsonObjectGetKeyConst( snode, "fkey" ) );
1952 char* field = jsonObjectToSimpleString( jsonObjectGetKeyConst( snode, "field" ) );
1954 if (field && !fkey) {
1955 fkey = (char*)oilsIDLFindPath("/%s/links/%s/key", class, field);
1959 "%s: JOIN failed. No link defined from %s.%s to %s",
1965 buffer_free(join_buf);
1967 jsonIteratorFree(search_itr);
1970 fkey = strdup( fkey );
1972 } else if (!field && fkey) {
1973 field = (char*)oilsIDLFindPath("/%s/links/%s/key", leftclass, fkey );
1977 "%s: JOIN failed. No link defined from %s.%s to %s",
1983 buffer_free(join_buf);
1985 jsonIteratorFree(search_itr);
1988 field = strdup( field );
1990 } else if (!field && !fkey) {
1991 osrfHash* _links = oilsIDLFindPath("/%s/links", leftclass);
1994 osrfStringArray* keys = osrfHashKeys( _links );
1995 while ( (fkey = osrfStringArrayGetString(keys, i++)) ) {
1996 fkey = strdup(osrfStringArrayGetString(keys, i++));
1997 if ( !strcmp( (char*)oilsIDLFindPath("/%s/links/%s/class", leftclass, fkey), class) ) {
1998 field = strdup( (char*)oilsIDLFindPath("/%s/links/%s/key", leftclass, fkey) );
2004 osrfStringArrayFree(keys);
2006 if (!field && !fkey) {
2007 _links = oilsIDLFindPath("/%s/links", class);
2010 keys = osrfHashKeys( _links );
2011 while ( (field = osrfStringArrayGetString(keys, i++)) ) {
2012 field = strdup(osrfStringArrayGetString(keys, i++));
2013 if ( !strcmp( (char*)oilsIDLFindPath("/%s/links/%s/class", class, field), class) ) {
2014 fkey = strdup( (char*)oilsIDLFindPath("/%s/links/%s/key", class, field) );
2020 osrfStringArrayFree(keys);
2023 if (!field && !fkey) {
2026 "%s: JOIN failed. No link defined between %s and %s",
2031 buffer_free(join_buf);
2032 jsonIteratorFree(search_itr);
2038 char* type = jsonObjectToSimpleString( jsonObjectGetKeyConst( snode, "type" ) );
2040 if ( !strcasecmp(type,"left") ) {
2041 buffer_add(join_buf, " LEFT JOIN");
2042 } else if ( !strcasecmp(type,"right") ) {
2043 buffer_add(join_buf, " RIGHT JOIN");
2044 } else if ( !strcasecmp(type,"full") ) {
2045 buffer_add(join_buf, " FULL JOIN");
2047 buffer_add(join_buf, " INNER JOIN");
2050 buffer_add(join_buf, " INNER JOIN");
2054 char* table = getSourceDefinition(idlClass);
2055 buffer_fadd(join_buf, " %s AS \"%s\" ON ( \"%s\".%s = \"%s\".%s", table, class, class, field, leftclass, fkey);
2058 const jsonObject* filter = jsonObjectGetKeyConst( snode, "filter" );
2060 char* filter_op = jsonObjectToSimpleString( jsonObjectGetKeyConst( snode, "filter_op" ) );
2062 if (!strcasecmp("or",filter_op)) {
2063 buffer_add( join_buf, " OR " );
2065 buffer_add( join_buf, " AND " );
2068 buffer_add( join_buf, " AND " );
2071 char* jpred = searchWHERE( filter, idlClass, AND_OP_JOIN, NULL );
2072 OSRF_BUFFER_ADD_CHAR( join_buf, ' ' );
2073 OSRF_BUFFER_ADD( join_buf, jpred );
2078 buffer_add(join_buf, " ) ");
2080 const jsonObject* join_filter = jsonObjectGetKeyConst( snode, "join" );
2082 char* jpred = searchJOIN( join_filter, idlClass );
2083 OSRF_BUFFER_ADD_CHAR( join_buf, ' ' );
2084 OSRF_BUFFER_ADD( join_buf, jpred );
2092 jsonIteratorFree(search_itr);
2094 return buffer_release(join_buf);
2099 { +class : { -or|-and : { field : { op : value }, ... } ... }, ... }
2100 { +class : { -or|-and : [ { field : { op : value }, ... }, ...] ... }, ... }
2101 [ { +class : { -or|-and : [ { field : { op : value }, ... }, ...] ... }, ... }, ... ]
2105 static char* searchWHERE ( const jsonObject* search_hash, osrfHash* meta, int opjoin_type, osrfMethodContext* ctx ) {
2109 "%s: Entering searchWHERE; search_hash addr = %d, meta addr = %d, opjoin_type = %d, ctx addr = %d",
2117 growing_buffer* sql_buf = buffer_init(128);
2119 jsonObject* node = NULL;
2122 if ( search_hash->type == JSON_ARRAY ) {
2123 osrfLogDebug(OSRF_LOG_MARK, "%s: In WHERE clause, condition type is JSON_ARRAY", MODULENAME);
2124 jsonIterator* search_itr = jsonNewIterator( search_hash );
2125 while ( (node = jsonIteratorNext( search_itr )) ) {
2129 if (opjoin_type == OR_OP_JOIN) buffer_add(sql_buf, " OR ");
2130 else buffer_add(sql_buf, " AND ");
2133 char* subpred = searchWHERE( node, meta, opjoin_type, ctx );
2134 buffer_fadd(sql_buf, "( %s )", subpred);
2137 jsonIteratorFree(search_itr);
2139 } else if ( search_hash->type == JSON_HASH ) {
2140 osrfLogDebug(OSRF_LOG_MARK, "%s: In WHERE clause, condition type is JSON_HASH", MODULENAME);
2141 jsonIterator* search_itr = jsonNewIterator( search_hash );
2142 while ( (node = jsonIteratorNext( search_itr )) ) {
2147 if (opjoin_type == OR_OP_JOIN) buffer_add(sql_buf, " OR ");
2148 else buffer_add(sql_buf, " AND ");
2151 if ( !strncmp("+",search_itr->key,1) ) {
2152 if ( node->type == JSON_STRING ) {
2153 char* subpred = jsonObjectToSimpleString( node );
2154 buffer_fadd(sql_buf, " \"%s\".%s ", search_itr->key + 1, subpred);
2157 char* subpred = searchWHERE( node, osrfHashGet( oilsIDL(), search_itr->key + 1 ), AND_OP_JOIN, ctx );
2158 buffer_fadd(sql_buf, "( %s )", subpred);
2161 } else if ( !strcasecmp("-or",search_itr->key) ) {
2162 char* subpred = searchWHERE( node, meta, OR_OP_JOIN, ctx );
2163 buffer_fadd(sql_buf, "( %s )", subpred);
2165 } else if ( !strcasecmp("-and",search_itr->key) ) {
2166 char* subpred = searchWHERE( node, meta, AND_OP_JOIN, ctx );
2167 buffer_fadd(sql_buf, "( %s )", subpred);
2169 } else if ( !strcasecmp("-exists",search_itr->key) ) {
2170 char* subpred = SELECT(
2172 jsonObjectGetKey( node, "select" ),
2173 jsonObjectGetKey( node, "from" ),
2174 jsonObjectGetKey( node, "where" ),
2175 jsonObjectGetKey( node, "having" ),
2176 jsonObjectGetKey( node, "order_by" ),
2177 jsonObjectGetKey( node, "limit" ),
2178 jsonObjectGetKey( node, "offset" ),
2182 buffer_fadd(sql_buf, "EXISTS ( %s )", subpred);
2184 } else if ( !strcasecmp("-not-exists",search_itr->key) ) {
2185 char* subpred = SELECT(
2187 jsonObjectGetKey( node, "select" ),
2188 jsonObjectGetKey( node, "from" ),
2189 jsonObjectGetKey( node, "where" ),
2190 jsonObjectGetKey( node, "having" ),
2191 jsonObjectGetKey( node, "order_by" ),
2192 jsonObjectGetKey( node, "limit" ),
2193 jsonObjectGetKey( node, "offset" ),
2197 buffer_fadd(sql_buf, "NOT EXISTS ( %s )", subpred);
2201 char* class = osrfHashGet(meta, "classname");
2202 osrfHash* fields = osrfHashGet(meta, "fields");
2203 osrfHash* field = osrfHashGet( fields, search_itr->key );
2207 char* table = getSourceDefinition(meta);
2210 "%s: Attempt to reference non-existant column %s on %s (%s)",
2216 buffer_free(sql_buf);
2218 jsonIteratorFree(search_itr);
2222 char* subpred = searchPredicate( class, field, node );
2223 buffer_add( sql_buf, subpred );
2227 jsonIteratorFree(search_itr);
2230 // ERROR ... only hash and array allowed at this level
2231 char* predicate_string = jsonObjectToJSON( search_hash );
2234 "%s: Invalid predicate structure: %s",
2238 buffer_free(sql_buf);
2239 free(predicate_string);
2244 return buffer_release(sql_buf);
2247 static char* SELECT (
2248 /* method context */ osrfMethodContext* ctx,
2250 /* SELECT */ jsonObject* selhash,
2251 /* FROM */ jsonObject* join_hash,
2252 /* WHERE */ jsonObject* search_hash,
2253 /* HAVING */ jsonObject* having_hash,
2254 /* ORDER BY */ jsonObject* order_hash,
2255 /* LIMIT */ jsonObject* limit,
2256 /* OFFSET */ jsonObject* offset,
2257 /* flags */ int flags
2259 const char* locale = osrf_message_get_last_locale();
2261 // in case we don't get a select list
2262 jsonObject* defaultselhash = NULL;
2264 // general tmp objects
2265 const jsonObject* tmp_const;
2266 jsonObject* _tmp = NULL;
2267 jsonObject* selclass = NULL;
2268 jsonObject* selfield = NULL;
2269 jsonObject* snode = NULL;
2270 jsonObject* onode = NULL;
2271 jsonObject* found = NULL;
2273 char* string = NULL;
2274 int from_function = 0;
2279 // the core search class
2280 char* core_class = NULL;
2282 // metadata about the core search class
2283 osrfHash* core_meta = NULL;
2284 osrfHash* core_fields = NULL;
2285 osrfHash* idlClass = NULL;
2287 // punt if there's no core class
2288 if (!join_hash || ( join_hash->type == JSON_HASH && !join_hash->size ))
2291 // get the core class -- the only key of the top level FROM clause, or a string
2292 if (join_hash->type == JSON_HASH) {
2293 jsonIterator* tmp_itr = jsonNewIterator( join_hash );
2294 snode = jsonIteratorNext( tmp_itr );
2296 core_class = strdup( tmp_itr->key );
2299 jsonIteratorFree( tmp_itr );
2302 } else if (join_hash->type == JSON_ARRAY) {
2306 } else if (join_hash->type == JSON_STRING) {
2307 core_class = jsonObjectToSimpleString( join_hash );
2311 // punt if we don't know about the core class (and it's not a function)
2312 if (!from_function && !(core_meta = osrfHashGet( oilsIDL(), core_class ))) {
2317 // if the select list is empty, or the core class field list is '*',
2318 // build the default select list ...
2320 selhash = defaultselhash = jsonNewObjectType(JSON_HASH);
2321 jsonObjectSetKey( selhash, core_class, jsonNewObjectType(JSON_ARRAY) );
2322 } else if ( (tmp_const = jsonObjectGetKeyConst( selhash, core_class )) && tmp_const->type == JSON_STRING ) {
2323 char* _x = jsonObjectToSimpleString( tmp_const );
2324 if (!strncmp( "*", _x, 1 )) {
2325 jsonObjectRemoveKey( selhash, core_class );
2326 jsonObjectSetKey( selhash, core_class, jsonNewObjectType(JSON_ARRAY) );
2332 growing_buffer* sql_buf = buffer_init(128);
2334 // temp buffer for the SELECT list
2335 growing_buffer* select_buf = buffer_init(128);
2336 growing_buffer* order_buf = buffer_init(128);
2337 growing_buffer* group_buf = buffer_init(128);
2338 growing_buffer* having_buf = buffer_init(128);
2341 core_fields = osrfHashGet(core_meta, "fields");
2343 // ... and if we /are/ building the default list, do that
2344 if ( (_tmp = jsonObjectGetKey(selhash,core_class)) && !_tmp->size ) {
2349 if (!from_function) {
2350 osrfStringArray* keys = osrfHashKeys( core_fields );
2351 while ( (field = osrfStringArrayGetString(keys, i++)) ) {
2352 if ( strncasecmp( "true", osrfHashGet( osrfHashGet( core_fields, field ), "virtual" ), 4 ) )
2353 jsonObjectPush( _tmp, jsonNewObject( field ) );
2355 osrfStringArrayFree(keys);
2359 // Now we build the actual select list
2360 if (!from_function) {
2362 jsonObject* is_agg = jsonObjectFindPath(selhash, "//aggregate");
2365 jsonIterator* selclass_itr = jsonNewIterator( selhash );
2366 while ( (selclass = jsonIteratorNext( selclass_itr )) ) {
2368 // round trip through the idl, just to be safe
2369 idlClass = osrfHashGet( oilsIDL(), selclass_itr->key );
2370 if (!idlClass) continue;
2371 char* cname = osrfHashGet(idlClass, "classname");
2373 // make sure the target relation is in the join tree
2374 if (strcmp(core_class,cname)) {
2375 if (!join_hash) continue;
2377 if (join_hash->type == JSON_STRING) {
2378 string = jsonObjectToSimpleString(join_hash);
2379 found = strcmp(string,cname) ? NULL : jsonParseString("{\"1\":\"1\"}");
2382 found = jsonObjectFindPath(join_hash, "//%s", cname);
2386 jsonObjectFree(found);
2390 jsonObjectFree(found);
2393 // stitch together the column list ...
2394 jsonIterator* select_itr = jsonNewIterator( selclass );
2395 while ( (selfield = jsonIteratorNext( select_itr )) ) {
2397 char* __column = NULL;
2398 char* __alias = NULL;
2400 // ... if it's a sstring, just toss it on the pile
2401 if (selfield->type == JSON_STRING) {
2403 // again, just to be safe
2404 char* _requested_col = jsonObjectToSimpleString(selfield);
2405 osrfHash* field = osrfHashGet( osrfHashGet( idlClass, "fields" ), _requested_col );
2406 free(_requested_col);
2408 if (!field) continue;
2409 __column = strdup(osrfHashGet(field, "name"));
2414 OSRF_BUFFER_ADD_CHAR( select_buf, ',' );
2418 char* i18n = osrfHashGet(field, "i18n");
2419 if (flags & DISABLE_I18N)
2422 if ( i18n && !strncasecmp("true", i18n, 4)) {
2423 char* pkey = osrfHashGet(idlClass, "primarykey");
2424 char* tname = osrfHashGet(idlClass, "tablename");
2426 buffer_fadd(select_buf, " oils_i18n_xlate('%s', '%s', '%s', '%s', \"%s\".%s::TEXT, '%s') AS \"%s\"", tname, cname, __column, pkey, cname, pkey, locale, __column);
2428 buffer_fadd(select_buf, " \"%s\".%s AS \"%s\"", cname, __column, __column);
2431 buffer_fadd(select_buf, " \"%s\".%s AS \"%s\"", cname, __column, __column);
2434 // ... but it could be an object, in which case we check for a Field Transform
2437 __column = jsonObjectToSimpleString( jsonObjectGetKeyConst( selfield, "column" ) );
2439 // again, just to be safe
2440 osrfHash* field = osrfHashGet( osrfHashGet( idlClass, "fields" ), __column );
2441 if (!field) continue;
2442 const char* fname = osrfHashGet(field, "name");
2447 OSRF_BUFFER_ADD_CHAR( select_buf, ',' );
2450 if ((tmp_const = jsonObjectGetKeyConst( selfield, "alias" ))) {
2451 __alias = jsonObjectToSimpleString( tmp_const );
2453 __alias = strdup(__column);
2456 if (jsonObjectGetKeyConst( selfield, "transform" )) {
2458 __column = searchFieldTransform(cname, field, selfield);
2459 buffer_fadd(select_buf, " %s AS \"%s\"", __column, __alias);
2462 char* i18n = osrfHashGet(field, "i18n");
2463 if (flags & DISABLE_I18N)
2466 if ( i18n && !strncasecmp("true", i18n, 4)) {
2467 char* pkey = osrfHashGet(idlClass, "primarykey");
2468 char* tname = osrfHashGet(idlClass, "tablename");
2470 buffer_fadd(select_buf, " oils_i18n_xlate('%s', '%s', '%s', '%s', \"%s\".%s::TEXT, '%s') AS \"%s\"", tname, cname, fname, pkey, cname, pkey, locale, __alias);
2472 buffer_fadd(select_buf, " \"%s\".%s AS \"%s\"", cname, fname, __alias);
2475 buffer_fadd(select_buf, " \"%s\".%s AS \"%s\"", cname, fname, __alias);
2480 if (is_agg->size || (flags & SELECT_DISTINCT)) {
2483 jsonBoolIsTrue( jsonObjectGetKey( selfield, "aggregate" ) ) ||
2484 ((int)jsonObjectGetNumber(jsonObjectGetKey( selfield, "aggregate" ))) == 1 // support 1/0 for perl's sake
2490 OSRF_BUFFER_ADD_CHAR( group_buf, ',' );
2493 buffer_fadd(group_buf, " %d", sel_pos);
2495 } else if (is_agg = jsonObjectGetKey( selfield, "having" )) {
2499 OSRF_BUFFER_ADD_CHAR( group_buf, ',' );
2502 __column = searchFieldTransform(cname, field, selfield);
2503 OSRF_BUFFER_ADD_CHAR(group_buf, ' ');
2504 OSRF_BUFFER_ADD(group_buf, __column);
2505 __column = searchFieldTransform(cname, field, selfield);
2510 if (__column) free(__column);
2511 if (__alias) free(__alias);
2516 // jsonIteratorFree(select_itr);
2519 // jsonIteratorFree(selclass_itr);
2521 if (is_agg) jsonObjectFree(is_agg);
2523 OSRF_BUFFER_ADD_CHAR( select_buf, '*' );
2527 char* col_list = buffer_release(select_buf);
2529 if (!from_function) table = getSourceDefinition(core_meta);
2530 else table = searchValueTransform(join_hash);
2532 // Put it all together
2533 buffer_fadd(sql_buf, "SELECT %s FROM %s AS \"%s\" ", col_list, table, core_class );
2537 if (!from_function) {
2538 // Now, walk the join tree and add that clause
2540 char* join_clause = searchJOIN( join_hash, core_meta );
2541 buffer_add(sql_buf, join_clause);
2545 if ( search_hash ) {
2546 buffer_add(sql_buf, " WHERE ");
2548 // and it's on the the WHERE clause
2549 char* pred = searchWHERE( search_hash, core_meta, AND_OP_JOIN, ctx );
2553 osrfAppSessionStatus(
2555 OSRF_STATUS_INTERNALSERVERERROR,
2556 "osrfMethodException",
2558 "Severe query error in WHERE predicate -- see error log for more details"
2562 buffer_free(having_buf);
2563 buffer_free(group_buf);
2564 buffer_free(order_buf);
2565 buffer_free(sql_buf);
2566 if (defaultselhash) jsonObjectFree(defaultselhash);
2569 buffer_add(sql_buf, pred);
2574 if ( having_hash ) {
2575 buffer_add(sql_buf, " HAVING ");
2577 // and it's on the the WHERE clause
2578 char* pred = searchWHERE( having_hash, core_meta, AND_OP_JOIN, ctx );
2582 osrfAppSessionStatus(
2584 OSRF_STATUS_INTERNALSERVERERROR,
2585 "osrfMethodException",
2587 "Severe query error in HAVING predicate -- see error log for more details"
2591 buffer_free(having_buf);
2592 buffer_free(group_buf);
2593 buffer_free(order_buf);
2594 buffer_free(sql_buf);
2595 if (defaultselhash) jsonObjectFree(defaultselhash);
2598 buffer_add(sql_buf, pred);
2604 jsonIterator* class_itr = jsonNewIterator( order_hash );
2605 while ( (snode = jsonIteratorNext( class_itr )) ) {
2607 if (!jsonObjectGetKeyConst(selhash,class_itr->key))
2610 if ( snode->type == JSON_HASH ) {
2612 jsonIterator* order_itr = jsonNewIterator( snode );
2613 while ( (onode = jsonIteratorNext( order_itr )) ) {
2615 if (!oilsIDLFindPath( "/%s/fields/%s", class_itr->key, order_itr->key ))
2618 char* direction = NULL;
2619 if ( onode->type == JSON_HASH ) {
2620 if ( jsonObjectGetKeyConst( onode, "transform" ) ) {
2621 string = searchFieldTransform(
2623 oilsIDLFindPath( "/%s/fields/%s", class_itr->key, order_itr->key ),
2627 growing_buffer* field_buf = buffer_init(16);
2628 buffer_fadd(field_buf, "\"%s\".%s", class_itr->key, order_itr->key);
2629 string = buffer_release(field_buf);
2632 if ( (tmp_const = jsonObjectGetKeyConst( onode, "direction" )) ) {
2633 direction = jsonObjectToSimpleString(tmp_const);
2634 if (!strncasecmp(direction, "d", 1)) {
2636 direction = " DESC";
2644 string = strdup(order_itr->key);
2645 direction = jsonObjectToSimpleString(onode);
2646 if (!strncasecmp(direction, "d", 1)) {
2648 direction = " DESC";
2658 buffer_add(order_buf, ", ");
2661 buffer_add(order_buf, string);
2665 buffer_add(order_buf, direction);
2669 // jsonIteratorFree(order_itr);
2671 } else if ( snode->type == JSON_ARRAY ) {
2673 jsonIterator* order_itr = jsonNewIterator( snode );
2674 while ( (onode = jsonIteratorNext( order_itr )) ) {
2676 char* _f = jsonObjectToSimpleString( onode );
2678 if (!oilsIDLFindPath( "/%s/fields/%s", class_itr->key, _f))
2684 buffer_add(order_buf, ", ");
2687 buffer_add(order_buf, _f);
2691 // jsonIteratorFree(order_itr);
2694 // IT'S THE OOOOOOOOOOOLD STYLE!
2696 osrfLogError(OSRF_LOG_MARK, "%s: Possible SQL injection attempt; direct order by is not allowed", MODULENAME);
2698 osrfAppSessionStatus(
2700 OSRF_STATUS_INTERNALSERVERERROR,
2701 "osrfMethodException",
2703 "Severe query error -- see error log for more details"
2708 buffer_free(having_buf);
2709 buffer_free(group_buf);
2710 buffer_free(order_buf);
2711 buffer_free(sql_buf);
2712 if (defaultselhash) jsonObjectFree(defaultselhash);
2713 jsonIteratorFree(class_itr);
2720 // jsonIteratorFree(class_itr);
2722 string = buffer_release(group_buf);
2724 if (strlen(string)) {
2725 OSRF_BUFFER_ADD( sql_buf, " GROUP BY " );
2726 OSRF_BUFFER_ADD( sql_buf, string );
2731 string = buffer_release(having_buf);
2733 if (strlen(string)) {
2734 OSRF_BUFFER_ADD( sql_buf, " HAVING " );
2735 OSRF_BUFFER_ADD( sql_buf, string );
2740 string = buffer_release(order_buf);
2742 if (strlen(string)) {
2743 OSRF_BUFFER_ADD( sql_buf, " ORDER BY " );
2744 OSRF_BUFFER_ADD( sql_buf, string );
2750 string = jsonObjectToSimpleString(limit);
2751 buffer_fadd( sql_buf, " LIMIT %d", atoi(string) );
2756 string = jsonObjectToSimpleString(offset);
2757 buffer_fadd( sql_buf, " OFFSET %d", atoi(string) );
2761 if (!(flags & SUBSELECT)) OSRF_BUFFER_ADD_CHAR(sql_buf, ';');
2764 if (defaultselhash) jsonObjectFree(defaultselhash);
2766 return buffer_release(sql_buf);
2770 static char* buildSELECT ( jsonObject* search_hash, jsonObject* order_hash, osrfHash* meta, osrfMethodContext* ctx ) {
2772 const char* locale = osrf_message_get_last_locale();
2774 osrfHash* fields = osrfHashGet(meta, "fields");
2775 char* core_class = osrfHashGet(meta, "classname");
2777 const jsonObject* join_hash = jsonObjectGetKeyConst( order_hash, "join" );
2779 jsonObject* node = NULL;
2780 jsonObject* snode = NULL;
2781 jsonObject* onode = NULL;
2782 const jsonObject* _tmp = NULL;
2783 jsonObject* selhash = NULL;
2784 jsonObject* defaultselhash = NULL;
2786 growing_buffer* sql_buf = buffer_init(128);
2787 growing_buffer* select_buf = buffer_init(128);
2789 if ( !(selhash = jsonObjectGetKey( order_hash, "select" )) ) {
2790 defaultselhash = jsonNewObjectType(JSON_HASH);
2791 selhash = defaultselhash;
2794 if ( !jsonObjectGetKeyConst(selhash,core_class) ) {
2795 jsonObjectSetKey( selhash, core_class, jsonNewObjectType(JSON_ARRAY) );
2796 jsonObject* flist = jsonObjectGetKey( selhash, core_class );
2801 osrfStringArray* keys = osrfHashKeys( fields );
2802 while ( (field = osrfStringArrayGetString(keys, i++)) ) {
2803 if ( strcasecmp( "true", osrfHashGet( osrfHashGet( fields, field ), "virtual" ) ) )
2804 jsonObjectPush( flist, jsonNewObject( field ) );
2806 osrfStringArrayFree(keys);
2810 jsonIterator* class_itr = jsonNewIterator( selhash );
2811 while ( (snode = jsonIteratorNext( class_itr )) ) {
2813 osrfHash* idlClass = osrfHashGet( oilsIDL(), class_itr->key );
2814 if (!idlClass) continue;
2815 char* cname = osrfHashGet(idlClass, "classname");
2817 if (strcmp(core_class,class_itr->key)) {
2818 if (!join_hash) continue;
2820 jsonObject* found = jsonObjectFindPath(join_hash, "//%s", class_itr->key);
2822 jsonObjectFree(found);
2826 jsonObjectFree(found);
2829 jsonIterator* select_itr = jsonNewIterator( snode );
2830 while ( (node = jsonIteratorNext( select_itr )) ) {
2831 char* item_str = jsonObjectToSimpleString(node);
2832 osrfHash* field = osrfHashGet( osrfHashGet( idlClass, "fields" ), item_str );
2834 char* fname = osrfHashGet(field, "name");
2836 if (!field) continue;
2841 OSRF_BUFFER_ADD_CHAR(select_buf, ',');
2845 char* i18n = osrfHashGet(field, "i18n");
2847 jsonBoolIsTrue( jsonObjectGetKey( order_hash, "no_i18n" ) ) ||
2848 ((int)jsonObjectGetNumber(jsonObjectGetKey( order_hash, "no_i18n" ))) == 1 // support 1/0 for perl's sake
2852 if ( i18n && !strncasecmp("true", i18n, 4)) {
2853 char* pkey = osrfHashGet(idlClass, "primarykey");
2854 char* tname = osrfHashGet(idlClass, "tablename");
2856 buffer_fadd(select_buf, " oils_i18n_xlate('%s', '%s', '%s', '%s', \"%s\".%s::TEXT, '%s') AS \"%s\"", tname, cname, fname, pkey, cname, pkey, locale, fname);
2858 buffer_fadd(select_buf, " \"%s\".%s", cname, fname);
2861 buffer_fadd(select_buf, " \"%s\".%s", cname, fname);
2865 jsonIteratorFree(select_itr);
2868 jsonIteratorFree(class_itr);
2870 char* col_list = buffer_release(select_buf);
2871 char* table = getSourceDefinition(meta);
2873 buffer_fadd(sql_buf, "SELECT %s FROM %s AS \"%s\"", col_list, table, core_class );
2878 char* join_clause = searchJOIN( join_hash, meta );
2879 OSRF_BUFFER_ADD_CHAR(sql_buf, ' ');
2880 OSRF_BUFFER_ADD(sql_buf, join_clause);
2884 osrfLogDebug(OSRF_LOG_MARK, "%s pre-predicate SQL = %s",
2885 MODULENAME, OSRF_BUFFER_C_STR(sql_buf));
2887 buffer_add(sql_buf, " WHERE ");
2889 char* pred = searchWHERE( search_hash, meta, AND_OP_JOIN, ctx );
2891 osrfAppSessionStatus(
2893 OSRF_STATUS_INTERNALSERVERERROR,
2894 "osrfMethodException",
2896 "Severe query error -- see error log for more details"
2898 buffer_free(sql_buf);
2899 if(defaultselhash) jsonObjectFree(defaultselhash);
2902 buffer_add(sql_buf, pred);
2907 char* string = NULL;
2908 if ( (_tmp = jsonObjectGetKeyConst( order_hash, "order_by" )) ){
2910 growing_buffer* order_buf = buffer_init(128);
2913 jsonIterator* class_itr = jsonNewIterator( _tmp );
2914 while ( (snode = jsonIteratorNext( class_itr )) ) {
2916 if (!jsonObjectGetKeyConst(selhash,class_itr->key))
2919 if ( snode->type == JSON_HASH ) {
2921 jsonIterator* order_itr = jsonNewIterator( snode );
2922 while ( (onode = jsonIteratorNext( order_itr )) ) {
2924 if (!oilsIDLFindPath( "/%s/fields/%s", class_itr->key, order_itr->key ))
2927 char* direction = NULL;
2928 if ( onode->type == JSON_HASH ) {
2929 if ( jsonObjectGetKeyConst( onode, "transform" ) ) {
2930 string = searchFieldTransform(
2932 oilsIDLFindPath( "/%s/fields/%s", class_itr->key, order_itr->key ),
2936 growing_buffer* field_buf = buffer_init(16);
2937 buffer_fadd(field_buf, "\"%s\".%s", class_itr->key, order_itr->key);
2938 string = buffer_release(field_buf);
2941 if ( (_tmp = jsonObjectGetKeyConst( onode, "direction" )) ) {
2942 direction = jsonObjectToSimpleString(_tmp);
2943 if (!strncasecmp(direction, "d", 1)) {
2945 direction = " DESC";
2953 string = strdup(order_itr->key);
2954 direction = jsonObjectToSimpleString(onode);
2955 if (!strncasecmp(direction, "d", 1)) {
2957 direction = " DESC";
2967 buffer_add(order_buf, ", ");
2970 buffer_add(order_buf, string);
2974 buffer_add(order_buf, direction);
2979 jsonIteratorFree(order_itr);
2982 string = jsonObjectToSimpleString(snode);
2983 buffer_add(order_buf, string);
2990 jsonIteratorFree(class_itr);
2992 string = buffer_release(order_buf);
2994 if (strlen(string)) {
2995 OSRF_BUFFER_ADD( sql_buf, " ORDER BY " );
2996 OSRF_BUFFER_ADD( sql_buf, string );
3002 if ( (_tmp = jsonObjectGetKeyConst( order_hash, "limit" )) ){
3003 string = jsonObjectToSimpleString(_tmp);
3012 _tmp = jsonObjectGetKeyConst( order_hash, "offset" );
3014 string = jsonObjectToSimpleString(_tmp);
3024 if (defaultselhash) jsonObjectFree(defaultselhash);
3026 OSRF_BUFFER_ADD_CHAR(sql_buf, ';');
3027 return buffer_release(sql_buf);
3030 int doJSONSearch ( osrfMethodContext* ctx ) {
3031 OSRF_METHOD_VERIFY_CONTEXT(ctx);
3032 osrfLogDebug(OSRF_LOG_MARK, "Recieved query request");
3037 dbhandle = writehandle;
3039 jsonObject* hash = jsonObjectGetIndex(ctx->params, 0);
3043 if (jsonBoolIsTrue(jsonObjectGetKey( hash, "distinct" )))
3044 flags |= SELECT_DISTINCT;
3046 if ( ((int)jsonObjectGetNumber(jsonObjectGetKey( hash, "distinct" ))) == 1 ) // support 1/0 for perl's sake
3047 flags |= SELECT_DISTINCT;
3049 if (jsonBoolIsTrue(jsonObjectGetKey( hash, "no_i18n" )))
3050 flags |= DISABLE_I18N;
3052 if ( ((int)jsonObjectGetNumber(jsonObjectGetKey( hash, "no_i18n" ))) == 1 ) // support 1/0 for perl's sake
3053 flags |= DISABLE_I18N;
3055 osrfLogDebug(OSRF_LOG_MARK, "Building SQL ...");
3058 jsonObjectGetKey( hash, "select" ),
3059 jsonObjectGetKey( hash, "from" ),
3060 jsonObjectGetKey( hash, "where" ),
3061 jsonObjectGetKey( hash, "having" ),
3062 jsonObjectGetKey( hash, "order_by" ),
3063 jsonObjectGetKey( hash, "limit" ),
3064 jsonObjectGetKey( hash, "offset" ),
3073 osrfLogDebug(OSRF_LOG_MARK, "%s SQL = %s", MODULENAME, sql);
3074 dbi_result result = dbi_conn_query(dbhandle, sql);
3077 osrfLogDebug(OSRF_LOG_MARK, "Query returned with no errors");
3079 if (dbi_result_first_row(result)) {
3080 /* JSONify the result */
3081 osrfLogDebug(OSRF_LOG_MARK, "Query returned at least one row");
3084 jsonObject* return_val = oilsMakeJSONFromResult( result );
3085 osrfAppRespond( ctx, return_val );
3086 jsonObjectFree( return_val );
3087 } while (dbi_result_next_row(result));
3090 osrfLogDebug(OSRF_LOG_MARK, "%s returned no results for query %s", MODULENAME, sql);
3093 osrfAppRespondComplete( ctx, NULL );
3095 /* clean up the query */
3096 dbi_result_free(result);
3100 osrfLogError(OSRF_LOG_MARK, "%s: Error with query [%s]", MODULENAME, sql);
3101 osrfAppSessionStatus(
3103 OSRF_STATUS_INTERNALSERVERERROR,
3104 "osrfMethodException",
3106 "Severe query error -- see error log for more details"
3114 static jsonObject* doFieldmapperSearch ( osrfMethodContext* ctx, osrfHash* meta,
3115 const jsonObject* params, int* err ) {
3118 dbhandle = writehandle;
3120 osrfHash* links = osrfHashGet(meta, "links");
3121 osrfHash* fields = osrfHashGet(meta, "fields");
3122 char* core_class = osrfHashGet(meta, "classname");
3123 char* pkey = osrfHashGet(meta, "primarykey");
3125 const jsonObject* _tmp;
3127 jsonObject* search_hash = jsonObjectGetIndex(params, 0);
3128 jsonObject* order_hash = jsonObjectGetIndex(params, 1);
3130 char* sql = buildSELECT( search_hash, order_hash, meta, ctx );
3132 osrfLogDebug(OSRF_LOG_MARK, "Problem building query, returning NULL");
3137 osrfLogDebug(OSRF_LOG_MARK, "%s SQL = %s", MODULENAME, sql);
3138 dbi_result result = dbi_conn_query(dbhandle, sql);
3140 jsonObject* res_list = jsonNewObjectType(JSON_ARRAY);
3142 osrfLogDebug(OSRF_LOG_MARK, "Query returned with no errors");
3143 osrfHash* dedup = osrfNewHash();
3145 if (dbi_result_first_row(result)) {
3146 /* JSONify the result */
3147 osrfLogDebug(OSRF_LOG_MARK, "Query returned at least one row");
3149 obj = oilsMakeFieldmapperFromResult( result, meta );
3150 char* pkey_val = oilsFMGetString( obj, pkey );
3151 if ( osrfHashGet( dedup, pkey_val ) ) {
3152 jsonObjectFree(obj);
3155 osrfHashSet( dedup, pkey_val, pkey_val );
3156 jsonObjectPush(res_list, obj);
3158 } while (dbi_result_next_row(result));
3160 osrfLogDebug(OSRF_LOG_MARK, "%s returned no results for query %s", MODULENAME, sql);
3163 osrfHashFree(dedup);
3165 /* clean up the query */
3166 dbi_result_free(result);
3169 osrfLogError(OSRF_LOG_MARK, "%s: Error retrieving %s with query [%s]", MODULENAME, osrfHashGet(meta, "fieldmapper"), sql);
3170 osrfAppSessionStatus(
3172 OSRF_STATUS_INTERNALSERVERERROR,
3173 "osrfMethodException",
3175 "Severe query error -- see error log for more details"
3179 jsonObjectFree(res_list);
3186 if (res_list->size && order_hash) {
3187 _tmp = jsonObjectGetKeyConst( order_hash, "flesh" );
3189 int x = (int)jsonObjectGetNumber(_tmp);
3190 if (x == -1 || x > max_flesh_depth) x = max_flesh_depth;
3192 const jsonObject* temp_blob;
3193 if ((temp_blob = jsonObjectGetKeyConst( order_hash, "flesh_fields" )) && x > 0) {
3195 jsonObject* flesh_blob = jsonObjectClone( temp_blob );
3196 const jsonObject* flesh_fields = jsonObjectGetKeyConst( flesh_blob, core_class );
3198 osrfStringArray* link_fields = NULL;
3201 if (flesh_fields->size == 1) {
3202 char* _t = jsonObjectToSimpleString( jsonObjectGetIndex( flesh_fields, 0 ) );
3203 if (!strcmp(_t,"*")) link_fields = osrfHashKeys( links );
3209 link_fields = osrfNewStringArray(1);
3210 jsonIterator* _i = jsonNewIterator( flesh_fields );
3211 while ((_f = jsonIteratorNext( _i ))) {
3212 osrfStringArrayAdd( link_fields, jsonObjectToSimpleString( _f ) );
3214 jsonIteratorFree(_i);
3219 jsonIterator* itr = jsonNewIterator( res_list );
3220 while ((cur = jsonIteratorNext( itr ))) {
3225 while ( (link_field = osrfStringArrayGetString(link_fields, i++)) ) {
3227 osrfLogDebug(OSRF_LOG_MARK, "Starting to flesh %s", link_field);
3229 osrfHash* kid_link = osrfHashGet(links, link_field);
3230 if (!kid_link) continue;
3232 osrfHash* field = osrfHashGet(fields, link_field);
3233 if (!field) continue;
3235 osrfHash* value_field = field;
3237 osrfHash* kid_idl = osrfHashGet(oilsIDL(), osrfHashGet(kid_link, "class"));
3238 if (!kid_idl) continue;
3240 if (!(strcmp( osrfHashGet(kid_link, "reltype"), "has_many" ))) { // has_many
3241 value_field = osrfHashGet( fields, osrfHashGet(meta, "primarykey") );
3244 if (!(strcmp( osrfHashGet(kid_link, "reltype"), "might_have" ))) { // might_have
3245 value_field = osrfHashGet( fields, osrfHashGet(meta, "primarykey") );
3248 osrfStringArray* link_map = osrfHashGet( kid_link, "map" );
3250 if (link_map->size > 0) {
3251 jsonObject* _kid_key = jsonNewObjectType(JSON_ARRAY);
3254 jsonNewObject( osrfStringArrayGetString( link_map, 0 ) )
3259 osrfHashGet(kid_link, "class"),
3266 "Link field: %s, remote class: %s, fkey: %s, reltype: %s",
3267 osrfHashGet(kid_link, "field"),
3268 osrfHashGet(kid_link, "class"),
3269 osrfHashGet(kid_link, "key"),
3270 osrfHashGet(kid_link, "reltype")
3273 jsonObject* fake_params = jsonNewObjectType(JSON_ARRAY);
3274 jsonObjectPush(fake_params, jsonNewObjectType(JSON_HASH)); // search hash
3275 jsonObjectPush(fake_params, jsonNewObjectType(JSON_HASH)); // order/flesh hash
3277 osrfLogDebug(OSRF_LOG_MARK, "Creating dummy params object...");
3280 jsonObjectToSimpleString(
3283 atoi( osrfHashGet(value_field, "array_position") )
3288 osrfLogDebug(OSRF_LOG_MARK, "Nothing to search for!");
3293 jsonObjectGetIndex(fake_params, 0),
3294 osrfHashGet(kid_link, "key"),
3295 jsonNewObject( search_key )
3302 jsonObjectGetIndex(fake_params, 1),
3304 jsonNewNumberObject( (double)(x - 1 + link_map->size) )
3308 jsonObjectSetKey( jsonObjectGetIndex(fake_params, 1), "flesh_fields", jsonObjectClone(flesh_blob) );
3310 if (jsonObjectGetKeyConst(order_hash, "order_by")) {
3312 jsonObjectGetIndex(fake_params, 1),
3314 jsonObjectClone(jsonObjectGetKeyConst(order_hash, "order_by"))
3318 if (jsonObjectGetKeyConst(order_hash, "select")) {
3320 jsonObjectGetIndex(fake_params, 1),
3322 jsonObjectClone(jsonObjectGetKeyConst(order_hash, "select"))
3326 jsonObject* kids = doFieldmapperSearch(ctx, kid_idl, fake_params, err);
3329 jsonObjectFree( fake_params );
3330 osrfStringArrayFree(link_fields);
3331 jsonIteratorFree(itr);
3332 jsonObjectFree(res_list);
3333 jsonObjectFree(flesh_blob);
3337 osrfLogDebug(OSRF_LOG_MARK, "Search for %s return %d linked objects", osrfHashGet(kid_link, "class"), kids->size);
3339 jsonObject* X = NULL;
3340 if ( link_map->size > 0 && kids->size > 0 ) {
3342 kids = jsonNewObjectType(JSON_ARRAY);
3344 jsonObject* _k_node;
3345 jsonIterator* _k = jsonNewIterator( X );
3346 while ((_k_node = jsonIteratorNext( _k ))) {
3352 (unsigned long)atoi(
3358 osrfHashGet(kid_link, "class")
3362 osrfStringArrayGetString( link_map, 0 )
3371 jsonIteratorFree(_k);
3374 if (!(strcmp( osrfHashGet(kid_link, "reltype"), "has_a" )) || !(strcmp( osrfHashGet(kid_link, "reltype"), "might_have" ))) {
3375 osrfLogDebug(OSRF_LOG_MARK, "Storing fleshed objects in %s", osrfHashGet(kid_link, "field"));
3378 (unsigned long)atoi( osrfHashGet( field, "array_position" ) ),
3379 jsonObjectClone( jsonObjectGetIndex(kids, 0) )
3383 if (!(strcmp( osrfHashGet(kid_link, "reltype"), "has_many" ))) { // has_many
3384 osrfLogDebug(OSRF_LOG_MARK, "Storing fleshed objects in %s", osrfHashGet(kid_link, "field"));
3387 (unsigned long)atoi( osrfHashGet( field, "array_position" ) ),
3388 jsonObjectClone( kids )
3393 jsonObjectFree(kids);
3397 jsonObjectFree( kids );
3398 jsonObjectFree( fake_params );
3400 osrfLogDebug(OSRF_LOG_MARK, "Fleshing of %s complete", osrfHashGet(kid_link, "field"));
3401 osrfLogDebug(OSRF_LOG_MARK, "%s", jsonObjectToJSON(cur));
3405 jsonObjectFree( flesh_blob );
3406 osrfStringArrayFree(link_fields);
3407 jsonIteratorFree(itr);
3416 static jsonObject* doUpdate(osrfMethodContext* ctx, int* err ) {
3418 osrfHash* meta = osrfHashGet( (osrfHash*) ctx->method->userData, "class" );
3420 jsonObject* target = jsonObjectGetIndex( ctx->params, 1 );
3422 jsonObject* target = jsonObjectGetIndex( ctx->params, 0 );
3425 if (!verifyObjectClass(ctx, target)) {
3430 if (!osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" )) {
3431 osrfAppSessionStatus(
3433 OSRF_STATUS_BADREQUEST,
3434 "osrfMethodException",
3436 "No active transaction -- required for UPDATE"
3442 if (osrfHashGet( meta, "readonly" ) && strncasecmp("true", osrfHashGet( meta, "readonly" ), 4)) {
3443 osrfAppSessionStatus(
3445 OSRF_STATUS_BADREQUEST,
3446 "osrfMethodException",
3448 "Cannot UPDATE readonly class"
3454 dbhandle = writehandle;
3456 char* trans_id = osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" );
3458 // Set the last_xact_id
3459 int index = oilsIDL_ntop( target->classname, "last_xact_id" );
3461 osrfLogDebug(OSRF_LOG_MARK, "Setting last_xact_id to %s on %s at position %d", trans_id, target->classname, index);
3462 jsonObjectSetIndex(target, index, jsonNewObject(trans_id));
3465 char* pkey = osrfHashGet(meta, "primarykey");
3466 osrfHash* fields = osrfHashGet(meta, "fields");
3468 char* id = oilsFMGetString( target, pkey );
3472 "%s updating %s object with %s = %s",
3474 osrfHashGet(meta, "fieldmapper"),
3479 growing_buffer* sql = buffer_init(128);
3480 buffer_fadd(sql,"UPDATE %s SET", osrfHashGet(meta, "tablename"));
3485 osrfStringArray* field_list = osrfHashKeys( fields );
3486 while ( (field_name = osrfStringArrayGetString(field_list, i++)) ) {
3488 osrfHash* field = osrfHashGet( fields, field_name );
3490 if(!( strcmp( field_name, pkey ) )) continue;
3491 if(!( strcmp( osrfHashGet(osrfHashGet(fields,field_name), "virtual"), "true" ) )) continue;
3493 const jsonObject* field_object = oilsFMGetObject( target, field_name );
3496 if (field_object && field_object->classname) {
3497 value = oilsFMGetString(
3499 (char*)oilsIDLFindPath("/%s/primarykey", field_object->classname)
3502 value = jsonObjectToSimpleString( field_object );
3505 osrfLogDebug( OSRF_LOG_MARK, "Updating %s object with %s = %s", osrfHashGet(meta, "fieldmapper"), field_name, value);
3507 if (!field_object || field_object->type == JSON_NULL) {
3508 if ( !(!( strcmp( osrfHashGet(meta, "classname"), "au" ) ) && !( strcmp( field_name, "passwd" ) )) ) { // arg at the special case!
3509 if (first) first = 0;
3510 else OSRF_BUFFER_ADD_CHAR(sql, ',');
3511 buffer_fadd( sql, " %s = NULL", field_name );
3514 } else if ( !strcmp(osrfHashGet(field, "primitive"), "number") ) {
3515 if (first) first = 0;
3516 else OSRF_BUFFER_ADD_CHAR(sql, ',');
3518 if ( !strncmp(osrfHashGet(field, "datatype"), "INT", (size_t)3) ) {
3519 buffer_fadd( sql, " %s = %ld", field_name, atol(value) );
3520 } else if ( !strcmp(osrfHashGet(field, "datatype"), "NUMERIC") ) {
3521 buffer_fadd( sql, " %s = %f", field_name, atof(value) );
3524 osrfLogDebug( OSRF_LOG_MARK, "%s is of type %s", field_name, osrfHashGet(field, "datatype"));
3527 if ( dbi_conn_quote_string(dbhandle, &value) ) {
3528 if (first) first = 0;
3529 else OSRF_BUFFER_ADD_CHAR(sql, ',');
3530 buffer_fadd( sql, " %s = %s", field_name, value );
3533 osrfLogError(OSRF_LOG_MARK, "%s: Error quoting string [%s]", MODULENAME, value);
3534 osrfAppSessionStatus(
3536 OSRF_STATUS_INTERNALSERVERERROR,
3537 "osrfMethodException",
3539 "Error quoting string -- please see the error log for more details"
3553 jsonObject* obj = jsonNewObject(id);
3555 if ( strcmp( osrfHashGet( osrfHashGet( osrfHashGet(meta, "fields"), pkey ), "primitive" ), "number" ) )
3556 dbi_conn_quote_string(dbhandle, &id);
3558 buffer_fadd( sql, " WHERE %s = %s;", pkey, id );
3560 char* query = buffer_release(sql);
3561 osrfLogDebug(OSRF_LOG_MARK, "%s: Update SQL [%s]", MODULENAME, query);
3563 dbi_result result = dbi_conn_query(dbhandle, query);
3567 jsonObjectFree(obj);
3568 obj = jsonNewObject(NULL);
3571 "%s ERROR updating %s object with %s = %s",
3573 osrfHashGet(meta, "fieldmapper"),
3584 static jsonObject* doDelete(osrfMethodContext* ctx, int* err ) {
3586 osrfHash* meta = osrfHashGet( (osrfHash*) ctx->method->userData, "class" );
3588 if (!osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" )) {
3589 osrfAppSessionStatus(
3591 OSRF_STATUS_BADREQUEST,
3592 "osrfMethodException",
3594 "No active transaction -- required for DELETE"
3600 if (osrfHashGet( meta, "readonly" ) && strncasecmp("true", osrfHashGet( meta, "readonly" ), 4)) {
3601 osrfAppSessionStatus(
3603 OSRF_STATUS_BADREQUEST,
3604 "osrfMethodException",
3606 "Cannot DELETE readonly class"
3612 dbhandle = writehandle;
3616 char* pkey = osrfHashGet(meta, "primarykey");
3624 if (jsonObjectGetIndex(ctx->params, _obj_pos)->classname) {
3625 if (!verifyObjectClass(ctx, jsonObjectGetIndex( ctx->params, _obj_pos ))) {
3630 id = oilsFMGetString( jsonObjectGetIndex(ctx->params, _obj_pos), pkey );
3633 if (!verifyObjectPCRUD( ctx, NULL )) {
3638 id = jsonObjectToSimpleString(jsonObjectGetIndex(ctx->params, _obj_pos));
3643 "%s deleting %s object with %s = %s",
3645 osrfHashGet(meta, "fieldmapper"),
3650 obj = jsonNewObject(id);
3652 if ( strcmp( osrfHashGet( osrfHashGet( osrfHashGet(meta, "fields"), pkey ), "primitive" ), "number" ) )
3653 dbi_conn_quote_string(writehandle, &id);
3655 dbi_result result = dbi_conn_queryf(writehandle, "DELETE FROM %s WHERE %s = %s;", osrfHashGet(meta, "tablename"), pkey, id);
3658 jsonObjectFree(obj);
3659 obj = jsonNewObject(NULL);
3662 "%s ERROR deleting %s object with %s = %s",
3664 osrfHashGet(meta, "fieldmapper"),
3677 static jsonObject* oilsMakeFieldmapperFromResult( dbi_result result, osrfHash* meta) {
3678 if(!(result && meta)) return jsonNULL;
3680 jsonObject* object = jsonNewObject(NULL);
3681 jsonObjectSetClass(object, osrfHashGet(meta, "classname"));
3683 osrfHash* fields = osrfHashGet(meta, "fields");
3685 osrfLogInternal(OSRF_LOG_MARK, "Setting object class to %s ", object->classname);
3689 char dt_string[256];
3693 int columnIndex = 1;
3695 unsigned short type;
3696 const char* columnName;
3698 /* cycle through the column list */
3699 while( (columnName = dbi_result_get_field_name(result, columnIndex++)) ) {
3701 osrfLogInternal(OSRF_LOG_MARK, "Looking for column named [%s]...", (char*)columnName);
3703 fmIndex = -1; // reset the position
3705 /* determine the field type and storage attributes */
3706 type = dbi_result_get_field_type(result, columnName);
3707 attr = dbi_result_get_field_attribs(result, columnName);
3709 /* fetch the fieldmapper index */
3710 if( (_f = osrfHashGet(fields, (char*)columnName)) ) {
3711 char* virt = (char*)osrfHashGet(_f, "virtual");
3712 char* pos = (char*)osrfHashGet(_f, "array_position");
3714 if ( !virt || !pos || !(strcmp( virt, "true" )) ) continue;
3716 fmIndex = atoi( pos );
3717 osrfLogInternal(OSRF_LOG_MARK, "... Found column at position [%s]...", pos);
3722 if (dbi_result_field_is_null(result, columnName)) {
3723 jsonObjectSetIndex( object, fmIndex, jsonNewObject(NULL) );
3728 case DBI_TYPE_INTEGER :
3730 if( attr & DBI_INTEGER_SIZE8 )
3731 jsonObjectSetIndex( object, fmIndex,
3732 jsonNewNumberObject(dbi_result_get_longlong(result, columnName)));
3734 jsonObjectSetIndex( object, fmIndex,
3735 jsonNewNumberObject(dbi_result_get_int(result, columnName)));
3739 case DBI_TYPE_DECIMAL :
3740 jsonObjectSetIndex( object, fmIndex,
3741 jsonNewNumberObject(dbi_result_get_double(result, columnName)));
3744 case DBI_TYPE_STRING :
3750 jsonNewObject( dbi_result_get_string(result, columnName) )
3755 case DBI_TYPE_DATETIME :
3757 memset(dt_string, '\0', sizeof(dt_string));
3758 memset(&gmdt, '\0', sizeof(gmdt));
3760 _tmp_dt = dbi_result_get_datetime(result, columnName);
3763 if (!(attr & DBI_DATETIME_DATE)) {
3764 gmtime_r( &_tmp_dt, &gmdt );
3765 strftime(dt_string, sizeof(dt_string), "%T", &gmdt);
3766 } else if (!(attr & DBI_DATETIME_TIME)) {
3767 localtime_r( &_tmp_dt, &gmdt );
3768 strftime(dt_string, sizeof(dt_string), "%F", &gmdt);
3770 localtime_r( &_tmp_dt, &gmdt );
3771 strftime(dt_string, sizeof(dt_string), "%FT%T%z", &gmdt);
3774 jsonObjectSetIndex( object, fmIndex, jsonNewObject(dt_string) );
3778 case DBI_TYPE_BINARY :
3779 osrfLogError( OSRF_LOG_MARK,
3780 "Can't do binary at column %s : index %d", columnName, columnIndex - 1);
3788 static jsonObject* oilsMakeJSONFromResult( dbi_result result ) {
3789 if(!result) return jsonNULL;
3791 jsonObject* object = jsonNewObject(NULL);
3794 char dt_string[256];
3798 int columnIndex = 1;
3800 unsigned short type;
3801 const char* columnName;
3803 /* cycle through the column list */
3804 while( (columnName = dbi_result_get_field_name(result, columnIndex++)) ) {
3806 osrfLogInternal(OSRF_LOG_MARK, "Looking for column named [%s]...", (char*)columnName);
3808 fmIndex = -1; // reset the position
3810 /* determine the field type and storage attributes */
3811 type = dbi_result_get_field_type(result, columnName);
3812 attr = dbi_result_get_field_attribs(result, columnName);
3814 if (dbi_result_field_is_null(result, columnName)) {
3815 jsonObjectSetKey( object, columnName, jsonNewObject(NULL) );
3820 case DBI_TYPE_INTEGER :
3822 if( attr & DBI_INTEGER_SIZE8 )
3823 jsonObjectSetKey( object, columnName, jsonNewNumberObject(dbi_result_get_longlong(result, columnName)) );
3825 jsonObjectSetKey( object, columnName, jsonNewNumberObject(dbi_result_get_int(result, columnName)) );
3828 case DBI_TYPE_DECIMAL :
3829 jsonObjectSetKey( object, columnName, jsonNewNumberObject(dbi_result_get_double(result, columnName)) );
3832 case DBI_TYPE_STRING :
3833 jsonObjectSetKey( object, columnName, jsonNewObject(dbi_result_get_string(result, columnName)) );
3836 case DBI_TYPE_DATETIME :
3838 memset(dt_string, '\0', sizeof(dt_string));
3839 memset(&gmdt, '\0', sizeof(gmdt));
3841 _tmp_dt = dbi_result_get_datetime(result, columnName);
3844 if (!(attr & DBI_DATETIME_DATE)) {
3845 gmtime_r( &_tmp_dt, &gmdt );
3846 strftime(dt_string, sizeof(dt_string), "%T", &gmdt);
3847 } else if (!(attr & DBI_DATETIME_TIME)) {
3848 localtime_r( &_tmp_dt, &gmdt );
3849 strftime(dt_string, sizeof(dt_string), "%F", &gmdt);
3851 localtime_r( &_tmp_dt, &gmdt );
3852 strftime(dt_string, sizeof(dt_string), "%FT%T%z", &gmdt);
3855 jsonObjectSetKey( object, columnName, jsonNewObject(dt_string) );
3858 case DBI_TYPE_BINARY :
3859 osrfLogError( OSRF_LOG_MARK,
3860 "Can't do binary at column %s : index %d", columnName, columnIndex - 1);