]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/c-apps/oils_cstore.c
handle embeded FM objects during insert/update
[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                 jsonObject* field_object = jsonObjectGetIndex( target, atoi(osrfHashGet(field, "array_position")) );
697
698                 char* value;
699                 if (field_object && field_object->classname) {
700                         value = jsonObjectToSimpleString(
701                                         jsonObjectGetIndex(
702                                                 field_object,
703                                                 atoi(
704                                                         osrfHashGet(
705                                                                 osrfHashGet(
706                                                                         oilsIDLFindPath("/%s/fields", field_object->classname),
707                                                                         (char*)oilsIDLFindPath("/%s/primarykey", field_object->classname)
708                                                                 ),
709                                                                 "array_position"
710                                                         )
711                                                 )
712                                         )
713                                 );
714
715                 } else {
716                         value = jsonObjectToSimpleString( field_object );
717                 }
718
719
720                 if (first) {
721                         first = 0;
722                 } else {
723                         buffer_add(col_buf, ",");
724                         buffer_add(val_buf, ",");
725                 }
726
727                 buffer_add(col_buf, field_name);
728
729                 if (!field_object || field_object->type == JSON_NULL) {
730                         buffer_add( val_buf, "DEFAULT" );
731                         
732                 } else if ( !strcmp(osrfHashGet(field, "primitive"), "number") ) {
733                         if ( !strcmp(osrfHashGet(field, "datatype"), "INT8") ) {
734                                 buffer_fadd( val_buf, "%lld", atol(value) );
735                                 
736                         } else if ( !strcmp(osrfHashGet(field, "datatype"), "INT") ) {
737                                 buffer_fadd( val_buf, "%ld", atoll(value) );
738                                 
739                         } else if ( !strcmp(osrfHashGet(field, "datatype"), "NUMERIC") ) {
740                                 buffer_fadd( val_buf, "%f", atof(value) );
741                         }
742                 } else {
743                         if ( dbi_conn_quote_string(writehandle, &value) ) {
744                                 buffer_fadd( val_buf, "%s", value );
745
746                         } else {
747                                 osrfLogError(OSRF_LOG_MARK, "%s: Error quoting string [%s]", MODULENAME, value);
748                                 osrfAppSessionStatus(
749                                         ctx->session,
750                                         OSRF_STATUS_INTERNALSERVERERROR,
751                                         "osrfMethodException",
752                                         ctx->request,
753                                         "Error quoting string -- please see the error log for more details"
754                                 );
755                                 free(value);
756                                 buffer_free(table_buf);
757                                 buffer_free(col_buf);
758                                 buffer_free(val_buf);
759                                 *err = -1;
760                                 return jsonNULL;
761                         }
762                 }
763
764                 free(value);
765                 
766         }
767
768
769         buffer_add(col_buf,")");
770         buffer_add(val_buf,")");
771
772         growing_buffer* sql = buffer_init(128);
773         buffer_fadd(
774                 sql,
775                 "%s %s %s;",
776                 buffer_data(table_buf),
777                 buffer_data(col_buf),
778                 buffer_data(val_buf)
779         );
780         buffer_free(table_buf);
781         buffer_free(col_buf);
782         buffer_free(val_buf);
783
784         char* query = buffer_data(sql);
785         buffer_free(sql);
786
787         osrfLogDebug(OSRF_LOG_MARK, "%s: Insert SQL [%s]", MODULENAME, query);
788
789         
790         dbi_result result = dbi_conn_query(writehandle, query);
791
792         jsonObject* obj = NULL;
793
794         if (!result) {
795                 obj = jsonNewObject(NULL);
796                 osrfLogError(
797                         OSRF_LOG_MARK,
798                         "%s ERROR inserting %s object using query [%s]",
799                         MODULENAME,
800                         osrfHashGet(meta, "fieldmapper"),
801                         query
802                 );
803                 osrfAppSessionStatus(
804                         ctx->session,
805                         OSRF_STATUS_INTERNALSERVERERROR,
806                         "osrfMethodException",
807                         ctx->request,
808                         "INSERT error -- please see the error log for more details"
809                 );
810                 *err = -1;
811         } else {
812
813                 int pos = atoi(osrfHashGet( osrfHashGet(fields, pkey), "array_position" ));
814                 char* id = jsonObjectToSimpleString(jsonObjectGetIndex(target, pos));
815                 if (!id) {
816                         unsigned long long new_id = dbi_conn_sequence_last(writehandle, seq);
817                         growing_buffer* _id = buffer_init(10);
818                         buffer_fadd(_id, "%lld", new_id);
819                         id = buffer_data(_id);
820                         buffer_free(_id);
821                 }
822
823                 if (    !options
824                         || !jsonObjectGetKey( options, "quiet")
825                         || strcmp( jsonObjectToSimpleString(jsonObjectGetKey( options, "quiet")), "true" )
826                 ) {
827
828                         jsonObject* fake_params = jsonParseString("[]");
829                         jsonObjectPush(fake_params, jsonParseString("{}"));
830
831                         jsonObjectSetKey(
832                                 jsonObjectGetIndex(fake_params, 0),
833                                 osrfHashGet(meta, "primarykey"),
834                                 jsonNewObject(id)
835                         );
836
837                         jsonObject* list = doSearch( ctx,meta, fake_params, err);
838
839                         if(*err) {
840                                 jsonObjectFree( fake_params );
841                                 obj = jsonNULL;
842                         } else {
843                                 obj = jsonObjectClone( jsonObjectGetIndex(list, 0) );
844                         }
845
846                         jsonObjectFree( list );
847                         jsonObjectFree( fake_params );
848
849                 } else {
850                         obj = jsonNewObject(id);
851                 }
852
853         }
854
855         free(query);
856
857         return obj;
858
859 }
860
861
862 jsonObject* doRetrieve(osrfMethodContext* ctx, int* err ) {
863
864         osrfHash* meta = osrfHashGet( (osrfHash*) ctx->method->userData, "class" );
865
866         jsonObject* obj;
867
868         char* id = jsonObjectToSimpleString(jsonObjectGetIndex(ctx->params, 0));
869         jsonObject* order_hash = jsonObjectGetIndex(ctx->params, 1);
870
871         osrfLogDebug(
872                 OSRF_LOG_MARK,
873                 "%s retrieving %s object with id %s",
874                 MODULENAME,
875                 osrfHashGet(meta, "fieldmapper"),
876                 id
877         );
878
879         jsonObject* fake_params = jsonParseString("[]");
880         jsonObjectPush(fake_params, jsonParseString("{}"));
881
882         jsonObjectSetKey(
883                 jsonObjectGetIndex(fake_params, 0),
884                 osrfHashGet(meta, "primarykey"),
885                 jsonParseString(id)
886         );
887
888         if (order_hash) jsonObjectPush(fake_params, jsonObjectClone(order_hash) );
889
890         jsonObject* list = doSearch( ctx,meta, fake_params, err);
891
892         if(*err) {
893                 jsonObjectFree( fake_params );
894                 return jsonNULL;
895         }
896
897         obj = jsonObjectClone( jsonObjectGetIndex(list, 0) );
898
899         jsonObjectFree( list );
900         jsonObjectFree( fake_params );
901
902         return obj;
903 }
904
905 char* jsonNumberToDBString ( osrfHash* field, jsonObject* value ) {
906         growing_buffer* val_buf = buffer_init(32);
907
908         if ( !strncmp(osrfHashGet(field, "datatype"), "INT", 3) ) {
909                 if (value->type == JSON_NUMBER) buffer_fadd( val_buf, "%ld", (long)jsonObjectGetNumber(value) );
910                 else buffer_fadd( val_buf, "%ld", atol(jsonObjectToSimpleString(value)) );
911
912         } else if ( !strcmp(osrfHashGet(field, "datatype"), "NUMERIC") ) {
913                 if (value->type == JSON_NUMBER) buffer_fadd( val_buf, "%f",  jsonObjectGetNumber(value) );
914                 else buffer_fadd( val_buf, "%f", atof(jsonObjectToSimpleString(value)) );
915         }
916
917         char* pred = buffer_data(val_buf);
918         buffer_free(val_buf);
919
920         return pred;
921 }
922
923 char* searchINPredicate (osrfHash* field, jsonObject* node, const char* op) {
924         growing_buffer* sql_buf = buffer_init(32);
925         
926         buffer_fadd(
927                 sql_buf,
928                 "%s ",
929                 osrfHashGet(field, "name")
930         );
931
932         if (!op) {
933                 buffer_add(sql_buf, "IN (");
934         } else if (!(strcasecmp(op,"not in"))) {
935                 buffer_add(sql_buf, "NOT IN (");
936         } else {
937                 buffer_add(sql_buf, "IN (");
938         }
939
940         int in_item_index = 0;
941         int in_item_first = 1;
942         jsonObject* in_item;
943         while ( (in_item = jsonObjectGetIndex(node, in_item_index++)) ) {
944
945                 if (in_item_first)
946                         in_item_first = 0;
947                 else
948                         buffer_add(sql_buf, ", ");
949
950                 if ( !strcmp(osrfHashGet(field, "primitive"), "number") ) {
951                         char* val = jsonNumberToDBString( field, in_item );
952                         buffer_fadd( sql_buf, "%s", val );
953                         free(val);
954
955                 } else {
956                         char* key_string = jsonObjectToSimpleString(in_item);
957                         if ( dbi_conn_quote_string(dbhandle, &key_string) ) {
958                                 buffer_fadd( sql_buf, "%s", key_string );
959                                 free(key_string);
960                         } else {
961                                 osrfLogError(OSRF_LOG_MARK, "%s: Error quoting key string [%s]", MODULENAME, key_string);
962                                 free(key_string);
963                                 buffer_free(sql_buf);
964                                 return NULL;
965                         }
966                 }
967         }
968
969         buffer_add(
970                 sql_buf,
971                 ")"
972         );
973
974         char* pred = buffer_data(sql_buf);
975         buffer_free(sql_buf);
976
977         return pred;
978 }
979
980 char* searchValueTransform( jsonObject* array ) {
981         growing_buffer* sql_buf = buffer_init(32);
982
983         char* val = NULL;
984         int func_item_index = 0;
985         int func_item_first = 2;
986         jsonObject* func_item;
987         while ( (func_item = jsonObjectGetIndex(array, func_item_index++)) ) {
988
989                 val = jsonObjectToSimpleString(func_item);
990
991                 if (func_item_first == 2) {
992                         buffer_fadd(sql_buf, "%s( ", val);
993                         free(val);
994                         func_item_first--;
995                         continue;
996                 }
997
998                 if (func_item_first)
999                         func_item_first--;
1000                 else
1001                         buffer_add(sql_buf, ", ");
1002
1003                 if ( dbi_conn_quote_string(dbhandle, &val) ) {
1004                         buffer_fadd( sql_buf, "%s", val );
1005                         free(val);
1006                 } else {
1007                         osrfLogError(OSRF_LOG_MARK, "%s: Error quoting key string [%s]", MODULENAME, val);
1008                         free(val);
1009                         buffer_free(sql_buf);
1010                         return NULL;
1011                 }
1012         }
1013
1014         buffer_add(
1015                 sql_buf,
1016                 " )"
1017         );
1018
1019         char* pred = buffer_data(sql_buf);
1020         buffer_free(sql_buf);
1021
1022         return pred;
1023 }
1024
1025 char* searchFunctionPredicate (osrfHash* field, jsonObjectNode* node) {
1026         growing_buffer* sql_buf = buffer_init(32);
1027
1028         char* val = searchValueTransform(node->item);
1029         
1030         buffer_fadd(
1031                 sql_buf,
1032                 "%s %s %s",
1033                 osrfHashGet(field, "name"),
1034                 node->key,
1035                 val
1036         );
1037
1038         char* pred = buffer_data(sql_buf);
1039         buffer_free(sql_buf);
1040         free(val);
1041
1042         return pred;
1043 }
1044
1045 char* searchFieldTransform (osrfHash* field, jsonObject* node) {
1046         growing_buffer* sql_buf = buffer_init(32);
1047         
1048         char* field_transform = jsonObjectToSimpleString( jsonObjectGetKey( node, "transform" ) );
1049
1050         buffer_fadd(
1051                 sql_buf,
1052                 "%s(%s)",
1053                 field_transform,
1054                 osrfHashGet(field, "name")
1055         );
1056
1057         char* pred = buffer_data(sql_buf);
1058         buffer_free(sql_buf);
1059         free(field_transform);
1060
1061         return pred;
1062 }
1063
1064 char* searchFieldTransformPredicate (osrfHash* field, jsonObjectNode* node) {
1065         growing_buffer* sql_buf = buffer_init(32);
1066         
1067         char* field_transform = searchFieldTransform( field, node->item );
1068         char* value = NULL;
1069
1070         if (jsonObjectGetKey( node->item, "value" )->type == JSON_ARRAY) {
1071                 value = searchValueTransform(jsonObjectGetKey( node->item, "value" ));
1072         } else if (jsonObjectGetKey( node->item, "value" )->type != JSON_NULL) {
1073                 if ( !strcmp(osrfHashGet(field, "primitive"), "number") ) {
1074                         value = jsonNumberToDBString( field, jsonObjectGetKey( node->item, "value" ) );
1075                 } else {
1076                         value = jsonObjectToSimpleString(jsonObjectGetKey( node->item, "value" ));
1077                         if ( !dbi_conn_quote_string(dbhandle, &value) ) {
1078                                 osrfLogError(OSRF_LOG_MARK, "%s: Error quoting key string [%s]", MODULENAME, value);
1079                                 free(value);
1080                                 return NULL;
1081                         }
1082                 }
1083         }
1084
1085         buffer_fadd(
1086                 sql_buf,
1087                 "%s %s %s",
1088                 field_transform,
1089                 node->key,
1090                 value
1091         );
1092
1093         char* pred = buffer_data(sql_buf);
1094         buffer_free(sql_buf);
1095         free(field_transform);
1096
1097         return pred;
1098 }
1099
1100 char* searchSimplePredicate (const char* orig_op, osrfHash* field, jsonObject* node) {
1101
1102         char* val = NULL;
1103
1104         if (node->type != JSON_NULL) {
1105                 if ( !strcmp(osrfHashGet(field, "primitive"), "number") ) {
1106                         val = jsonNumberToDBString( field, node );
1107                 } else {
1108                         val = jsonObjectToSimpleString(node);
1109                 }
1110         }
1111
1112         char* pred = searchWriteSimplePredicate( field, osrfHashGet(field, "name"), orig_op, val );
1113
1114         if (val) free(val);
1115
1116         return pred;
1117 }
1118
1119 char* searchWriteSimplePredicate ( osrfHash* field, const char* left, const char* orig_op, const char* right ) {
1120
1121         char* val = NULL;
1122         char* op = NULL;
1123         if (right == NULL) {
1124                 val = strdup("NULL");
1125
1126                 if (strcmp( orig_op, "=" ))
1127                         op = strdup("IS NOT");
1128                 else
1129                         op = strdup("IS");
1130
1131         } else if ( !strcmp(osrfHashGet(field, "primitive"), "number") ) {
1132                 val = strdup(right);
1133                 op = strdup(orig_op);
1134
1135         } else {
1136                 val = strdup(right);
1137                 if ( !dbi_conn_quote_string(dbhandle, &val) ) {
1138                         osrfLogError(OSRF_LOG_MARK, "%s: Error quoting key string [%s]", MODULENAME, val);
1139                         free(val);
1140                         return NULL;
1141                 }
1142                 op = strdup(orig_op);
1143         }
1144
1145         growing_buffer* sql_buf = buffer_init(16);
1146         buffer_fadd( sql_buf, "%s %s %s", left, op, val );
1147         free(val);
1148         free(op);
1149
1150         char* pred = buffer_data(sql_buf);
1151         buffer_free(sql_buf);
1152
1153         return pred;
1154
1155 }
1156
1157 char* searchBETWEENPredicate (osrfHash* field, jsonObject* node) {
1158
1159         char* x_string;
1160         char* y_string;
1161
1162         if ( !strcmp(osrfHashGet(field, "primitive"), "number") ) {
1163                 x_string = jsonNumberToDBString(field, jsonObjectGetIndex(node,0));
1164                 y_string = jsonNumberToDBString(field, jsonObjectGetIndex(node,1));
1165
1166         } else {
1167                 x_string = jsonObjectToSimpleString(jsonObjectGetIndex(node,0));
1168                 y_string = jsonObjectToSimpleString(jsonObjectGetIndex(node,1));
1169                 if ( !(dbi_conn_quote_string(dbhandle, &x_string) && dbi_conn_quote_string(dbhandle, &y_string)) ) {
1170                         osrfLogError(OSRF_LOG_MARK, "%s: Error quoting key strings [%s] and [%s]", MODULENAME, x_string, y_string);
1171                         free(x_string);
1172                         free(y_string);
1173                         return NULL;
1174                 }
1175         }
1176
1177         growing_buffer* sql_buf = buffer_init(32);
1178         buffer_fadd( sql_buf, "%s BETWEEN %s AND %s", osrfHashGet(field, "name"), x_string, y_string );
1179         free(x_string);
1180         free(y_string);
1181
1182         char* pred = buffer_data(sql_buf);
1183         buffer_free(sql_buf);
1184
1185         return pred;
1186 }
1187
1188 char* searchPredicate ( osrfHash* field, jsonObject* node ) {
1189
1190         char* pred = NULL;
1191         if (node->type == JSON_ARRAY) { // equality IN search
1192                 pred = searchINPredicate( field, node, NULL );
1193         } else if (node->type == JSON_HASH) { // non-equality search
1194                 jsonObjectNode* pred_node;
1195                 jsonObjectIterator* pred_itr = jsonNewObjectIterator( node );
1196                 while ( (pred_node = jsonObjectIteratorNext( pred_itr )) ) {
1197                         if ( !(strcasecmp( pred_node->key,"between" )) )
1198                                 pred = searchBETWEENPredicate( field, pred_node->item );
1199                         else if ( !(strcasecmp( pred_node->key,"in" )) || !(strcasecmp( pred_node->key,"not in" )) )
1200                                 pred = searchINPredicate( field, pred_node->item, pred_node->key );
1201                         else if ( pred_node->item->type == JSON_ARRAY )
1202                                 pred = searchFunctionPredicate( field, pred_node );
1203                         else if ( pred_node->item->type == JSON_HASH )
1204                                 pred = searchFieldTransformPredicate( field, pred_node );
1205                         else 
1206                                 pred = searchSimplePredicate( pred_node->key, field, pred_node->item );
1207
1208                         break;
1209                 }
1210         } else if (node->type == JSON_NULL) { // IS NULL search
1211                 growing_buffer* _p = buffer_init(16);
1212                 buffer_fadd(
1213                         _p,
1214                         "%s IS NULL",
1215                         osrfHashGet(field, "name")
1216                 );
1217                 pred = buffer_data(_p);
1218                 buffer_free(_p);
1219         } else { // equality search
1220                 pred = searchSimplePredicate( "=", field, node );
1221         }
1222
1223         return pred;
1224
1225 }
1226
1227 char* buildSELECT ( jsonObject* search_hash, jsonObject* order_hash, osrfHash* meta, osrfMethodContext* ctx ) {
1228
1229         //  XXX this will be used for joins, I think
1230         //osrfHash* links = osrfHashGet(meta, "links");
1231
1232         osrfHash* fields = osrfHashGet(meta, "fields");
1233         char* core_class = osrfHashGet(meta, "classname");
1234
1235         jsonObjectNode* node = NULL;
1236         jsonObjectNode* snode = NULL;
1237         jsonObject* _tmp;
1238
1239         growing_buffer* sql_buf = buffer_init(128);
1240         buffer_add(sql_buf, "SELECT");
1241
1242         int first = 1;
1243         if ( (_tmp = jsonObjectGetKey( order_hash, "select" )) ) {
1244
1245                 jsonObjectIterator* class_itr = jsonNewObjectIterator( _tmp );
1246                 while ( (snode = jsonObjectIteratorNext( class_itr )) ) {
1247
1248                         osrfHash* idlClass = osrfHashGet( idl, snode->key );
1249                         if (!idlClass) continue;
1250                         char* cname = osrfHashGet(idlClass, "classname");
1251
1252                         if (strcmp(core_class,snode->key)) continue;
1253
1254                         jsonObjectIterator* select_itr = jsonNewObjectIterator( snode->item );
1255                         while ( (node = jsonObjectIteratorNext( select_itr )) ) {
1256                                 osrfHash* field = osrfHashGet( osrfHashGet( idlClass, "fields" ), jsonObjectToSimpleString(node->item) );
1257                                 char* fname = osrfHashGet(field, "name");
1258
1259                                 if (!field) continue;
1260
1261                                 if (first) {
1262                                         first = 0;
1263                                 } else {
1264                                         buffer_add(sql_buf, ",");
1265                                 }
1266
1267                                 buffer_fadd(sql_buf, " \"%s\".%s", cname, fname, cname, fname);
1268                         }
1269                 }
1270
1271                 if (first) buffer_add(sql_buf, " *");
1272
1273         } else {
1274                 buffer_add(sql_buf, " *");
1275         }
1276
1277         buffer_fadd(sql_buf, " FROM %s AS \"%s\" WHERE ", osrfHashGet(meta, "tablename"), core_class );
1278
1279
1280         char* pred;
1281         first = 1;
1282         jsonObjectIterator* search_itr = jsonNewObjectIterator( search_hash );
1283         while ( (node = jsonObjectIteratorNext( search_itr )) ) {
1284                 osrfHash* field = osrfHashGet( fields, node->key );
1285
1286                 if (!field) {
1287                         osrfLogError(
1288                                 OSRF_LOG_MARK,
1289                                 "%s: Attempt to reference non-existant column %s on table %s",
1290                                 MODULENAME,
1291                                 node->key,
1292                                 osrfHashGet(meta, "tablename")
1293                         );
1294                         osrfAppSessionStatus(
1295                                 ctx->session,
1296                                 OSRF_STATUS_INTERNALSERVERERROR,
1297                                 "osrfMethodException",
1298                                 ctx->request,
1299                                 "Severe query error -- see error log for more details"
1300                         );
1301                         buffer_free(sql_buf);
1302                         return NULL;
1303                 }
1304
1305                 if (first) {
1306                         first = 0;
1307                 } else {
1308                         buffer_add(sql_buf, " AND ");
1309                 }
1310
1311                 pred = searchPredicate( field, node->item);
1312                 buffer_fadd( sql_buf, "%s", pred );
1313                 free(pred);
1314         }
1315
1316         jsonObjectIteratorFree(search_itr);
1317
1318         if (order_hash) {
1319                 char* string;
1320                 if ( (_tmp = jsonObjectGetKey( jsonObjectGetKey( order_hash, "order_by" ), core_class ) ) ){
1321                         string = jsonObjectToSimpleString(_tmp);
1322                         buffer_fadd(
1323                                 sql_buf,
1324                                 " ORDER BY %s",
1325                                 string
1326                         );
1327                         free(string);
1328                 }
1329
1330                 if ( (_tmp = jsonObjectGetKey( order_hash, "limit" )) ){
1331                         string = jsonObjectToSimpleString(_tmp);
1332                         buffer_fadd(
1333                                 sql_buf,
1334                                 " LIMIT %d",
1335                                 atoi(string)
1336                         );
1337                         free(string);
1338                 }
1339
1340                 _tmp = jsonObjectGetKey( order_hash, "offset" );
1341                 if (_tmp) {
1342                         string = jsonObjectToSimpleString(_tmp);
1343                         buffer_fadd(
1344                                 sql_buf,
1345                                 " OFFSET %d",
1346                                 atoi(string)
1347                         );
1348                         free(string);
1349                 }
1350         }
1351
1352         buffer_add(sql_buf, ";");
1353
1354         char* sql = buffer_data(sql_buf);
1355         buffer_free(sql_buf);
1356
1357         return sql;
1358 }
1359
1360 jsonObject* doSearch ( osrfMethodContext* ctx, osrfHash* meta, jsonObject* params, int* err ) {
1361
1362         // XXX for now...
1363         dbhandle = writehandle;
1364
1365         osrfHash* links = osrfHashGet(meta, "links");
1366         osrfHash* fields = osrfHashGet(meta, "fields");
1367         char* core_class = osrfHashGet(meta, "classname");
1368
1369         jsonObject* _tmp;
1370         jsonObject* obj;
1371         jsonObject* search_hash = jsonObjectGetIndex(params, 0);
1372         jsonObject* order_hash = jsonObjectGetIndex(params, 1);
1373
1374         char* sql = buildSELECT( search_hash, order_hash, meta, ctx );
1375         if (!sql) {
1376                 *err = -1;
1377                 return NULL;
1378         }
1379         
1380         osrfLogDebug(OSRF_LOG_MARK, "%s SQL =  %s", MODULENAME, sql);
1381         dbi_result result = dbi_conn_query(dbhandle, sql);
1382
1383         jsonObject* res_list = jsonParseString("[]");
1384         if(result) {
1385                 osrfLogDebug(OSRF_LOG_MARK, "Query returned with no errors");
1386
1387                 if (dbi_result_first_row(result)) {
1388                         /* JSONify the result */
1389                         osrfLogDebug(OSRF_LOG_MARK, "Query returned at least one row");
1390                         do {
1391                                 obj = oilsMakeJSONFromResult( result, meta );
1392                                 jsonObjectPush(res_list, obj);
1393                         } while (dbi_result_next_row(result));
1394                 } else {
1395                         osrfLogDebug(OSRF_LOG_MARK, "%s returned no results for query %s", MODULENAME, sql);
1396                 }
1397
1398                 /* clean up the query */
1399                 dbi_result_free(result); 
1400
1401         } else {
1402                 osrfLogError(OSRF_LOG_MARK, "%s: Error retrieving %s with query [%s]", MODULENAME, osrfHashGet(meta, "fieldmapper"), sql);
1403                 osrfAppSessionStatus(
1404                         ctx->session,
1405                         OSRF_STATUS_INTERNALSERVERERROR,
1406                         "osrfMethodException",
1407                         ctx->request,
1408                         "Severe query error -- see error log for more details"
1409                 );
1410                 *err = -1;
1411                 free(sql);
1412                 jsonObjectFree(res_list);
1413                 return jsonNULL;
1414
1415         }
1416
1417         free(sql);
1418
1419         if (res_list->size && order_hash) {
1420                 _tmp = jsonObjectGetKey( order_hash, "flesh" );
1421                 if (_tmp) {
1422                         int x = (int)jsonObjectGetNumber(_tmp);
1423
1424                         jsonObject* flesh_blob = NULL;
1425                         if ((flesh_blob = jsonObjectGetKey( order_hash, "flesh_fields" )) && x > 0) {
1426
1427                                 flesh_blob = jsonObjectClone( flesh_blob );
1428                                 jsonObject* flesh_fields = jsonObjectGetKey( flesh_blob, core_class );
1429
1430                                 osrfStringArray* link_fields = NULL;
1431
1432                                 if (flesh_fields) {
1433                                         if (flesh_fields->size == 1) {
1434                                                 char* _t = jsonObjectToSimpleString( jsonObjectGetIndex( flesh_fields, 0 ) );
1435                                                 if (!strcmp(_t,"*")) link_fields = osrfHashKeys( links );
1436                                                 free(_t);
1437                                         }
1438
1439                                         if (!link_fields) {
1440                                                 jsonObjectNode* _f;
1441                                                 link_fields = osrfNewStringArray(1);
1442                                                 jsonObjectIterator* _i = jsonNewObjectIterator( flesh_fields );
1443                                                 while ((_f = jsonObjectIteratorNext( _i ))) {
1444                                                         osrfStringArrayAdd( link_fields, jsonObjectToSimpleString( _f->item ) );
1445                                                 }
1446                                         }
1447                                 }
1448
1449                                 jsonObjectNode* cur;
1450                                 jsonObjectIterator* itr = jsonNewObjectIterator( res_list );
1451                                 while ((cur = jsonObjectIteratorNext( itr ))) {
1452
1453                                         int i = 0;
1454                                         char* link_field;
1455                                         
1456                                         while ( (link_field = osrfStringArrayGetString(link_fields, i++)) ) {
1457
1458                                                 osrfLogDebug(OSRF_LOG_MARK, "Starting to flesh %s", link_field);
1459
1460                                                 osrfHash* kid_link = osrfHashGet(links, link_field);
1461                                                 if (!kid_link) continue;
1462
1463                                                 osrfHash* field = osrfHashGet(fields, link_field);
1464                                                 if (!field) continue;
1465
1466                                                 osrfHash* value_field = field;
1467
1468                                                 osrfHash* kid_idl = osrfHashGet(idl, osrfHashGet(kid_link, "class"));
1469                                                 if (!kid_idl) continue;
1470
1471                                                 if (!(strcmp( osrfHashGet(kid_link, "reltype"), "has_many" ))) { // has_many
1472                                                         value_field = osrfHashGet( fields, osrfHashGet(meta, "primarykey") );
1473                                                 }
1474                                                         
1475                                                 if (!(strcmp( osrfHashGet(kid_link, "reltype"), "might_have" ))) { // might_have
1476                                                         value_field = osrfHashGet( fields, osrfHashGet(meta, "primarykey") );
1477                                                 }
1478
1479                                                 osrfStringArray* link_map = osrfHashGet( kid_link, "map" );
1480
1481                                                 if (link_map->size > 0) {
1482                                                         jsonObject* _kid_key = jsonParseString("[]");
1483                                                         jsonObjectPush(
1484                                                                 _kid_key,
1485                                                                 jsonNewObject( osrfStringArrayGetString( link_map, 0 ) )
1486                                                         );
1487
1488                                                         jsonObjectSetKey(
1489                                                                 flesh_blob,
1490                                                                 osrfHashGet(kid_link, "class"),
1491                                                                 _kid_key
1492                                                         );
1493                                                 };
1494
1495                                                 osrfLogDebug(
1496                                                         OSRF_LOG_MARK,
1497                                                         "Link field: %s, remote class: %s, fkey: %s, reltype: %s",
1498                                                         osrfHashGet(kid_link, "field"),
1499                                                         osrfHashGet(kid_link, "class"),
1500                                                         osrfHashGet(kid_link, "key"),
1501                                                         osrfHashGet(kid_link, "reltype")
1502                                                 );
1503
1504                                                 jsonObject* fake_params = jsonParseString("[]");
1505                                                 jsonObjectPush(fake_params, jsonParseString("{}")); // search hash
1506                                                 jsonObjectPush(fake_params, jsonParseString("{}")); // order/flesh hash
1507
1508                                                 osrfLogDebug(OSRF_LOG_MARK, "Creating dummy params object...");
1509
1510                                                 char* search_key =
1511                                                 jsonObjectToSimpleString(
1512                                                         jsonObjectGetIndex(
1513                                                                 cur->item,
1514                                                                 atoi( osrfHashGet(value_field, "array_position") )
1515                                                         )
1516                                                 );
1517
1518                                                 if (!search_key) {
1519                                                         osrfLogDebug(OSRF_LOG_MARK, "Nothing to search for!");
1520                                                         continue;
1521                                                 }
1522                                                         
1523                                                 jsonObjectSetKey(
1524                                                         jsonObjectGetIndex(fake_params, 0),
1525                                                         osrfHashGet(kid_link, "key"),
1526                                                         jsonNewObject( search_key )
1527                                                 );
1528
1529                                                 free(search_key);
1530
1531
1532                                                 jsonObjectSetKey(
1533                                                         jsonObjectGetIndex(fake_params, 1),
1534                                                         "flesh",
1535                                                         jsonNewNumberObject( (double)(x - 1 + link_map->size) )
1536                                                 );
1537
1538                                                 if (flesh_blob)
1539                                                         jsonObjectSetKey( jsonObjectGetIndex(fake_params, 1), "flesh_fields", jsonObjectClone(flesh_blob) );
1540
1541                                                 if (jsonObjectGetKey(order_hash, "order_by")) {
1542                                                         jsonObjectSetKey(
1543                                                                 jsonObjectGetIndex(fake_params, 1),
1544                                                                 "order_by",
1545                                                                 jsonObjectClone(jsonObjectGetKey(order_hash, "order_by"))
1546                                                         );
1547                                                 }
1548
1549                                                 if (jsonObjectGetKey(order_hash, "select")) {
1550                                                         jsonObjectSetKey(
1551                                                                 jsonObjectGetIndex(fake_params, 1),
1552                                                                 "select",
1553                                                                 jsonObjectClone(jsonObjectGetKey(order_hash, "select"))
1554                                                         );
1555                                                 }
1556
1557                                                 jsonObject* kids = doSearch(ctx, kid_idl, fake_params, err);
1558
1559                                                 if(*err) {
1560                                                         jsonObjectFree( fake_params );
1561                                                         osrfStringArrayFree(link_fields);
1562                                                         jsonObjectIteratorFree(itr);
1563                                                         jsonObjectFree(res_list);
1564                                                         return jsonNULL;
1565                                                 }
1566
1567                                                 osrfLogDebug(OSRF_LOG_MARK, "Search for %s return %d linked objects", osrfHashGet(kid_link, "class"), kids->size);
1568
1569                                                 jsonObject* X = NULL;
1570                                                 if ( link_map->size > 0 && kids->size > 0 ) {
1571                                                         X = kids;
1572                                                         kids = jsonParseString("[]");
1573
1574                                                         jsonObjectNode* _k_node;
1575                                                         jsonObjectIterator* _k = jsonNewObjectIterator( X );
1576                                                         while ((_k_node = jsonObjectIteratorNext( _k ))) {
1577                                                                 jsonObjectPush(
1578                                                                         kids,
1579                                                                         jsonObjectClone(
1580                                                                                 jsonObjectGetIndex(
1581                                                                                         _k_node->item,
1582                                                                                         (unsigned long)atoi(
1583                                                                                                 osrfHashGet(
1584                                                                                                         osrfHashGet(
1585                                                                                                                 osrfHashGet(
1586                                                                                                                         osrfHashGet(
1587                                                                                                                                 idl,
1588                                                                                                                                 osrfHashGet(kid_link, "class")
1589                                                                                                                         ),
1590                                                                                                                         "fields"
1591                                                                                                                 ),
1592                                                                                                                 osrfStringArrayGetString( link_map, 0 )
1593                                                                                                         ),
1594                                                                                                         "array_position"
1595                                                                                                 )
1596                                                                                         )
1597                                                                                 )
1598                                                                         )
1599                                                                 );
1600                                                         }
1601                                                 }
1602
1603                                                 if (!(strcmp( osrfHashGet(kid_link, "reltype"), "has_a" )) || !(strcmp( osrfHashGet(kid_link, "reltype"), "might_have" ))) {
1604                                                         osrfLogDebug(OSRF_LOG_MARK, "Storing fleshed objects in %s", osrfHashGet(kid_link, "field"));
1605                                                         jsonObjectSetIndex(
1606                                                                 cur->item,
1607                                                                 (unsigned long)atoi( osrfHashGet( field, "array_position" ) ),
1608                                                                 jsonObjectClone( jsonObjectGetIndex(kids, 0) )
1609                                                         );
1610                                                 }
1611
1612                                                 if (!(strcmp( osrfHashGet(kid_link, "reltype"), "has_many" ))) { // has_many
1613                                                         osrfLogDebug(OSRF_LOG_MARK, "Storing fleshed objects in %s", osrfHashGet(kid_link, "field"));
1614                                                         jsonObjectSetIndex(
1615                                                                 cur->item,
1616                                                                 (unsigned long)atoi( osrfHashGet( field, "array_position" ) ),
1617                                                                 jsonObjectClone( kids )
1618                                                         );
1619                                                 }
1620
1621                                                 if (X) {
1622                                                         jsonObjectFree(kids);
1623                                                         kids = X;
1624                                                 }
1625
1626                                                 jsonObjectFree( kids );
1627                                                 jsonObjectFree( fake_params );
1628
1629                                                 osrfLogDebug(OSRF_LOG_MARK, "Fleshing of %s complete", osrfHashGet(kid_link, "field"));
1630                                                 osrfLogDebug(OSRF_LOG_MARK, "%s", jsonObjectToJSON(cur->item));
1631
1632                                         }
1633                                 }
1634                                 jsonObjectFree( flesh_blob );
1635                                 osrfStringArrayFree(link_fields);
1636                                 jsonObjectIteratorFree(itr);
1637                         }
1638                 }
1639         }
1640
1641         return res_list;
1642 }
1643
1644
1645 jsonObject* doUpdate(osrfMethodContext* ctx, int* err ) {
1646
1647         osrfHash* meta = osrfHashGet( (osrfHash*) ctx->method->userData, "class" );
1648         jsonObject* target = jsonObjectGetIndex(ctx->params, 0);
1649
1650         if (!verifyObjectClass(ctx, target)) {
1651                 *err = -1;
1652                 return jsonNULL;
1653         }
1654
1655         if (!osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" )) {
1656                 osrfAppSessionStatus(
1657                         ctx->session,
1658                         OSRF_STATUS_BADREQUEST,
1659                         "osrfMethodException",
1660                         ctx->request,
1661                         "No active transaction -- required for UPDATE"
1662                 );
1663                 *err = -1;
1664                 return jsonNULL;
1665         }
1666
1667         dbhandle = writehandle;
1668
1669         char* trans_id = osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" );
1670
1671         // Set the last_xact_id
1672         osrfHash* last_xact_id;
1673         if ((last_xact_id = oilsIDLFindPath("/%s/fields/last_xact_id", target->classname))) {
1674                 int index = atoi( osrfHashGet(last_xact_id, "array_position") );
1675                 osrfLogDebug(OSRF_LOG_MARK, "Setting last_xact_id to %s on %s at position %d", trans_id, target->classname, index);
1676                 jsonObjectSetIndex(target, index, jsonNewObject(trans_id));
1677         }       
1678
1679         char* pkey = osrfHashGet(meta, "primarykey");
1680         osrfHash* fields = osrfHashGet(meta, "fields");
1681
1682         char* id =
1683                 jsonObjectToSimpleString(
1684                         jsonObjectGetIndex(
1685                                 target,
1686                                 atoi( osrfHashGet( osrfHashGet( fields, pkey ), "array_position" ) )
1687                         )
1688                 );
1689
1690         osrfLogDebug(
1691                 OSRF_LOG_MARK,
1692                 "%s updating %s object with %s = %s",
1693                 MODULENAME,
1694                 osrfHashGet(meta, "fieldmapper"),
1695                 pkey,
1696                 id
1697         );
1698
1699         growing_buffer* sql = buffer_init(128);
1700         buffer_fadd(sql,"UPDATE %s SET", osrfHashGet(meta, "tablename"));
1701
1702         int i = 0;
1703         int first = 1;
1704         char* field_name;
1705         osrfStringArray* field_list = osrfHashKeys( fields );
1706         while ( (field_name = osrfStringArrayGetString(field_list, i++)) ) {
1707
1708                 osrfHash* field = osrfHashGet( fields, field_name );
1709
1710                 if(!( strcmp( field_name, pkey ) )) continue;
1711                 if(!( strcmp( osrfHashGet(osrfHashGet(fields,field_name), "virtual"), "true" ) )) continue;
1712
1713                 jsonObject* field_object = jsonObjectGetIndex( target, atoi(osrfHashGet(field, "array_position")) );
1714
1715                 char* value;
1716                 if (field_object && field_object->classname) {
1717                         value = jsonObjectToSimpleString(
1718                                         jsonObjectGetIndex(
1719                                                 field_object,
1720                                                 atoi(
1721                                                         osrfHashGet(
1722                                                                 osrfHashGet(
1723                                                                         oilsIDLFindPath("/%s/fields", field_object->classname),
1724                                                                         (char*)oilsIDLFindPath("/%s/primarykey", field_object->classname)
1725                                                                 ),
1726                                                                 "array_position"
1727                                                         )
1728                                                 )
1729                                         )
1730                                 );
1731
1732                 } else {
1733                         value = jsonObjectToSimpleString( field_object );
1734                 }
1735
1736                 osrfLogDebug( OSRF_LOG_MARK, "Updating %s object with %s = %s", osrfHashGet(meta, "fieldmapper"), field_name, value);
1737
1738                 if (!field_object || field_object->type == JSON_NULL) {
1739                         if ( !(!( strcmp( osrfHashGet(meta, "classname"), "au" ) ) && !( strcmp( field_name, "passwd" ) )) ) { // arg at the special case!
1740                                 if (first) first = 0;
1741                                 else buffer_add(sql, ",");
1742                                 buffer_fadd( sql, " %s = NULL", field_name );
1743                         }
1744                         
1745                 } else if ( !strcmp(osrfHashGet(field, "primitive"), "number") ) {
1746                         if (first) first = 0;
1747                         else buffer_add(sql, ",");
1748
1749                         if ( !strncmp(osrfHashGet(field, "datatype"), "INT", (size_t)3) ) {
1750                                 buffer_fadd( sql, " %s = %ld", field_name, atol(value) );
1751                         } else if ( !strcmp(osrfHashGet(field, "datatype"), "NUMERIC") ) {
1752                                 buffer_fadd( sql, " %s = %f", field_name, atof(value) );
1753                         }
1754
1755                         osrfLogDebug( OSRF_LOG_MARK, "%s is of type %s", field_name, osrfHashGet(field, "datatype"));
1756
1757                 } else {
1758                         if ( dbi_conn_quote_string(dbhandle, &value) ) {
1759                                 if (first) first = 0;
1760                                 else buffer_add(sql, ",");
1761                                 buffer_fadd( sql, " %s = %s", field_name, value );
1762
1763                         } else {
1764                                 osrfLogError(OSRF_LOG_MARK, "%s: Error quoting string [%s]", MODULENAME, value);
1765                                 osrfAppSessionStatus(
1766                                         ctx->session,
1767                                         OSRF_STATUS_INTERNALSERVERERROR,
1768                                         "osrfMethodException",
1769                                         ctx->request,
1770                                         "Error quoting string -- please see the error log for more details"
1771                                 );
1772                                 free(value);
1773                                 free(id);
1774                                 buffer_free(sql);
1775                                 *err = -1;
1776                                 return jsonNULL;
1777                         }
1778                 }
1779
1780                 free(value);
1781                 
1782         }
1783
1784         jsonObject* obj = jsonParseString(id);
1785
1786         if ( strcmp( osrfHashGet( osrfHashGet( osrfHashGet(meta, "fields"), pkey ), "primitive" ), "number" ) )
1787                 dbi_conn_quote_string(dbhandle, &id);
1788
1789         buffer_fadd( sql, " WHERE %s = %s;", pkey, id );
1790
1791         char* query = buffer_data(sql);
1792         buffer_free(sql);
1793
1794         osrfLogDebug(OSRF_LOG_MARK, "%s: Update SQL [%s]", MODULENAME, query);
1795
1796         dbi_result result = dbi_conn_query(dbhandle, query);
1797         free(query);
1798
1799         if (!result) {
1800                 jsonObjectFree(obj);
1801                 obj = jsonNewObject(NULL);
1802                 osrfLogError(
1803                         OSRF_LOG_MARK,
1804                         "%s ERROR updating %s object with %s = %s",
1805                         MODULENAME,
1806                         osrfHashGet(meta, "fieldmapper"),
1807                         pkey,
1808                         id
1809                 );
1810         }
1811
1812         free(id);
1813
1814         return obj;
1815 }
1816
1817 jsonObject* doDelete(osrfMethodContext* ctx, int* err ) {
1818
1819         osrfHash* meta = osrfHashGet( (osrfHash*) ctx->method->userData, "class" );
1820
1821         if (!osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" )) {
1822                 osrfAppSessionStatus(
1823                         ctx->session,
1824                         OSRF_STATUS_BADREQUEST,
1825                         "osrfMethodException",
1826                         ctx->request,
1827                         "No active transaction -- required for DELETE"
1828                 );
1829                 *err = -1;
1830                 return jsonNULL;
1831         }
1832
1833         dbhandle = writehandle;
1834
1835         jsonObject* obj;
1836
1837         char* pkey = osrfHashGet(meta, "primarykey");
1838
1839         char* id;
1840         if (jsonObjectGetIndex(ctx->params, 0)->classname) {
1841                 if (!verifyObjectClass(ctx, jsonObjectGetIndex( ctx->params, 0 ))) {
1842                         *err = -1;
1843                         return jsonNULL;
1844                 }
1845
1846                 id = jsonObjectToSimpleString(
1847                         jsonObjectGetIndex(
1848                                 jsonObjectGetIndex(ctx->params, 0),
1849                                 atoi( osrfHashGet( osrfHashGet( osrfHashGet(meta, "fields"), pkey ), "array_position") )
1850                         )
1851                 );
1852         } else {
1853                 id = jsonObjectToSimpleString(jsonObjectGetIndex(ctx->params, 0));
1854         }
1855
1856         osrfLogDebug(
1857                 OSRF_LOG_MARK,
1858                 "%s deleting %s object with %s = %s",
1859                 MODULENAME,
1860                 osrfHashGet(meta, "fieldmapper"),
1861                 pkey,
1862                 id
1863         );
1864
1865         obj = jsonParseString(id);
1866
1867         if ( strcmp( osrfHashGet( osrfHashGet( osrfHashGet(meta, "fields"), pkey ), "primitive" ), "number" ) )
1868                 dbi_conn_quote_string(writehandle, &id);
1869
1870         dbi_result result = dbi_conn_queryf(writehandle, "DELETE FROM %s WHERE %s = %s;", osrfHashGet(meta, "tablename"), pkey, id);
1871
1872         if (!result) {
1873                 jsonObjectFree(obj);
1874                 obj = jsonNewObject(NULL);
1875                 osrfLogError(
1876                         OSRF_LOG_MARK,
1877                         "%s ERROR deleting %s object with %s = %s",
1878                         MODULENAME,
1879                         osrfHashGet(meta, "fieldmapper"),
1880                         pkey,
1881                         id
1882                 );
1883         }
1884
1885         free(id);
1886
1887         return obj;
1888
1889 }
1890
1891
1892 jsonObject* oilsMakeJSONFromResult( dbi_result result, osrfHash* meta) {
1893         if(!(result && meta)) return jsonNULL;
1894
1895         jsonObject* object = jsonParseString("[]");
1896         jsonObjectSetClass(object, osrfHashGet(meta, "classname"));
1897
1898         osrfHash* fields = osrfHashGet(meta, "fields");
1899
1900         osrfLogInternal(OSRF_LOG_MARK, "Setting object class to %s ", object->classname);
1901
1902         osrfHash* _f;
1903         time_t _tmp_dt;
1904         char dt_string[256];
1905         struct tm gmdt;
1906
1907         int fmIndex;
1908         int columnIndex = 1;
1909         int attr;
1910         unsigned short type;
1911         const char* columnName;
1912
1913         /* cycle through the column list */
1914         while( (columnName = dbi_result_get_field_name(result, columnIndex++)) ) {
1915
1916                 osrfLogInternal(OSRF_LOG_MARK, "Looking for column named [%s]...", (char*)columnName);
1917
1918                 fmIndex = -1; // reset the position
1919                 
1920                 /* determine the field type and storage attributes */
1921                 type = dbi_result_get_field_type(result, columnName);
1922                 attr = dbi_result_get_field_attribs(result, columnName);
1923
1924                 /* fetch the fieldmapper index */
1925                 if( (_f = osrfHashGet(fields, (char*)columnName)) ) {
1926                         char* virt = (char*)osrfHashGet(_f, "virtual");
1927                         char* pos = (char*)osrfHashGet(_f, "array_position");
1928
1929                         if ( !virt || !pos || !(strcmp( virt, "true" )) ) continue;
1930
1931                         fmIndex = atoi( pos );
1932                         osrfLogInternal(OSRF_LOG_MARK, "... Found column at position [%s]...", pos);
1933                 } else {
1934                         continue;
1935                 }
1936
1937                 if (dbi_result_field_is_null(result, columnName)) {
1938                         jsonObjectSetIndex( object, fmIndex, jsonNewObject(NULL) );
1939                 } else {
1940
1941                         switch( type ) {
1942
1943                                 case DBI_TYPE_INTEGER :
1944
1945                                         if( attr & DBI_INTEGER_SIZE8 ) 
1946                                                 jsonObjectSetIndex( object, fmIndex, 
1947                                                         jsonNewNumberObject(dbi_result_get_longlong(result, columnName)));
1948                                         else 
1949                                                 jsonObjectSetIndex( object, fmIndex, 
1950                                                         jsonNewNumberObject(dbi_result_get_long(result, columnName)));
1951
1952                                         break;
1953
1954                                 case DBI_TYPE_DECIMAL :
1955                                         jsonObjectSetIndex( object, fmIndex, 
1956                                                         jsonNewNumberObject(dbi_result_get_double(result, columnName)));
1957                                         break;
1958
1959                                 case DBI_TYPE_STRING :
1960
1961
1962                                         jsonObjectSetIndex(
1963                                                 object,
1964                                                 fmIndex,
1965                                                 jsonNewObject( dbi_result_get_string(result, columnName) )
1966                                         );
1967
1968                                         break;
1969
1970                                 case DBI_TYPE_DATETIME :
1971
1972                                         memset(dt_string, '\0', 256);
1973                                         memset(&gmdt, '\0', sizeof(gmdt));
1974                                         memset(&_tmp_dt, '\0', sizeof(_tmp_dt));
1975
1976                                         _tmp_dt = dbi_result_get_datetime(result, columnName);
1977
1978                                         localtime_r( &_tmp_dt, &gmdt );
1979
1980                                         if (!(attr & DBI_DATETIME_DATE)) {
1981                                                 strftime(dt_string, 255, "%T", &gmdt);
1982                                         } else if (!(attr & DBI_DATETIME_TIME)) {
1983                                                 strftime(dt_string, 255, "%F", &gmdt);
1984                                         } else {
1985                                                 strftime(dt_string, 255, "%FT%T%z", &gmdt);
1986                                         }
1987
1988                                         jsonObjectSetIndex( object, fmIndex, jsonNewObject(dt_string) );
1989
1990                                         break;
1991
1992                                 case DBI_TYPE_BINARY :
1993                                         osrfLogError( OSRF_LOG_MARK, 
1994                                                 "Can't do binary at column %s : index %d", columnName, columnIndex - 1);
1995                         }
1996                 }
1997         }
1998
1999         return object;
2000 }
2001