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