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