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