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