fixing NOT IN queries
[Evergreen.git] / Open-ILS / src / c-apps / oils_cstore.c
1 #include "opensrf/osrf_application.h"
2 #include "opensrf/osrf_settings.h"
3 #include "opensrf/utils.h"
4 #include "objson/object.h"
5 #include "opensrf/log.h"
6 #include "oils_utils.h"
7 #include "oils_constants.h"
8 #include "oils_event.h"
9 #include "oils_idl.h"
10 #include <dbi/dbi.h>
11
12 #include <time.h>
13 #include <stdlib.h>
14 #include <string.h>
15
16 #define OILS_AUTH_CACHE_PRFX "oils_cstore_"
17 #define MODULENAME "open-ils.cstore"
18 #define PERSIST_NS "http://open-ils.org/spec/opensrf/IDL/persistance/v1"
19 #define OBJECT_NS "http://open-ils.org/spec/opensrf/IDL/objects/v1"
20 #define BASE_NS "http://opensrf.org/spec/IDL/base/v1"
21
22 int osrfAppChildInit();
23 int osrfAppInitialize();
24
25 int verifyObjectClass ( osrfMethodContext*, jsonObject* );
26
27 int beginTransaction ( osrfMethodContext* );
28 int commitTransaction ( osrfMethodContext* );
29 int rollbackTransaction ( osrfMethodContext* );
30
31 int setSavepoint ( osrfMethodContext* );
32 int releaseSavepoint ( osrfMethodContext* );
33 int rollbackSavepoint ( osrfMethodContext* );
34
35 int dispatchCRUDMethod ( osrfMethodContext* );
36 jsonObject* doCreate ( osrfMethodContext*, int* );
37 jsonObject* doRetrieve ( osrfMethodContext*, int* );
38 jsonObject* doUpdate ( osrfMethodContext*, int* );
39 jsonObject* doDelete ( osrfMethodContext*, int* );
40 jsonObject* doSearch ( osrfMethodContext*, osrfHash*, jsonObject*, int* );
41 jsonObject* oilsMakeJSONFromResult( dbi_result, osrfHash* );
42
43 char* searchWriteSimplePredicate ( osrfHash*, const char*, const char*, const char* );
44 char* searchSimplePredicate ( const char*, osrfHash*, jsonObject* );
45 char* searchFunctionPredicate ( osrfHash*, jsonObjectNode* );
46 char* searchFieldTransform (osrfHash*, jsonObject*);
47 char* searchFieldTransformPredicate ( osrfHash*, jsonObjectNode* );
48 char* searchBETWEENPredicate ( osrfHash*, jsonObject* );
49 char* searchINPredicate ( osrfHash*, jsonObject*, const char* );
50 char* searchPredicate ( osrfHash*, jsonObject* );
51 char* buildSELECT ( jsonObject*, jsonObject*, osrfHash*, osrfMethodContext* );
52
53 void userDataFree( void* );
54 void sessionDataFree( char*, void* );
55
56 dbi_conn writehandle; /* our MASTER db connection */
57 dbi_conn dbhandle; /* our CURRENT db connection */
58 osrfHash readHandles;
59 jsonObject* jsonNULL = NULL; // 
60
61
62 /* parse and store the IDL here */
63 osrfHash* idl;
64
65 int osrfAppInitialize() {
66
67         // first we register all the transaction and savepoint methods
68         osrfAppRegisterMethod( MODULENAME, "open-ils.cstore.transaction.begin", "beginTransaction", "", 0, 0 );
69         osrfAppRegisterMethod( MODULENAME, "open-ils.cstore.transaction.commit", "commitTransaction", "", 0, 0 );
70         osrfAppRegisterMethod( MODULENAME, "open-ils.cstore.transaction.rollback", "rollbackTransaction", "", 0, 0 );
71
72         osrfAppRegisterMethod( MODULENAME, "open-ils.cstore.savepoint.set", "setSavepoint", "", 1, 0 );
73         osrfAppRegisterMethod( MODULENAME, "open-ils.cstore.savepoint.release", "releaseSavepoint", "", 1, 0 );
74         osrfAppRegisterMethod( MODULENAME, "open-ils.cstore.savepoint.rollback", "rollbackSavepoint", "", 1, 0 );
75
76
77         osrfLogInfo(OSRF_LOG_MARK, "Initializing the CStore Server...");
78         osrfLogInfo(OSRF_LOG_MARK, "Finding XML file...");
79
80         char * idl_filename = osrf_settings_host_value("/apps/%s/app_settings/IDL", MODULENAME);
81         osrfLogInfo(OSRF_LOG_MARK, "Found file:");
82         osrfLogInfo(OSRF_LOG_MARK, idl_filename);
83
84         idl = oilsIDLInit( idl_filename );
85
86         if (!idl) {
87                 osrfLogError(OSRF_LOG_MARK, "Problem loading the IDL.  Seacrest out!");
88                 exit(1);
89         }
90
91         osrfStringArray* global_methods = osrfNewStringArray(6);
92
93         osrfStringArrayAdd( global_methods, "create" );
94         osrfStringArrayAdd( global_methods, "retrieve" );
95         osrfStringArrayAdd( global_methods, "update" );
96         osrfStringArrayAdd( global_methods, "delete" );
97         osrfStringArrayAdd( global_methods, "search" );
98         osrfStringArrayAdd( global_methods, "id_list" );
99
100         int c_index = 0; 
101         char* classname;
102         osrfStringArray* classes = osrfHashKeys( idl );
103         osrfLogDebug(OSRF_LOG_MARK, "%d classes loaded", classes->size );
104         osrfLogDebug(OSRF_LOG_MARK, "At least %d methods will be generated", classes->size * global_methods->size);
105         
106         while ( (classname = osrfStringArrayGetString(classes, c_index++)) ) {
107                 osrfLogInfo(OSRF_LOG_MARK, "Generating class methods for %s", classname);
108                 
109                 osrfHash* idlClass = osrfHashGet(idl, classname);
110
111                 char* virt = osrfHashGet(idlClass, "virtual");
112                 if (virt && !strcmp( virt, "true")) {
113                         osrfLogDebug(OSRF_LOG_MARK, "Class %s is virtual, skipping", classname );
114                         continue;
115                 }
116
117                 osrfLogDebug(OSRF_LOG_MARK, "HERE");
118                 
119                 int i = 0; 
120                 char* method_type;
121                 char* st_tmp;
122                 char* _fm;
123                 char* part;
124                 osrfHash* method_meta;
125                 while ( (method_type = osrfStringArrayGetString(global_methods, i++)) ) {
126                         osrfLogDebug(OSRF_LOG_MARK, "Using files to build %s class methods for %s", method_type, classname);
127
128                         if (!osrfHashGet(idlClass, "fieldmapper")) continue;
129
130                         method_meta = osrfNewHash();
131                         osrfHashSet(method_meta, idlClass, "class");
132
133                         _fm = strdup( (char*)osrfHashGet(idlClass, "fieldmapper") );
134                         part = strtok_r(_fm, ":", &st_tmp);
135
136                         growing_buffer* method_name =  buffer_init(64);
137                         buffer_fadd(method_name, "%s.direct.%s", MODULENAME, part);
138
139                         while ((part = strtok_r(NULL, ":", &st_tmp))) {
140                                 buffer_fadd(method_name, ".%s", part);
141                         }
142                         buffer_fadd(method_name, ".%s", method_type);
143
144
145                         char* method = buffer_data(method_name);
146                         buffer_free(method_name);
147                         free(_fm);
148
149                         osrfHashSet( method_meta, method, "methodname" );
150                         osrfHashSet( method_meta, method_type, "methodtype" );
151
152                         int flags = 0;
153                         if (!(strcmp( method_type, "search" )) || !(strcmp( method_type, "id_list" ))) {
154                                 flags = flags | OSRF_METHOD_STREAMING;
155                         }
156
157                         osrfAppRegisterExtendedMethod(
158                                 MODULENAME,
159                                 method,
160                                 "dispatchCRUDMethod",
161                                 "",
162                                 1,
163                                 flags,
164                                 (void*)method_meta
165                         );
166                 }
167         }
168
169         return 0;
170 }
171
172 /**
173  * Connects to the database 
174  */
175 int osrfAppChildInit() {
176
177         osrfLogDebug(OSRF_LOG_MARK, "Attempting to initialize libdbi...");
178         dbi_initialize(NULL);
179         osrfLogDebug(OSRF_LOG_MARK, "... libdbi initialized.");
180
181         char* driver    = osrf_settings_host_value("/apps/%s/app_settings/driver", MODULENAME);
182         char* user      = osrf_settings_host_value("/apps/%s/app_settings/database/user", MODULENAME);
183         char* host      = osrf_settings_host_value("/apps/%s/app_settings/database/host", MODULENAME);
184         char* port      = osrf_settings_host_value("/apps/%s/app_settings/database/port", MODULENAME);
185         char* db        = osrf_settings_host_value("/apps/%s/app_settings/database/db", MODULENAME);
186         char* pw        = osrf_settings_host_value("/apps/%s/app_settings/database/pw", MODULENAME);
187
188         osrfLogDebug(OSRF_LOG_MARK, "Attempting to load the database driver [%s]...", driver);
189         writehandle = dbi_conn_new(driver);
190
191         if(!writehandle) {
192                 osrfLogError(OSRF_LOG_MARK, "Error loading database driver [%s]", driver);
193                 return -1;
194         }
195         osrfLogDebug(OSRF_LOG_MARK, "Database driver [%s] seems OK", driver);
196
197         osrfLogInfo(OSRF_LOG_MARK, "%s connecting to database.  host=%s, "
198                 "port=%s, user=%s, pw=%s, db=%s", MODULENAME, host, port, user, pw, db );
199
200         if(host) dbi_conn_set_option(writehandle, "host", host );
201         if(port) dbi_conn_set_option_numeric( writehandle, "port", atoi(port) );
202         if(user) dbi_conn_set_option(writehandle, "username", user);
203         if(pw) dbi_conn_set_option(writehandle, "password", pw );
204         if(db) dbi_conn_set_option(writehandle, "dbname", db );
205
206         free(user);
207         free(host);
208         free(port);
209         free(db);
210         free(pw);
211
212         const char* err;
213         if (dbi_conn_connect(writehandle) < 0) {
214                 dbi_conn_error(writehandle, &err);
215                 osrfLogError( OSRF_LOG_MARK, "Error connecting to database: %s", err);
216                 return -1;
217         }
218
219         osrfLogInfo(OSRF_LOG_MARK, "%s successfully connected to the database", MODULENAME);
220
221         int attr;
222         unsigned short type;
223         int i = 0; 
224         char* classname;
225         osrfStringArray* classes = osrfHashKeys( idl );
226         
227         while ( (classname = osrfStringArrayGetString(classes, i++)) ) {
228                 osrfHash* class = osrfHashGet( idl, classname );
229                 osrfHash* fields = osrfHashGet( class, "fields" );
230
231                 char* virt = osrfHashGet(class, "virtual");
232                 if (virt && !strcmp( virt, "true")) {
233                         osrfLogDebug(OSRF_LOG_MARK, "Class %s is virtual, skipping", classname );
234                         continue;
235                 }
236
237         
238                 growing_buffer* sql_buf = buffer_init(32);
239                 buffer_fadd( sql_buf, "SELECT * FROM %s WHERE 1=0;", osrfHashGet(class, "tablename") );
240
241                 char* sql = buffer_data(sql_buf);
242                 buffer_free(sql_buf);
243                 osrfLogDebug(OSRF_LOG_MARK, "%s Investigatory SQL = %s", MODULENAME, sql);
244
245                 dbi_result result = dbi_conn_query(writehandle, sql);
246                 free(sql);
247
248                 if (result) {
249
250                         int columnIndex = 1;
251                         const char* columnName;
252                         osrfHash* _f;
253                         while( (columnName = dbi_result_get_field_name(result, columnIndex++)) ) {
254
255                                 osrfLogInternal(OSRF_LOG_MARK, "Looking for column named [%s]...", (char*)columnName);
256
257                                 /* fetch the fieldmapper index */
258                                 if( (_f = osrfHashGet(fields, (char*)columnName)) ) {
259
260                                         osrfLogDebug(OSRF_LOG_MARK, "Found [%s] in IDL hash...", (char*)columnName);
261
262                                         /* determine the field type and storage attributes */
263                                         type = dbi_result_get_field_type(result, columnName);
264                                         attr = dbi_result_get_field_attribs(result, columnName);
265
266                                         switch( type ) {
267
268                                                 case DBI_TYPE_INTEGER :
269
270                                                         if ( !osrfHashGet(_f, "primitive") )
271                                                                 osrfHashSet(_f,"number", "primitive");
272
273                                                         if( attr & DBI_INTEGER_SIZE8 ) 
274                                                                 osrfHashSet(_f,"INT8", "datatype");
275                                                         else 
276                                                                 osrfHashSet(_f,"INT", "datatype");
277                                                         break;
278
279                                                 case DBI_TYPE_DECIMAL :
280                                                         if ( !osrfHashGet(_f, "primitive") )
281                                                                 osrfHashSet(_f,"number", "primitive");
282
283                                                         osrfHashSet(_f,"NUMERIC", "datatype");
284                                                         break;
285
286                                                 case DBI_TYPE_STRING :
287                                                         if ( !osrfHashGet(_f, "primitive") )
288                                                                 osrfHashSet(_f,"string", "primitive");
289                                                         osrfHashSet(_f,"TEXT", "datatype");
290                                                         break;
291
292                                                 case DBI_TYPE_DATETIME :
293                                                         if ( !osrfHashGet(_f, "primitive") )
294                                                                 osrfHashSet(_f,"string", "primitive");
295
296                                                         osrfHashSet(_f,"TIMESTAMP", "datatype");
297                                                         break;
298
299                                                 case DBI_TYPE_BINARY :
300                                                         if ( !osrfHashGet(_f, "primitive") )
301                                                                 osrfHashSet(_f,"string", "primitive");
302
303                                                         osrfHashSet(_f,"BYTEA", "datatype");
304                                         }
305
306                                         osrfLogDebug(
307                                                 OSRF_LOG_MARK,
308                                                 "Setting [%s] to primitive [%s] and datatype [%s]...",
309                                                 (char*)columnName,
310                                                 osrfHashGet(_f, "primitive"),
311                                                 osrfHashGet(_f, "datatype")
312                                         );
313                                 }
314                         }
315                         dbi_result_free(result);
316                 } else {
317                         osrfLogDebug(OSRF_LOG_MARK, "No data found for class [%s]...", (char*)classname);
318                 }
319         }
320
321         osrfStringArrayFree(classes);
322
323         return 0;
324 }
325
326 void userDataFree( void* blob ) {
327         osrfHashFree( (osrfHash*)blob );
328         return;
329 }
330
331 void sessionDataFree( char* key, void* item ) {
332         if (!(strcmp(key,"xact_id"))) {
333                 if (writehandle)
334                         dbi_conn_query(writehandle, "ROLLBACK;");
335                 free(item);
336         }
337
338         return;
339 }
340
341 int beginTransaction ( osrfMethodContext* ctx ) {
342         OSRF_METHOD_VERIFY_CONTEXT(ctx);
343
344         dbi_result result = dbi_conn_query(writehandle, "START TRANSACTION;");
345         if (!result) {
346                 osrfLogError(OSRF_LOG_MARK, "%s: Error starting transaction", MODULENAME );
347                 osrfAppSessionStatus( ctx->session, OSRF_STATUS_INTERNALSERVERERROR, "osrfMethodException", ctx->request, "Error starting transaction" );
348                 return -1;
349         } else {
350                 jsonObject* ret = jsonNewObject(ctx->session->session_id);
351                 osrfAppRespondComplete( ctx, ret );
352                 jsonObjectFree(ret);
353                 
354                 if (!ctx->session->userData) {
355                         ctx->session->userData = osrfNewHash();
356                         ((osrfHash*)ctx->session->userData)->freeItem = &sessionDataFree;
357                 }
358
359                 osrfHashSet( (osrfHash*)ctx->session->userData, strdup( ctx->session->session_id ), "xact_id" );
360                 ctx->session->userDataFree = &userDataFree;
361                 
362         }
363         return 0;
364 }
365
366 int setSavepoint ( osrfMethodContext* ctx ) {
367         OSRF_METHOD_VERIFY_CONTEXT(ctx);
368
369         char* spName = jsonObjectToSimpleString(jsonObjectGetIndex(ctx->params, 0));
370
371         if (!osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" )) {
372                 osrfAppSessionStatus(
373                         ctx->session,
374                         OSRF_STATUS_INTERNALSERVERERROR,
375                         "osrfMethodException",
376                         ctx->request,
377                         "No active transaction -- required for savepoints"
378                 );
379                 return -1;
380         }
381
382         dbi_result result = dbi_conn_queryf(writehandle, "SAVEPOINT \"%s\";", spName);
383         if (!result) {
384                 osrfLogError(
385                         OSRF_LOG_MARK,
386                         "%s: Error creating savepoint %s in transaction %s",
387                         MODULENAME,
388                         spName,
389                         osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" )
390                 );
391                 osrfAppSessionStatus( ctx->session, OSRF_STATUS_INTERNALSERVERERROR, "osrfMethodException", ctx->request, "Error creating savepoint" );
392                 return -1;
393         } else {
394                 jsonObject* ret = jsonNewObject(spName);
395                 osrfAppRespondComplete( ctx, ret );
396                 jsonObjectFree(ret);
397         }
398         return 0;
399 }
400
401 int releaseSavepoint ( osrfMethodContext* ctx ) {
402         OSRF_METHOD_VERIFY_CONTEXT(ctx);
403
404         char* spName = jsonObjectToSimpleString(jsonObjectGetIndex(ctx->params, 0));
405
406         if (!osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" )) {
407                 osrfAppSessionStatus(
408                         ctx->session,
409                         OSRF_STATUS_INTERNALSERVERERROR,
410                         "osrfMethodException",
411                         ctx->request,
412                         "No active transaction -- required for savepoints"
413                 );
414                 return -1;
415         }
416
417         dbi_result result = dbi_conn_queryf(writehandle, "RELEASE SAVEPOINT \"%s\";", spName);
418         if (!result) {
419                 osrfLogError(
420                         OSRF_LOG_MARK,
421                         "%s: Error releasing savepoint %s in transaction %s",
422                         MODULENAME,
423                         spName,
424                         osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" )
425                 );
426                 osrfAppSessionStatus( ctx->session, OSRF_STATUS_INTERNALSERVERERROR, "osrfMethodException", ctx->request, "Error releasing savepoint" );
427                 return -1;
428         } else {
429                 jsonObject* ret = jsonNewObject(spName);
430                 osrfAppRespondComplete( ctx, ret );
431                 jsonObjectFree(ret);
432         }
433         return 0;
434 }
435
436 int rollbackSavepoint ( osrfMethodContext* ctx ) {
437         OSRF_METHOD_VERIFY_CONTEXT(ctx);
438
439         char* spName = jsonObjectToSimpleString(jsonObjectGetIndex(ctx->params, 0));
440
441         if (!osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" )) {
442                 osrfAppSessionStatus(
443                         ctx->session,
444                         OSRF_STATUS_INTERNALSERVERERROR,
445                         "osrfMethodException",
446                         ctx->request,
447                         "No active transaction -- required for savepoints"
448                 );
449                 return -1;
450         }
451
452         dbi_result result = dbi_conn_queryf(writehandle, "ROLLBACK TO SAVEPOINT \"%s\";", spName);
453         if (!result) {
454                 osrfLogError(
455                         OSRF_LOG_MARK,
456                         "%s: Error rolling back savepoint %s in transaction %s",
457                         MODULENAME,
458                         spName,
459                         osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" )
460                 );
461                 osrfAppSessionStatus( ctx->session, OSRF_STATUS_INTERNALSERVERERROR, "osrfMethodException", ctx->request, "Error rolling back savepoint" );
462                 return -1;
463         } else {
464                 jsonObject* ret = jsonNewObject(spName);
465                 osrfAppRespondComplete( ctx, ret );
466                 jsonObjectFree(ret);
467         }
468         return 0;
469 }
470
471 int commitTransaction ( osrfMethodContext* ctx ) {
472         OSRF_METHOD_VERIFY_CONTEXT(ctx);
473
474         if (!osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" )) {
475                 osrfAppSessionStatus( ctx->session, OSRF_STATUS_INTERNALSERVERERROR, "osrfMethodException", ctx->request, "No active transaction to commit" );
476                 return -1;
477         }
478
479         dbi_result result = dbi_conn_query(writehandle, "COMMIT;");
480         if (!result) {
481                 osrfLogError(OSRF_LOG_MARK, "%s: Error committing transaction", MODULENAME );
482                 osrfAppSessionStatus( ctx->session, OSRF_STATUS_INTERNALSERVERERROR, "osrfMethodException", ctx->request, "Error committing transaction" );
483                 return -1;
484         } else {
485                 osrfHashRemove(ctx->session->userData, "xact_id");
486                 jsonObject* ret = jsonNewObject(ctx->session->session_id);
487                 osrfAppRespondComplete( ctx, ret );
488                 jsonObjectFree(ret);
489         }
490         return 0;
491 }
492
493 int rollbackTransaction ( osrfMethodContext* ctx ) {
494         OSRF_METHOD_VERIFY_CONTEXT(ctx);
495
496         if (!osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" )) {
497                 osrfAppSessionStatus( ctx->session, OSRF_STATUS_INTERNALSERVERERROR, "osrfMethodException", ctx->request, "No active transaction to roll back" );
498                 return -1;
499         }
500
501         dbi_result result = dbi_conn_query(writehandle, "ROLLBACK;");
502         if (!result) {
503                 osrfLogError(OSRF_LOG_MARK, "%s: Error rolling back transaction", MODULENAME );
504                 osrfAppSessionStatus( ctx->session, OSRF_STATUS_INTERNALSERVERERROR, "osrfMethodException", ctx->request, "Error rolling back transaction" );
505                 return -1;
506         } else {
507                 osrfHashRemove(ctx->session->userData, "xact_id");
508                 jsonObject* ret = jsonNewObject(ctx->session->session_id);
509                 osrfAppRespondComplete( ctx, ret );
510                 jsonObjectFree(ret);
511         }
512         return 0;
513 }
514
515 int dispatchCRUDMethod ( osrfMethodContext* ctx ) {
516         OSRF_METHOD_VERIFY_CONTEXT(ctx);
517
518         osrfHash* meta = (osrfHash*) ctx->method->userData;
519         osrfHash* class_obj = osrfHashGet( meta, "class" );
520         
521         int err = 0;
522
523         jsonObject * obj = NULL;
524         if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "create"))
525                 obj = doCreate(ctx, &err);
526
527         if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "retrieve"))
528                 obj = doRetrieve(ctx, &err);
529
530         if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "update"))
531                 obj = doUpdate(ctx, &err);
532
533         if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "delete"))
534                 obj = doDelete(ctx, &err);
535
536         if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "search")) {
537
538                 obj = doSearch(ctx, class_obj, ctx->params, &err);
539                 if(err) return err;
540
541                 jsonObjectNode* cur;
542                 jsonObjectIterator* itr = jsonNewObjectIterator( obj );
543                 while ((cur = jsonObjectIteratorNext( itr ))) {
544                         osrfAppRespond( ctx, jsonObjectClone(cur->item) );
545                 }
546                 jsonObjectIteratorFree(itr);
547                 osrfAppRespondComplete( ctx, NULL );
548
549         } else if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "id_list")) {
550
551                 jsonObject* _p = jsonObjectClone( ctx->params );
552                 if (jsonObjectGetIndex( _p, 1 )) {
553                         jsonObjectRemoveKey( jsonObjectGetIndex( _p, 1 ), "flesh" );
554                         jsonObjectRemoveKey( jsonObjectGetIndex( _p, 1 ), "flesh_columns" );
555                 } else {
556                         jsonObjectSetIndex( _p, 1, jsonParseString("{}") );
557                 }
558
559                 growing_buffer* sel_list = buffer_init(16);
560                 buffer_fadd(sel_list, "{ \"%s\":[\"%s\"] }", osrfHashGet( class_obj, "classname" ), osrfHashGet( class_obj, "primarykey" ));
561                 char* _s = buffer_data(sel_list);
562                 buffer_free(sel_list);
563
564                 jsonObjectSetKey( jsonObjectGetIndex( _p, 1 ), "select", jsonParseString(_s) );
565                 osrfLogDebug(OSRF_LOG_MARK, "%s: Select qualifer set to [%s]", MODULENAME, _s);
566                 free(_s);
567
568                 obj = doSearch(ctx, class_obj, _p, &err);
569                 if(err) return err;
570
571                 jsonObjectNode* cur;
572                 jsonObjectIterator* itr = jsonNewObjectIterator( obj );
573                 while ((cur = jsonObjectIteratorNext( itr ))) {
574                         osrfAppRespond(
575                                 ctx,
576                                 jsonObjectClone(
577                                         jsonObjectGetIndex(
578                                                 cur->item,
579                                                 atoi(
580                                                         osrfHashGet(
581                                                                 osrfHashGet(
582                                                                         osrfHashGet( class_obj, "fields" ),
583                                                                         osrfHashGet( class_obj, "primarykey")
584                                                                 ),
585                                                                 "array_position"
586                                                         )
587                                                 )
588                                         )
589                                 )
590                         );
591                 }
592                 jsonObjectIteratorFree(itr);
593                 osrfAppRespondComplete( ctx, NULL );
594                 
595         } else {
596                 osrfAppRespondComplete( ctx, obj );
597         }
598
599         jsonObjectFree(obj);
600
601         return err;
602 }
603
604 int verifyObjectClass ( osrfMethodContext* ctx, jsonObject* param ) {
605         
606         osrfHash* meta = (osrfHash*) ctx->method->userData;
607         osrfHash* class = osrfHashGet( meta, "class" );
608         
609         if ((strcmp( osrfHashGet(class, "classname"), param->classname ))) {
610
611                 growing_buffer* msg = buffer_init(128);
612                 buffer_fadd(
613                         msg,
614                         "%s: %s method for type %s was passed a %s",
615                         MODULENAME,
616                         osrfHashGet(meta, "methodtype"),
617                         osrfHashGet(class, "classname"),
618                         param->classname
619                 );
620
621                 char* m = buffer_data(msg);
622                 osrfAppSessionStatus( ctx->session, OSRF_STATUS_BADREQUEST, "osrfMethodException", ctx->request, m );
623
624                 buffer_free(msg);
625                 free(m);
626
627                 return 0;
628         }
629         return 1;
630 }
631
632 jsonObject* doCreate(osrfMethodContext* ctx, int* err ) {
633
634         osrfHash* meta = osrfHashGet( (osrfHash*) ctx->method->userData, "class" );
635         jsonObject* target = jsonObjectGetIndex( ctx->params, 0 );
636         jsonObject* options = jsonObjectGetIndex( ctx->params, 1 );
637
638         if (!verifyObjectClass(ctx, target)) {
639                 *err = -1;
640                 return jsonNULL;
641         }
642
643         osrfLogDebug( OSRF_LOG_MARK, "Object seems to be of the correct type" );
644
645         if (!ctx->session || !ctx->session->userData || !osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" )) {
646                 osrfLogError( OSRF_LOG_MARK, "No active transaction -- required for CREATE" );
647
648                 osrfAppSessionStatus(
649                         ctx->session,
650                         OSRF_STATUS_BADREQUEST,
651                         "osrfMethodException",
652                         ctx->request,
653                         "No active transaction -- required for CREATE"
654                 );
655                 *err = -1;
656                 return jsonNULL;
657         }
658
659         char* trans_id = osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" );
660
661         // Set the last_xact_id
662         osrfHash* last_xact_id;
663         if ((last_xact_id = oilsIDLFindPath("/%s/fields/last_xact_id", target->classname))) {
664                 int index = atoi( osrfHashGet(last_xact_id, "array_position") );
665                 osrfLogDebug(OSRF_LOG_MARK, "Setting last_xact_id to %s on %s at position %d", trans_id, target->classname, index);
666                 jsonObjectSetIndex(target, index, jsonNewObject(trans_id));
667         }       
668
669         osrfLogDebug( OSRF_LOG_MARK, "There is a transaction running..." );
670
671         dbhandle = writehandle;
672
673         osrfHash* fields = osrfHashGet(meta, "fields");
674         char* pkey = osrfHashGet(meta, "primarykey");
675         char* seq = osrfHashGet(meta, "sequence");
676
677         growing_buffer* table_buf = buffer_init(128);
678         growing_buffer* col_buf = buffer_init(128);
679         growing_buffer* val_buf = buffer_init(128);
680
681         buffer_fadd(table_buf,"INSERT INTO %s", osrfHashGet(meta, "tablename"));
682         buffer_add(col_buf,"(");
683         buffer_add(val_buf,"VALUES (");
684
685
686         int i = 0;
687         int first = 1;
688         char* field_name;
689         osrfStringArray* field_list = osrfHashKeys( fields );
690         while ( (field_name = osrfStringArrayGetString(field_list, i++)) ) {
691
692                 osrfHash* field = osrfHashGet( fields, field_name );
693
694                 if(!( strcmp( osrfHashGet(osrfHashGet(fields,field_name), "virtual"), "true" ) )) continue;
695
696                 int pos = atoi(osrfHashGet(field, "array_position"));
697                 char* value = jsonObjectToSimpleString( jsonObjectGetIndex( target, pos ) );
698
699                 if (first) {
700                         first = 0;
701                 } else {
702                         buffer_add(col_buf, ",");
703                         buffer_add(val_buf, ",");
704                 }
705
706                 buffer_add(col_buf, field_name);
707
708                 if (!jsonObjectGetIndex(target, pos) || jsonObjectGetIndex(target, pos)->type == JSON_NULL) {
709                         buffer_add( val_buf, "DEFAULT" );
710                         
711                 } else if ( !strcmp(osrfHashGet(field, "primitive"), "number") ) {
712                         if ( !strcmp(osrfHashGet(field, "datatype"), "INT8") ) {
713                                 buffer_fadd( val_buf, "%lld", atol(value) );
714                                 
715                         } else if ( !strcmp(osrfHashGet(field, "datatype"), "INT") ) {
716                                 buffer_fadd( val_buf, "%ld", atoll(value) );
717                                 
718                         } else if ( !strcmp(osrfHashGet(field, "datatype"), "NUMERIC") ) {
719                                 buffer_fadd( val_buf, "%f", atof(value) );
720                         }
721                 } else {
722                         if ( dbi_conn_quote_string(writehandle, &value) ) {
723                                 buffer_fadd( val_buf, "%s", value );
724
725                         } else {
726                                 osrfLogError(OSRF_LOG_MARK, "%s: Error quoting string [%s]", MODULENAME, value);
727                                 osrfAppSessionStatus(
728                                         ctx->session,
729                                         OSRF_STATUS_INTERNALSERVERERROR,
730                                         "osrfMethodException",
731                                         ctx->request,
732                                         "Error quoting string -- please see the error log for more details"
733                                 );
734                                 free(value);
735                                 buffer_free(table_buf);
736                                 buffer_free(col_buf);
737                                 buffer_free(val_buf);
738                                 *err = -1;
739                                 return jsonNULL;
740                         }
741                 }
742
743                 free(value);
744                 
745         }
746
747
748         buffer_add(col_buf,")");
749         buffer_add(val_buf,")");
750
751         growing_buffer* sql = buffer_init(128);
752         buffer_fadd(
753                 sql,
754                 "%s %s %s;",
755                 buffer_data(table_buf),
756                 buffer_data(col_buf),
757                 buffer_data(val_buf)
758         );
759         buffer_free(table_buf);
760         buffer_free(col_buf);
761         buffer_free(val_buf);
762
763         char* query = buffer_data(sql);
764         buffer_free(sql);
765
766         osrfLogDebug(OSRF_LOG_MARK, "%s: Insert SQL [%s]", MODULENAME, query);
767
768         
769         dbi_result result = dbi_conn_query(writehandle, query);
770
771         jsonObject* obj = NULL;
772
773         if (!result) {
774                 obj = jsonNewObject(NULL);
775                 osrfLogError(
776                         OSRF_LOG_MARK,
777                         "%s ERROR inserting %s object using query [%s]",
778                         MODULENAME,
779                         osrfHashGet(meta, "fieldmapper"),
780                         query
781                 );
782                 osrfAppSessionStatus(
783                         ctx->session,
784                         OSRF_STATUS_INTERNALSERVERERROR,
785                         "osrfMethodException",
786                         ctx->request,
787                         "INSERT error -- please see the error log for more details"
788                 );
789                 *err = -1;
790         } else {
791
792                 int pos = atoi(osrfHashGet( osrfHashGet(fields, pkey), "array_position" ));
793                 char* id = jsonObjectToSimpleString(jsonObjectGetIndex(target, pos));
794                 if (!id) {
795                         unsigned long long new_id = dbi_conn_sequence_last(writehandle, seq);
796                         growing_buffer* _id = buffer_init(10);
797                         buffer_fadd(_id, "%lld", new_id);
798                         id = buffer_data(_id);
799                         buffer_free(_id);
800                 }
801
802                 if (    !options
803                         || !jsonObjectGetKey( options, "quiet")
804                         || strcmp( jsonObjectToSimpleString(jsonObjectGetKey( options, "quiet")), "true" )
805                 ) {
806
807                         jsonObject* fake_params = jsonParseString("[]");
808                         jsonObjectPush(fake_params, jsonParseString("{}"));
809
810                         jsonObjectSetKey(
811                                 jsonObjectGetIndex(fake_params, 0),
812                                 osrfHashGet(meta, "primarykey"),
813                                 jsonNewObject(id)
814                         );
815
816                         jsonObject* list = doSearch( ctx,meta, fake_params, err);
817
818                         if(*err) {
819                                 jsonObjectFree( fake_params );
820                                 obj = jsonNULL;
821                         } else {
822                                 obj = jsonObjectClone( jsonObjectGetIndex(list, 0) );
823                         }
824
825                         jsonObjectFree( list );
826                         jsonObjectFree( fake_params );
827
828                 } else {
829                         obj = jsonNewObject(id);
830                 }
831
832         }
833
834         free(query);
835
836         return obj;
837
838 }
839
840
841 jsonObject* doRetrieve(osrfMethodContext* ctx, int* err ) {
842
843         osrfHash* meta = osrfHashGet( (osrfHash*) ctx->method->userData, "class" );
844
845         jsonObject* obj;
846
847         char* id = jsonObjectToSimpleString(jsonObjectGetIndex(ctx->params, 0));
848         jsonObject* order_hash = jsonObjectGetIndex(ctx->params, 1);
849
850         osrfLogDebug(
851                 OSRF_LOG_MARK,
852                 "%s retrieving %s object with id %s",
853                 MODULENAME,
854                 osrfHashGet(meta, "fieldmapper"),
855                 id
856         );
857
858         jsonObject* fake_params = jsonParseString("[]");
859         jsonObjectPush(fake_params, jsonParseString("{}"));
860
861         jsonObjectSetKey(
862                 jsonObjectGetIndex(fake_params, 0),
863                 osrfHashGet(meta, "primarykey"),
864                 jsonParseString(id)
865         );
866
867         if (order_hash) jsonObjectPush(fake_params, jsonObjectClone(order_hash) );
868
869         jsonObject* list = doSearch( ctx,meta, fake_params, err);
870
871         if(*err) {
872                 jsonObjectFree( fake_params );
873                 return jsonNULL;
874         }
875
876         obj = jsonObjectClone( jsonObjectGetIndex(list, 0) );
877
878         jsonObjectFree( list );
879         jsonObjectFree( fake_params );
880
881         return obj;
882 }
883
884 char* jsonNumberToDBString ( osrfHash* field, jsonObject* value ) {
885         growing_buffer* val_buf = buffer_init(32);
886
887         if ( !strncmp(osrfHashGet(field, "datatype"), "INT", 3) ) {
888                 if (value->type == JSON_NUMBER) buffer_fadd( val_buf, "%ld", (long)jsonObjectGetNumber(value) );
889                 else buffer_fadd( val_buf, "%ld", atol(jsonObjectToSimpleString(value)) );
890
891         } else if ( !strcmp(osrfHashGet(field, "datatype"), "NUMERIC") ) {
892                 if (value->type == JSON_NUMBER) buffer_fadd( val_buf, "%f",  jsonObjectGetNumber(value) );
893                 else buffer_fadd( val_buf, "%f", atof(jsonObjectToSimpleString(value)) );
894         }
895
896         char* pred = buffer_data(val_buf);
897         buffer_free(val_buf);
898
899         return pred;
900 }
901
902 char* searchINPredicate (osrfHash* field, jsonObject* node, const char* op) {
903         growing_buffer* sql_buf = buffer_init(32);
904         
905         buffer_fadd(
906                 sql_buf,
907                 "%s ",
908                 osrfHashGet(field, "name")
909         );
910
911         if (!op) {
912                 buffer_add(sql_buf, "IN (");
913         } else if (!(strcasecmp(op,"not in"))) {
914                 buffer_add(sql_buf, "NOT IN (");
915         } else {
916                 buffer_add(sql_buf, "IN (");
917         }
918
919         int in_item_index = 0;
920         int in_item_first = 1;
921         jsonObject* in_item;
922         while ( (in_item = jsonObjectGetIndex(node, in_item_index++)) ) {
923
924                 if (in_item_first)
925                         in_item_first = 0;
926                 else
927                         buffer_add(sql_buf, ", ");
928
929                 if ( !strcmp(osrfHashGet(field, "primitive"), "number") ) {
930                         char* val = jsonNumberToDBString( field, in_item );
931                         buffer_fadd( sql_buf, "%s", val );
932                         free(val);
933
934                 } else {
935                         char* key_string = jsonObjectToSimpleString(in_item);
936                         if ( dbi_conn_quote_string(dbhandle, &key_string) ) {
937                                 buffer_fadd( sql_buf, "%s", key_string );
938                                 free(key_string);
939                         } else {
940                                 osrfLogError(OSRF_LOG_MARK, "%s: Error quoting key string [%s]", MODULENAME, key_string);
941                                 free(key_string);
942                                 buffer_free(sql_buf);
943                                 return NULL;
944                         }
945                 }
946         }
947
948         buffer_add(
949                 sql_buf,
950                 ")"
951         );
952
953         char* pred = buffer_data(sql_buf);
954         buffer_free(sql_buf);
955
956         return pred;
957 }
958
959 char* searchValueTransform( jsonObject* array ) {
960         growing_buffer* sql_buf = buffer_init(32);
961
962         char* val = NULL;
963         int func_item_index = 0;
964         int func_item_first = 2;
965         jsonObject* func_item;
966         while ( (func_item = jsonObjectGetIndex(array, func_item_index++)) ) {
967
968                 val = jsonObjectToSimpleString(func_item);
969
970                 if (func_item_first == 2) {
971                         buffer_fadd(sql_buf, "%s( ", val);
972                         free(val);
973                         func_item_first--;
974                         continue;
975                 }
976
977                 if (func_item_first)
978                         func_item_first--;
979                 else
980                         buffer_add(sql_buf, ", ");
981
982                 if ( dbi_conn_quote_string(dbhandle, &val) ) {
983                         buffer_fadd( sql_buf, "%s", val );
984                         free(val);
985                 } else {
986                         osrfLogError(OSRF_LOG_MARK, "%s: Error quoting key string [%s]", MODULENAME, val);
987                         free(val);
988                         buffer_free(sql_buf);
989                         return NULL;
990                 }
991         }
992
993         buffer_add(
994                 sql_buf,
995                 " )"
996         );
997
998         char* pred = buffer_data(sql_buf);
999         buffer_free(sql_buf);
1000
1001         return pred;
1002 }
1003
1004 char* searchFunctionPredicate (osrfHash* field, jsonObjectNode* node) {
1005         growing_buffer* sql_buf = buffer_init(32);
1006
1007         char* val = searchValueTransform(node->item);
1008         
1009         buffer_fadd(
1010                 sql_buf,
1011                 "%s %s %s",
1012                 osrfHashGet(field, "name"),
1013                 node->key,
1014                 val
1015         );
1016
1017         char* pred = buffer_data(sql_buf);
1018         buffer_free(sql_buf);
1019         free(val);
1020
1021         return pred;
1022 }
1023
1024 char* searchFieldTransform (osrfHash* field, jsonObject* node) {
1025         growing_buffer* sql_buf = buffer_init(32);
1026         
1027         char* field_transform = jsonObjectToSimpleString( jsonObjectGetKey( node, "transform" ) );
1028
1029         buffer_fadd(
1030                 sql_buf,
1031                 "%s(%s)",
1032                 field_transform,
1033                 osrfHashGet(field, "name")
1034         );
1035
1036         char* pred = buffer_data(sql_buf);
1037         buffer_free(sql_buf);
1038         free(field_transform);
1039
1040         return pred;
1041 }
1042
1043 char* searchFieldTransformPredicate (osrfHash* field, jsonObjectNode* node) {
1044         growing_buffer* sql_buf = buffer_init(32);
1045         
1046         char* field_transform = searchFieldTransform( field, node->item );
1047         char* value = NULL;
1048
1049         if (jsonObjectGetKey( node->item, "value" )->type == JSON_ARRAY) {
1050                 value = searchValueTransform(jsonObjectGetKey( node->item, "value" ));
1051         } else if (jsonObjectGetKey( node->item, "value" )->type != JSON_NULL) {
1052                 if ( !strcmp(osrfHashGet(field, "primitive"), "number") ) {
1053                         value = jsonNumberToDBString( field, jsonObjectGetKey( node->item, "value" ) );
1054                 } else {
1055                         value = jsonObjectToSimpleString(jsonObjectGetKey( node->item, "value" ));
1056                         if ( !dbi_conn_quote_string(dbhandle, &value) ) {
1057                                 osrfLogError(OSRF_LOG_MARK, "%s: Error quoting key string [%s]", MODULENAME, value);
1058                                 free(value);
1059                                 return NULL;
1060                         }
1061                 }
1062         }
1063
1064         buffer_fadd(
1065                 sql_buf,
1066                 "%s %s %s",
1067                 field_transform,
1068                 node->key,
1069                 value
1070         );
1071
1072         char* pred = buffer_data(sql_buf);
1073         buffer_free(sql_buf);
1074         free(field_transform);
1075
1076         return pred;
1077 }
1078
1079 char* searchSimplePredicate (const char* orig_op, osrfHash* field, jsonObject* node) {
1080
1081         char* val = NULL;
1082
1083         if (node->type != JSON_NULL) {
1084                 if ( !strcmp(osrfHashGet(field, "primitive"), "number") ) {
1085                         val = jsonNumberToDBString( field, node );
1086                 } else {
1087                         val = jsonObjectToSimpleString(node);
1088                 }
1089         }
1090
1091         char* pred = searchWriteSimplePredicate( field, osrfHashGet(field, "name"), orig_op, val );
1092
1093         if (val) free(val);
1094
1095         return pred;
1096 }
1097
1098 char* searchWriteSimplePredicate ( osrfHash* field, const char* left, const char* orig_op, const char* right ) {
1099
1100         char* val = NULL;
1101         char* op = NULL;
1102         if (right == NULL) {
1103                 val = strdup("NULL");
1104
1105                 if (strcmp( orig_op, "=" ))
1106                         op = strdup("IS NOT");
1107                 else
1108                         op = strdup("IS");
1109
1110         } else if ( !strcmp(osrfHashGet(field, "primitive"), "number") ) {
1111                 val = strdup(right);
1112                 op = strdup(orig_op);
1113
1114         } else {
1115                 val = strdup(right);
1116                 if ( !dbi_conn_quote_string(dbhandle, &val) ) {
1117                         osrfLogError(OSRF_LOG_MARK, "%s: Error quoting key string [%s]", MODULENAME, val);
1118                         free(val);
1119                         return NULL;
1120                 }
1121                 op = strdup(orig_op);
1122         }
1123
1124         growing_buffer* sql_buf = buffer_init(16);
1125         buffer_fadd( sql_buf, "%s %s %s", left, op, val );
1126         free(val);
1127         free(op);
1128
1129         char* pred = buffer_data(sql_buf);
1130         buffer_free(sql_buf);
1131
1132         return pred;
1133
1134 }
1135
1136 char* searchBETWEENPredicate (osrfHash* field, jsonObject* node) {
1137
1138         char* x_string;
1139         char* y_string;
1140
1141         if ( !strcmp(osrfHashGet(field, "primitive"), "number") ) {
1142                 x_string = jsonNumberToDBString(field, jsonObjectGetIndex(node,0));
1143                 y_string = jsonNumberToDBString(field, jsonObjectGetIndex(node,1));
1144
1145         } else {
1146                 x_string = jsonObjectToSimpleString(jsonObjectGetIndex(node,0));
1147                 y_string = jsonObjectToSimpleString(jsonObjectGetIndex(node,1));
1148                 if ( !(dbi_conn_quote_string(dbhandle, &x_string) && dbi_conn_quote_string(dbhandle, &y_string)) ) {
1149                         osrfLogError(OSRF_LOG_MARK, "%s: Error quoting key strings [%s] and [%s]", MODULENAME, x_string, y_string);
1150                         free(x_string);
1151                         free(y_string);
1152                         return NULL;
1153                 }
1154         }
1155
1156         growing_buffer* sql_buf = buffer_init(32);
1157         buffer_fadd( sql_buf, "%s BETWEEN %s AND %s", osrfHashGet(field, "name"), x_string, y_string );
1158         free(x_string);
1159         free(y_string);
1160
1161         char* pred = buffer_data(sql_buf);
1162         buffer_free(sql_buf);
1163
1164         return pred;
1165 }
1166
1167 char* searchPredicate ( osrfHash* field, jsonObject* node ) {
1168
1169         char* pred = NULL;
1170         if (node->type == JSON_ARRAY) { // equality IN search
1171                 pred = searchINPredicate( field, node, NULL );
1172         } else if (node->type == JSON_HASH) { // non-equality search
1173                 jsonObjectNode* pred_node;
1174                 jsonObjectIterator* pred_itr = jsonNewObjectIterator( node );
1175                 while ( (pred_node = jsonObjectIteratorNext( pred_itr )) ) {
1176                         if ( !(strcasecmp( pred_node->key,"between" )) )
1177                                 pred = searchBETWEENPredicate( field, pred_node->item );
1178                         else if ( !(strcasecmp( pred_node->key,"in" )) || !(strcasecmp( pred_node->key,"not in" )) )
1179                                 pred = searchINPredicate( field, pred_node->item, pred_node->key );
1180                         else if ( pred_node->item->type == JSON_ARRAY )
1181                                 pred = searchFunctionPredicate( field, pred_node );
1182                         else if ( pred_node->item->type == JSON_HASH )
1183                                 pred = searchFieldTransformPredicate( field, pred_node );
1184                         else 
1185                                 pred = searchSimplePredicate( pred_node->key, field, pred_node->item );
1186
1187                         break;
1188                 }
1189         } else if (node->type == JSON_NULL) { // IS NULL search
1190                 growing_buffer* _p = buffer_init(16);
1191                 buffer_fadd(
1192                         _p,
1193                         "%s IS NULL",
1194                         osrfHashGet(field, "name")
1195                 );
1196                 pred = buffer_data(_p);
1197                 buffer_free(_p);
1198         } else { // equality search
1199                 pred = searchSimplePredicate( "=", field, node );
1200         }
1201
1202         return pred;
1203
1204 }
1205
1206 char* buildSELECT ( jsonObject* search_hash, jsonObject* order_hash, osrfHash* meta, osrfMethodContext* ctx ) {
1207
1208         osrfHash* links = osrfHashGet(meta, "links");
1209         osrfHash* fields = osrfHashGet(meta, "fields");
1210         char* core_class = osrfHashGet(meta, "classname");
1211
1212         jsonObjectNode* node = NULL;
1213         jsonObjectNode* snode = NULL;
1214         jsonObject* _tmp;
1215
1216         growing_buffer* sql_buf = buffer_init(128);
1217         buffer_add(sql_buf, "SELECT");
1218
1219         int first = 1;
1220         if ( (_tmp = jsonObjectGetKey( order_hash, "select" )) ) {
1221
1222                 jsonObjectIterator* class_itr = jsonNewObjectIterator( _tmp );
1223                 while ( (snode = jsonObjectIteratorNext( class_itr )) ) {
1224
1225                         osrfHash* idlClass = osrfHashGet( idl, snode->key );
1226                         if (!idlClass) continue;
1227                         char* cname = osrfHashGet(idlClass, "classname");
1228
1229                         if (strcmp(core_class,snode->key)) continue;
1230
1231                         jsonObjectIterator* select_itr = jsonNewObjectIterator( snode->item );
1232                         while ( (node = jsonObjectIteratorNext( select_itr )) ) {
1233                                 osrfHash* field = osrfHashGet( osrfHashGet( idlClass, "fields" ), jsonObjectToSimpleString(node->item) );
1234                                 char* fname = osrfHashGet(field, "name");
1235
1236                                 if (!field) continue;
1237
1238                                 if (first) {
1239                                         first = 0;
1240                                 } else {
1241                                         buffer_add(sql_buf, ",");
1242                                 }
1243
1244                                 buffer_fadd(sql_buf, " \"%s\".%s", cname, fname, cname, fname);
1245                         }
1246                 }
1247
1248                 if (first) buffer_add(sql_buf, " *");
1249
1250         } else {
1251                 buffer_add(sql_buf, " *");
1252         }
1253
1254         buffer_fadd(sql_buf, " FROM %s AS \"%s\" WHERE ", osrfHashGet(meta, "tablename"), core_class );
1255
1256
1257         char* pred;
1258         first = 1;
1259         jsonObjectIterator* search_itr = jsonNewObjectIterator( search_hash );
1260         while ( (node = jsonObjectIteratorNext( search_itr )) ) {
1261                 osrfHash* field = osrfHashGet( fields, node->key );
1262
1263                 if (!field) {
1264                         osrfLogError(
1265                                 OSRF_LOG_MARK,
1266                                 "%s: Attempt to reference non-existant column %s on table %s",
1267                                 MODULENAME,
1268                                 node->key,
1269                                 osrfHashGet(meta, "tablename")
1270                         );
1271                         osrfAppSessionStatus(
1272                                 ctx->session,
1273                                 OSRF_STATUS_INTERNALSERVERERROR,
1274                                 "osrfMethodException",
1275                                 ctx->request,
1276                                 "Severe query error -- see error log for more details"
1277                         );
1278                         buffer_free(sql_buf);
1279                         return NULL;
1280                 }
1281
1282                 if (first) {
1283                         first = 0;
1284                 } else {
1285                         buffer_add(sql_buf, " AND ");
1286                 }
1287
1288                 pred = searchPredicate( field, node->item);
1289                 buffer_fadd( sql_buf, "%s", pred );
1290                 free(pred);
1291         }
1292
1293         jsonObjectIteratorFree(search_itr);
1294
1295         if (order_hash) {
1296                 char* string;
1297                 if ( (_tmp = jsonObjectGetKey( jsonObjectGetKey( order_hash, "order_by" ), core_class ) ) ){
1298                         string = jsonObjectToSimpleString(_tmp);
1299                         buffer_fadd(
1300                                 sql_buf,
1301                                 " ORDER BY %s",
1302                                 string
1303                         );
1304                         free(string);
1305                 }
1306
1307                 if ( (_tmp = jsonObjectGetKey( order_hash, "limit" )) ){
1308                         string = jsonObjectToSimpleString(_tmp);
1309                         buffer_fadd(
1310                                 sql_buf,
1311                                 " LIMIT %d",
1312                                 atoi(string)
1313                         );
1314                         free(string);
1315                 }
1316
1317                 _tmp = jsonObjectGetKey( order_hash, "offset" );
1318                 if (_tmp) {
1319                         string = jsonObjectToSimpleString(_tmp);
1320                         buffer_fadd(
1321                                 sql_buf,
1322                                 " OFFSET %d",
1323                                 atoi(string)
1324                         );
1325                         free(string);
1326                 }
1327         }
1328
1329         buffer_add(sql_buf, ";");
1330
1331         char* sql = buffer_data(sql_buf);
1332         buffer_free(sql_buf);
1333
1334         return sql;
1335 }
1336
1337 jsonObject* doSearch ( osrfMethodContext* ctx, osrfHash* meta, jsonObject* params, int* err ) {
1338
1339         // XXX for now...
1340         dbhandle = writehandle;
1341
1342         osrfHash* links = osrfHashGet(meta, "links");
1343         osrfHash* fields = osrfHashGet(meta, "fields");
1344         char* core_class = osrfHashGet(meta, "classname");
1345
1346         jsonObject* _tmp;
1347         jsonObject* obj;
1348         jsonObject* search_hash = jsonObjectGetIndex(params, 0);
1349         jsonObject* order_hash = jsonObjectGetIndex(params, 1);
1350
1351         char* sql = buildSELECT( search_hash, order_hash, meta, ctx );
1352         if (!sql) {
1353                 *err = -1;
1354                 return NULL;
1355         }
1356         
1357         osrfLogDebug(OSRF_LOG_MARK, "%s SQL =  %s", MODULENAME, sql);
1358         dbi_result result = dbi_conn_query(dbhandle, sql);
1359
1360         jsonObject* res_list = jsonParseString("[]");
1361         if(result) {
1362                 osrfLogDebug(OSRF_LOG_MARK, "Query returned with no errors");
1363
1364                 if (dbi_result_first_row(result)) {
1365                         /* JSONify the result */
1366                         osrfLogDebug(OSRF_LOG_MARK, "Query returned at least one row");
1367                         do {
1368                                 obj = oilsMakeJSONFromResult( result, meta );
1369                                 jsonObjectPush(res_list, obj);
1370                         } while (dbi_result_next_row(result));
1371                 } else {
1372                         osrfLogDebug(OSRF_LOG_MARK, "%s returned no results for query %s", MODULENAME, sql);
1373                 }
1374
1375                 /* clean up the query */
1376                 dbi_result_free(result); 
1377
1378         } else {
1379                 osrfLogError(OSRF_LOG_MARK, "%s: Error retrieving %s with query [%s]", MODULENAME, osrfHashGet(meta, "fieldmapper"), sql);
1380                 osrfAppSessionStatus(
1381                         ctx->session,
1382                         OSRF_STATUS_INTERNALSERVERERROR,
1383                         "osrfMethodException",
1384                         ctx->request,
1385                         "Severe query error -- see error log for more details"
1386                 );
1387                 *err = -1;
1388                 free(sql);
1389                 jsonObjectFree(res_list);
1390                 return jsonNULL;
1391
1392         }
1393
1394         free(sql);
1395
1396         if (res_list->size && order_hash) {
1397                 _tmp = jsonObjectGetKey( order_hash, "flesh" );
1398                 if (_tmp) {
1399                         int x = (int)jsonObjectGetNumber(_tmp);
1400
1401                         jsonObject* flesh_blob = NULL;
1402                         if ((flesh_blob = jsonObjectGetKey( order_hash, "flesh_fields" )) && x > 0) {
1403
1404                                 flesh_blob = jsonObjectClone( flesh_blob );
1405                                 jsonObject* flesh_fields = jsonObjectGetKey( flesh_blob, core_class );
1406
1407                                 osrfStringArray* link_fields = NULL;
1408
1409                                 if (flesh_fields) {
1410                                         if (flesh_fields->size == 1) {
1411                                                 char* _t = jsonObjectToSimpleString( jsonObjectGetIndex( flesh_fields, 0 ) );
1412                                                 if (!strcmp(_t,"*")) link_fields = osrfHashKeys( links );
1413                                                 free(_t);
1414                                         }
1415
1416                                         if (!link_fields) {
1417                                                 jsonObjectNode* _f;
1418                                                 link_fields = osrfNewStringArray(1);
1419                                                 jsonObjectIterator* _i = jsonNewObjectIterator( flesh_fields );
1420                                                 while ((_f = jsonObjectIteratorNext( _i ))) {
1421                                                         osrfStringArrayAdd( link_fields, jsonObjectToSimpleString( _f->item ) );
1422                                                 }
1423                                         }
1424                                 }
1425
1426                                 jsonObjectNode* cur;
1427                                 jsonObjectIterator* itr = jsonNewObjectIterator( res_list );
1428                                 while ((cur = jsonObjectIteratorNext( itr ))) {
1429
1430                                         int i = 0;
1431                                         char* link_field;
1432                                         
1433                                         while ( (link_field = osrfStringArrayGetString(link_fields, i++)) ) {
1434
1435                                                 osrfLogDebug(OSRF_LOG_MARK, "Starting to flesh %s", link_field);
1436
1437                                                 osrfHash* kid_link = osrfHashGet(links, link_field);
1438                                                 if (!kid_link) continue;
1439
1440                                                 osrfHash* field = osrfHashGet(fields, link_field);
1441                                                 if (!field) continue;
1442
1443                                                 osrfHash* value_field = field;
1444
1445                                                 osrfHash* kid_idl = osrfHashGet(idl, osrfHashGet(kid_link, "class"));
1446                                                 if (!kid_idl) continue;
1447
1448                                                 if (!(strcmp( osrfHashGet(kid_link, "reltype"), "has_many" ))) { // has_many
1449                                                         value_field = osrfHashGet( fields, osrfHashGet(meta, "primarykey") );
1450                                                 }
1451                                                         
1452                                                 if (!(strcmp( osrfHashGet(kid_link, "reltype"), "might_have" ))) { // might_have
1453                                                         value_field = osrfHashGet( fields, osrfHashGet(meta, "primarykey") );
1454                                                 }
1455
1456                                                 osrfStringArray* link_map = osrfHashGet( kid_link, "map" );
1457
1458                                                 if (link_map->size > 0) {
1459                                                         jsonObject* _kid_key = jsonParseString("[]");
1460                                                         jsonObjectPush(
1461                                                                 _kid_key,
1462                                                                 jsonNewObject( osrfStringArrayGetString( link_map, 0 ) )
1463                                                         );
1464
1465                                                         jsonObjectSetKey(
1466                                                                 flesh_blob,
1467                                                                 osrfHashGet(kid_link, "class"),
1468                                                                 _kid_key
1469                                                         );
1470                                                 };
1471
1472                                                 osrfLogDebug(
1473                                                         OSRF_LOG_MARK,
1474                                                         "Link field: %s, remote class: %s, fkey: %s, reltype: %s",
1475                                                         osrfHashGet(kid_link, "field"),
1476                                                         osrfHashGet(kid_link, "class"),
1477                                                         osrfHashGet(kid_link, "key"),
1478                                                         osrfHashGet(kid_link, "reltype")
1479                                                 );
1480
1481                                                 jsonObject* fake_params = jsonParseString("[]");
1482                                                 jsonObjectPush(fake_params, jsonParseString("{}")); // search hash
1483                                                 jsonObjectPush(fake_params, jsonParseString("{}")); // order/flesh hash
1484
1485                                                 osrfLogDebug(OSRF_LOG_MARK, "Creating dummy params object...");
1486
1487                                                 char* search_key =
1488                                                 jsonObjectToSimpleString(
1489                                                         jsonObjectGetIndex(
1490                                                                 cur->item,
1491                                                                 atoi( osrfHashGet(value_field, "array_position") )
1492                                                         )
1493                                                 );
1494
1495                                                 if (!search_key) {
1496                                                         osrfLogDebug(OSRF_LOG_MARK, "Nothing to search for!");
1497                                                         continue;
1498                                                 }
1499                                                         
1500                                                 jsonObjectSetKey(
1501                                                         jsonObjectGetIndex(fake_params, 0),
1502                                                         osrfHashGet(kid_link, "key"),
1503                                                         jsonNewObject( search_key )
1504                                                 );
1505
1506                                                 free(search_key);
1507
1508
1509                                                 jsonObjectSetKey(
1510                                                         jsonObjectGetIndex(fake_params, 1),
1511                                                         "flesh",
1512                                                         jsonNewNumberObject( (double)(x - 1 + link_map->size) )
1513                                                 );
1514
1515                                                 if (flesh_blob)
1516                                                         jsonObjectSetKey( jsonObjectGetIndex(fake_params, 1), "flesh_fields", jsonObjectClone(flesh_blob) );
1517
1518                                                 if (jsonObjectGetKey(order_hash, "order_by")) {
1519                                                         jsonObjectSetKey(
1520                                                                 jsonObjectGetIndex(fake_params, 1),
1521                                                                 "order_by",
1522                                                                 jsonObjectClone(jsonObjectGetKey(order_hash, "order_by"))
1523                                                         );
1524                                                 }
1525
1526                                                 if (jsonObjectGetKey(order_hash, "select")) {
1527                                                         jsonObjectSetKey(
1528                                                                 jsonObjectGetIndex(fake_params, 1),
1529                                                                 "select",
1530                                                                 jsonObjectClone(jsonObjectGetKey(order_hash, "select"))
1531                                                         );
1532                                                 }
1533
1534                                                 jsonObject* kids = doSearch(ctx, kid_idl, fake_params, err);
1535
1536                                                 if(*err) {
1537                                                         jsonObjectFree( fake_params );
1538                                                         osrfStringArrayFree(link_fields);
1539                                                         jsonObjectIteratorFree(itr);
1540                                                         jsonObjectFree(res_list);
1541                                                         return jsonNULL;
1542                                                 }
1543
1544                                                 osrfLogDebug(OSRF_LOG_MARK, "Search for %s return %d linked objects", osrfHashGet(kid_link, "class"), kids->size);
1545
1546                                                 jsonObject* X = NULL;
1547                                                 if ( link_map->size > 0 && kids->size > 0 ) {
1548                                                         X = kids;
1549                                                         kids = jsonParseString("[]");
1550
1551                                                         jsonObjectNode* _k_node;
1552                                                         jsonObjectIterator* _k = jsonNewObjectIterator( X );
1553                                                         while ((_k_node = jsonObjectIteratorNext( _k ))) {
1554                                                                 jsonObjectPush(
1555                                                                         kids,
1556                                                                         jsonObjectClone(
1557                                                                                 jsonObjectGetIndex(
1558                                                                                         _k_node->item,
1559                                                                                         (unsigned long)atoi(
1560                                                                                                 osrfHashGet(
1561                                                                                                         osrfHashGet(
1562                                                                                                                 osrfHashGet(
1563                                                                                                                         osrfHashGet(
1564                                                                                                                                 idl,
1565                                                                                                                                 osrfHashGet(kid_link, "class")
1566                                                                                                                         ),
1567                                                                                                                         "fields"
1568                                                                                                                 ),
1569                                                                                                                 osrfStringArrayGetString( link_map, 0 )
1570                                                                                                         ),
1571                                                                                                         "array_position"
1572                                                                                                 )
1573                                                                                         )
1574                                                                                 )
1575                                                                         )
1576                                                                 );
1577                                                         }
1578                                                 }
1579
1580                                                 if (!(strcmp( osrfHashGet(kid_link, "reltype"), "has_a" )) || !(strcmp( osrfHashGet(kid_link, "reltype"), "might_have" ))) {
1581                                                         osrfLogDebug(OSRF_LOG_MARK, "Storing fleshed objects in %s", osrfHashGet(kid_link, "field"));
1582                                                         jsonObjectSetIndex(
1583                                                                 cur->item,
1584                                                                 (unsigned long)atoi( osrfHashGet( field, "array_position" ) ),
1585                                                                 jsonObjectClone( jsonObjectGetIndex(kids, 0) )
1586                                                         );
1587                                                 }
1588
1589                                                 if (!(strcmp( osrfHashGet(kid_link, "reltype"), "has_many" ))) { // has_many
1590                                                         osrfLogDebug(OSRF_LOG_MARK, "Storing fleshed objects in %s", osrfHashGet(kid_link, "field"));
1591                                                         jsonObjectSetIndex(
1592                                                                 cur->item,
1593                                                                 (unsigned long)atoi( osrfHashGet( field, "array_position" ) ),
1594                                                                 jsonObjectClone( kids )
1595                                                         );
1596                                                 }
1597
1598                                                 if (X) {
1599                                                         jsonObjectFree(kids);
1600                                                         kids = X;
1601                                                 }
1602
1603                                                 jsonObjectFree( kids );
1604                                                 jsonObjectFree( fake_params );
1605
1606                                                 osrfLogDebug(OSRF_LOG_MARK, "Fleshing of %s complete", osrfHashGet(kid_link, "field"));
1607                                                 osrfLogDebug(OSRF_LOG_MARK, "%s", jsonObjectToJSON(cur->item));
1608
1609                                         }
1610                                 }
1611                                 jsonObjectFree( flesh_blob );
1612                                 osrfStringArrayFree(link_fields);
1613                                 jsonObjectIteratorFree(itr);
1614                         }
1615                 }
1616         }
1617
1618         return res_list;
1619 }
1620
1621
1622 jsonObject* doUpdate(osrfMethodContext* ctx, int* err ) {
1623
1624         osrfHash* meta = osrfHashGet( (osrfHash*) ctx->method->userData, "class" );
1625         jsonObject* target = jsonObjectGetIndex(ctx->params, 0);
1626
1627         if (!verifyObjectClass(ctx, target)) {
1628                 *err = -1;
1629                 return jsonNULL;
1630         }
1631
1632         if (!osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" )) {
1633                 osrfAppSessionStatus(
1634                         ctx->session,
1635                         OSRF_STATUS_BADREQUEST,
1636                         "osrfMethodException",
1637                         ctx->request,
1638                         "No active transaction -- required for UPDATE"
1639                 );
1640                 *err = -1;
1641                 return jsonNULL;
1642         }
1643
1644         dbhandle = writehandle;
1645
1646         char* trans_id = osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" );
1647
1648         // Set the last_xact_id
1649         osrfHash* last_xact_id;
1650         if ((last_xact_id = oilsIDLFindPath("/%s/fields/last_xact_id", target->classname))) {
1651                 int index = atoi( osrfHashGet(last_xact_id, "array_position") );
1652                 osrfLogDebug(OSRF_LOG_MARK, "Setting last_xact_id to %s on %s at position %d", trans_id, target->classname, index);
1653                 jsonObjectSetIndex(target, index, jsonNewObject(trans_id));
1654         }       
1655
1656         char* pkey = osrfHashGet(meta, "primarykey");
1657         osrfHash* fields = osrfHashGet(meta, "fields");
1658
1659         char* id =
1660                 jsonObjectToSimpleString(
1661                         jsonObjectGetIndex(
1662                                 target,
1663                                 atoi( osrfHashGet( osrfHashGet( fields, pkey ), "array_position" ) )
1664                         )
1665                 );
1666
1667         osrfLogDebug(
1668                 OSRF_LOG_MARK,
1669                 "%s updating %s object with %s = %s",
1670                 MODULENAME,
1671                 osrfHashGet(meta, "fieldmapper"),
1672                 pkey,
1673                 id
1674         );
1675
1676         growing_buffer* sql = buffer_init(128);
1677         buffer_fadd(sql,"UPDATE %s SET", osrfHashGet(meta, "tablename"));
1678
1679         int i = 0;
1680         int first = 1;
1681         char* field_name;
1682         osrfStringArray* field_list = osrfHashKeys( fields );
1683         while ( (field_name = osrfStringArrayGetString(field_list, i++)) ) {
1684
1685                 osrfHash* field = osrfHashGet( fields, field_name );
1686
1687                 if(!( strcmp( field_name, pkey ) )) continue;
1688                 if(!( strcmp( osrfHashGet(osrfHashGet(fields,field_name), "virtual"), "true" ) )) continue;
1689
1690                 int pos = atoi(osrfHashGet(field, "array_position"));
1691                 char* value = jsonObjectToSimpleString( jsonObjectGetIndex( target, pos ) );
1692
1693                 osrfLogDebug( OSRF_LOG_MARK, "Updating %s object with %s = %s", osrfHashGet(meta, "fieldmapper"), field_name, value);
1694
1695                 if (!jsonObjectGetIndex(target, pos) || jsonObjectGetIndex(target, pos)->type == JSON_NULL) {
1696                         if ( !(!( strcmp( osrfHashGet(meta, "classname"), "au" ) ) && !( strcmp( field_name, "passwd" ) )) ) { // arg at the special case!
1697                                 if (first) first = 0;
1698                                 else buffer_add(sql, ",");
1699                                 buffer_fadd( sql, " %s = NULL", field_name );
1700                         }
1701                         
1702                 } else if ( !strcmp(osrfHashGet(field, "primitive"), "number") ) {
1703                         if (first) first = 0;
1704                         else buffer_add(sql, ",");
1705
1706                         if ( !strncmp(osrfHashGet(field, "datatype"), "INT", (size_t)3) ) {
1707                                 buffer_fadd( sql, " %s = %ld", field_name, atol(value) );
1708                         } else if ( !strcmp(osrfHashGet(field, "datatype"), "NUMERIC") ) {
1709                                 buffer_fadd( sql, " %s = %f", field_name, atof(value) );
1710                         }
1711
1712                         osrfLogDebug( OSRF_LOG_MARK, "%s is of type %s", field_name, osrfHashGet(field, "datatype"));
1713
1714                 } else {
1715                         if ( dbi_conn_quote_string(dbhandle, &value) ) {
1716                                 if (first) first = 0;
1717                                 else buffer_add(sql, ",");
1718                                 buffer_fadd( sql, " %s = %s", field_name, value );
1719
1720                         } else {
1721                                 osrfLogError(OSRF_LOG_MARK, "%s: Error quoting string [%s]", MODULENAME, value);
1722                                 osrfAppSessionStatus(
1723                                         ctx->session,
1724                                         OSRF_STATUS_INTERNALSERVERERROR,
1725                                         "osrfMethodException",
1726                                         ctx->request,
1727                                         "Error quoting string -- please see the error log for more details"
1728                                 );
1729                                 free(value);
1730                                 free(id);
1731                                 buffer_free(sql);
1732                                 *err = -1;
1733                                 return jsonNULL;
1734                         }
1735                 }
1736
1737                 free(value);
1738                 
1739         }
1740
1741         jsonObject* obj = jsonParseString(id);
1742
1743         if ( strcmp( osrfHashGet( osrfHashGet( osrfHashGet(meta, "fields"), pkey ), "primitive" ), "number" ) )
1744                 dbi_conn_quote_string(dbhandle, &id);
1745
1746         buffer_fadd( sql, " WHERE %s = %s;", pkey, id );
1747
1748         char* query = buffer_data(sql);
1749         buffer_free(sql);
1750
1751         osrfLogDebug(OSRF_LOG_MARK, "%s: Update SQL [%s]", MODULENAME, query);
1752
1753         dbi_result result = dbi_conn_query(dbhandle, query);
1754         free(query);
1755
1756         if (!result) {
1757                 jsonObjectFree(obj);
1758                 obj = jsonNewObject(NULL);
1759                 osrfLogError(
1760                         OSRF_LOG_MARK,
1761                         "%s ERROR updating %s object with %s = %s",
1762                         MODULENAME,
1763                         osrfHashGet(meta, "fieldmapper"),
1764                         pkey,
1765                         id
1766                 );
1767         }
1768
1769         free(id);
1770
1771         return obj;
1772 }
1773
1774 jsonObject* doDelete(osrfMethodContext* ctx, int* err ) {
1775
1776         osrfHash* meta = osrfHashGet( (osrfHash*) ctx->method->userData, "class" );
1777
1778         if (!osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" )) {
1779                 osrfAppSessionStatus(
1780                         ctx->session,
1781                         OSRF_STATUS_BADREQUEST,
1782                         "osrfMethodException",
1783                         ctx->request,
1784                         "No active transaction -- required for DELETE"
1785                 );
1786                 *err = -1;
1787                 return jsonNULL;
1788         }
1789
1790         dbhandle = writehandle;
1791
1792         jsonObject* obj;
1793
1794         char* pkey = osrfHashGet(meta, "primarykey");
1795
1796         char* id;
1797         if (jsonObjectGetIndex(ctx->params, 0)->classname) {
1798                 if (!verifyObjectClass(ctx, jsonObjectGetIndex( ctx->params, 0 ))) {
1799                         *err = -1;
1800                         return jsonNULL;
1801                 }
1802
1803                 id = jsonObjectToSimpleString(
1804                         jsonObjectGetIndex(
1805                                 jsonObjectGetIndex(ctx->params, 0),
1806                                 atoi( osrfHashGet( osrfHashGet( osrfHashGet(meta, "fields"), pkey ), "array_position") )
1807                         )
1808                 );
1809         } else {
1810                 id = jsonObjectToSimpleString(jsonObjectGetIndex(ctx->params, 0));
1811         }
1812
1813         osrfLogDebug(
1814                 OSRF_LOG_MARK,
1815                 "%s deleting %s object with %s = %s",
1816                 MODULENAME,
1817                 osrfHashGet(meta, "fieldmapper"),
1818                 pkey,
1819                 id
1820         );
1821
1822         obj = jsonParseString(id);
1823
1824         if ( strcmp( osrfHashGet( osrfHashGet( osrfHashGet(meta, "fields"), pkey ), "primitive" ), "number" ) )
1825                 dbi_conn_quote_string(writehandle, &id);
1826
1827         dbi_result result = dbi_conn_queryf(writehandle, "DELETE FROM %s WHERE %s = %s;", osrfHashGet(meta, "tablename"), pkey, id);
1828
1829         if (!result) {
1830                 jsonObjectFree(obj);
1831                 obj = jsonNewObject(NULL);
1832                 osrfLogError(
1833                         OSRF_LOG_MARK,
1834                         "%s ERROR deleting %s object with %s = %s",
1835                         MODULENAME,
1836                         osrfHashGet(meta, "fieldmapper"),
1837                         pkey,
1838                         id
1839                 );
1840         }
1841
1842         free(id);
1843
1844         return obj;
1845
1846 }
1847
1848
1849 jsonObject* oilsMakeJSONFromResult( dbi_result result, osrfHash* meta) {
1850         if(!(result && meta)) return jsonNULL;
1851
1852         jsonObject* object = jsonParseString("[]");
1853         jsonObjectSetClass(object, osrfHashGet(meta, "classname"));
1854
1855         osrfHash* fields = osrfHashGet(meta, "fields");
1856
1857         osrfLogInternal(OSRF_LOG_MARK, "Setting object class to %s ", object->classname);
1858
1859         osrfHash* _f;
1860         time_t _tmp_dt;
1861         char dt_string[256];
1862         struct tm gmdt;
1863
1864         int fmIndex;
1865         int columnIndex = 1;
1866         int attr;
1867         unsigned short type;
1868         const char* columnName;
1869
1870         /* cycle through the column list */
1871         while( (columnName = dbi_result_get_field_name(result, columnIndex++)) ) {
1872
1873                 osrfLogInternal(OSRF_LOG_MARK, "Looking for column named [%s]...", (char*)columnName);
1874
1875                 fmIndex = -1; // reset the position
1876                 
1877                 /* determine the field type and storage attributes */
1878                 type = dbi_result_get_field_type(result, columnName);
1879                 attr = dbi_result_get_field_attribs(result, columnName);
1880
1881                 /* fetch the fieldmapper index */
1882                 if( (_f = osrfHashGet(fields, (char*)columnName)) ) {
1883                         char* virt = (char*)osrfHashGet(_f, "virtual");
1884                         char* pos = (char*)osrfHashGet(_f, "array_position");
1885
1886                         if ( !virt || !pos || !(strcmp( virt, "true" )) ) continue;
1887
1888                         fmIndex = atoi( pos );
1889                         osrfLogInternal(OSRF_LOG_MARK, "... Found column at position [%s]...", pos);
1890                 } else {
1891                         continue;
1892                 }
1893
1894                 if (dbi_result_field_is_null(result, columnName)) {
1895                         jsonObjectSetIndex( object, fmIndex, jsonNewObject(NULL) );
1896                 } else {
1897
1898                         switch( type ) {
1899
1900                                 case DBI_TYPE_INTEGER :
1901
1902                                         if( attr & DBI_INTEGER_SIZE8 ) 
1903                                                 jsonObjectSetIndex( object, fmIndex, 
1904                                                         jsonNewNumberObject(dbi_result_get_longlong(result, columnName)));
1905                                         else 
1906                                                 jsonObjectSetIndex( object, fmIndex, 
1907                                                         jsonNewNumberObject(dbi_result_get_long(result, columnName)));
1908
1909                                         break;
1910
1911                                 case DBI_TYPE_DECIMAL :
1912                                         jsonObjectSetIndex( object, fmIndex, 
1913                                                         jsonNewNumberObject(dbi_result_get_double(result, columnName)));
1914                                         break;
1915
1916                                 case DBI_TYPE_STRING :
1917
1918
1919                                         jsonObjectSetIndex(
1920                                                 object,
1921                                                 fmIndex,
1922                                                 jsonNewObject( dbi_result_get_string(result, columnName) )
1923                                         );
1924
1925                                         break;
1926
1927                                 case DBI_TYPE_DATETIME :
1928
1929                                         memset(dt_string, '\0', 256);
1930                                         memset(&gmdt, '\0', sizeof(gmdt));
1931                                         memset(&_tmp_dt, '\0', sizeof(_tmp_dt));
1932
1933                                         _tmp_dt = dbi_result_get_datetime(result, columnName);
1934
1935                                         localtime_r( &_tmp_dt, &gmdt );
1936
1937                                         if (!(attr & DBI_DATETIME_DATE)) {
1938                                                 strftime(dt_string, 255, "%T", &gmdt);
1939                                         } else if (!(attr & DBI_DATETIME_TIME)) {
1940                                                 strftime(dt_string, 255, "%F", &gmdt);
1941                                         } else {
1942                                                 strftime(dt_string, 255, "%FT%T%z", &gmdt);
1943                                         }
1944
1945                                         jsonObjectSetIndex( object, fmIndex, jsonNewObject(dt_string) );
1946
1947                                         break;
1948
1949                                 case DBI_TYPE_BINARY :
1950                                         osrfLogError( OSRF_LOG_MARK, 
1951                                                 "Can't do binary at column %s : index %d", columnName, columnIndex - 1);
1952                         }
1953                 }
1954         }
1955
1956         return object;
1957 }
1958