]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/c-apps/oils_cstore.c
allowing non-numeric pkeys for search
[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 dispatchCRUDMethod ( osrfMethodContext* );
31 jsonObject* doCreate ( osrfHash*, jsonObject* );
32 jsonObject* doRetrieve ( osrfHash*, jsonObject* );
33 jsonObject* doUpdate ( osrfHash*, jsonObject* );
34 jsonObject* doDelete ( osrfHash*, jsonObject* );
35 jsonObject* oilsMakeJSONFromResult( dbi_result, osrfHash* );
36
37 dbi_conn dbhandle; /* our db connection */
38 xmlDocPtr idlDoc = NULL; // parse and store the IDL here
39
40
41 /* parse and store the IDL here */
42 osrfHash* idlHash;
43
44 int osrfAppInitialize() {
45
46         idlHash = osrfNewHash();
47
48         osrfLogInfo(OSRF_LOG_MARK, "Initializing the CStore Server...");
49         osrfLogInfo(OSRF_LOG_MARK, "Finding XML file...");
50
51         char * idl_filename = osrf_settings_host_value("/apps/%s/app_settings/IDL", MODULENAME);
52         osrfLogInfo(OSRF_LOG_MARK, "Found file:");
53         osrfLogInfo(OSRF_LOG_MARK, idl_filename);
54
55         osrfLogInfo(OSRF_LOG_MARK, "Parsing the IDL XML...");
56         idlDoc = xmlReadFile( idl_filename, NULL, XML_PARSE_XINCLUDE );
57         
58         if (!idlDoc) {
59                 osrfLogError(OSRF_LOG_MARK, "Could not load or parse the IDL XML file!");
60                 exit(1);
61         }
62
63         osrfLogInfo(OSRF_LOG_MARK, "...IDL XML parsed");
64
65         osrfStringArray* global_methods = osrfNewStringArray(1);
66
67         //osrfStringArrayAdd( global_methods, "create" );
68         osrfStringArrayAdd( global_methods, "retrieve" );
69         //osrfStringArrayAdd( global_methods, "update" );
70         //osrfStringArrayAdd( global_methods, "delete" );
71
72         xmlNodePtr docRoot = xmlDocGetRootElement(idlDoc);
73         xmlNodePtr kid = docRoot->children;
74         while (kid) {
75                 if (!strcmp( (char*)kid->name, "class" )) {
76                         int i = 0; 
77                         char* method_type;
78                         while ( (method_type = osrfStringArrayGetString(global_methods, i++)) ) {
79
80                                 osrfHash * usrData = osrfNewHash();
81                                 osrfHashSet( usrData, xmlGetProp(kid, "id"), "classname");
82                                 osrfHashSet( usrData, xmlGetNsProp(kid, "tablename", PERSIST_NS), "tablename");
83                                 osrfHashSet( usrData, xmlGetNsProp(kid, "fieldmapper", OBJECT_NS), "fieldmapper");
84
85                                 if(!strcmp(method_type, "retrieve"))
86                                         osrfHashSet( idlHash, usrData, (char*)osrfHashGet(usrData, "classname") );
87
88                                 osrfLogInfo(OSRF_LOG_MARK, "Generating class methods for %s", osrfHashGet(usrData, "fieldmapper") );
89
90                                 osrfHash* _tmp;
91                                 osrfHash* links = osrfNewHash();
92                                 osrfHash* fields = osrfNewHash();
93
94                                 osrfHashSet( usrData, fields, "fields" );
95                                 osrfHashSet( usrData, links, "links" );
96
97                                 xmlNodePtr _cur = kid->children;
98
99                                 while (_cur) {
100                                         char* string_tmp = NULL;
101
102                                         if (!strcmp( (char*)_cur->name, "fields" )) {
103
104                                                 if( (string_tmp = (char*)xmlGetNsProp(_cur, "primary", PERSIST_NS)) ) {
105                                                         osrfHashSet(
106                                                                 usrData,
107                                                                 strdup( string_tmp ),
108                                                                 "primarykey"
109                                                         );
110                                                 }
111                                                 string_tmp = NULL;
112
113                                                 xmlNodePtr _f = _cur->children;
114
115                                                 while(_f) {
116                                                         if (strcmp( (char*)_f->name, "field" )) {
117                                                                 _f = _f->next;
118                                                                 continue;
119                                                         }
120
121                                                         _tmp = osrfNewHash();
122
123                                                         if( (string_tmp = (char*)xmlGetNsProp(_f, "array_position", OBJECT_NS)) ) {
124                                                                 osrfHashSet(
125                                                                         _tmp,
126                                                                         strdup( string_tmp ),
127                                                                         "array_position"
128                                                                 );
129                                                         }
130                                                         string_tmp = NULL;
131
132                                                         if( (string_tmp = (char*)xmlGetNsProp(_f, "virtual", PERSIST_NS)) ) {
133                                                                 osrfHashSet(
134                                                                         _tmp,
135                                                                         strdup( string_tmp ),
136                                                                         "virtual"
137                                                                 );
138                                                         }
139                                                         string_tmp = NULL;
140
141                                                         if( (string_tmp = (char*)xmlGetProp(_f, "name")) ) {
142                                                                 osrfHashSet(
143                                                                         _tmp,
144                                                                         strdup( string_tmp ),
145                                                                         "name"
146                                                                 );
147                                                         }
148
149                                                         osrfLogInfo(OSRF_LOG_MARK, "Found field %s for class %s", string_tmp, osrfHashGet(usrData, "classname") );
150
151                                                         osrfHashSet(
152                                                                 fields,
153                                                                 _tmp,
154                                                                 strdup( string_tmp )
155                                                         );
156                                                         _f = _f->next;
157                                                 }
158                                         }
159
160                                         if (!strcmp( (char*)_cur->name, "links" )) {
161                                                 xmlNodePtr _l = _cur->children;
162
163                                                 while(_l) {
164                                                         if (strcmp( (char*)_l->name, "link" )) {
165                                                                 _l = _l->next;
166                                                                 continue;
167                                                         }
168
169                                                         _tmp = osrfNewHash();
170
171                                                         if( (string_tmp = (char*)xmlGetProp(_l, "reltype")) ) {
172                                                                 osrfHashSet(
173                                                                         _tmp,
174                                                                         strdup( string_tmp ),
175                                                                         "reltype"
176                                                                 );
177                                                         }
178                                                         osrfLogInfo(OSRF_LOG_MARK, "Adding link with reltype %s", string_tmp );
179                                                         string_tmp = NULL;
180
181                                                         if( (string_tmp = (char*)xmlGetProp(_l, "key")) ) {
182                                                                 osrfHashSet(
183                                                                         _tmp,
184                                                                         strdup( string_tmp ),
185                                                                         "key"
186                                                                 );
187                                                         }
188                                                         osrfLogInfo(OSRF_LOG_MARK, "Link fkey is %s", string_tmp );
189                                                         string_tmp = NULL;
190
191                                                         if( (string_tmp = (char*)xmlGetProp(_l, "class")) ) {
192                                                                 osrfHashSet(
193                                                                         _tmp,
194                                                                         strdup( string_tmp ),
195                                                                         "class"
196                                                                 );
197                                                         }
198                                                         osrfLogInfo(OSRF_LOG_MARK, "Link fclass is %s", string_tmp );
199                                                         string_tmp = NULL;
200
201                                                         osrfStringArray* map = osrfNewStringArray(0);
202
203                                                         if( (string_tmp = (char*)xmlGetProp(_l, "map") )) {
204                                                                 char* map_list = strdup( string_tmp );
205                                                                 osrfLogInfo(OSRF_LOG_MARK, "Link mapping list is %s", string_tmp );
206
207                                                                 if (strlen( map_list ) > 0) {
208                                                                         char* st_tmp;
209                                                                         char* _map_class = strtok_r(map_list, " ", &st_tmp);
210                                                                         osrfStringArrayAdd(map, strdup(_map_class));
211                                                         
212                                                                         while ((_map_class = strtok_r(NULL, " ", &st_tmp))) {
213                                                                                 osrfStringArrayAdd(map, strdup(_map_class));
214                                                                         }
215                                                                 }
216                                                         }
217                                                         osrfHashSet( _tmp, map, "map");
218
219                                                         if( (string_tmp = (char*)xmlGetProp(_l, "field")) ) {
220                                                                 osrfHashSet(
221                                                                         _tmp,
222                                                                         strdup( string_tmp ),
223                                                                         "field"
224                                                                 );
225                                                         }
226
227                                                         osrfHashSet(
228                                                                 links,
229                                                                 _tmp,
230                                                                 strdup( string_tmp )
231                                                         );
232
233                                                         osrfLogInfo(OSRF_LOG_MARK, "Found link %s for class %s", string_tmp, osrfHashGet(usrData, "classname") );
234
235                                                         _l = _l->next;
236                                                 }
237                                         }
238
239                                         _cur = _cur->next;
240                                 }
241
242
243                                 char* st_tmp;
244                                 char* _fm;
245                                 if (!osrfHashGet(usrData, "fieldmapper")) continue;
246
247                                 _fm = strdup( (char*)osrfHashGet(usrData, "fieldmapper") );
248                                 char* part = strtok_r(_fm, ":", &st_tmp);
249
250                                 growing_buffer* method_name =  buffer_init(64);
251                                 buffer_fadd(method_name, "%s.direct.%s", MODULENAME, part);
252
253                                 while ((part = strtok_r(NULL, ":", &st_tmp))) {
254                                         buffer_fadd(method_name, ".%s", part);
255                                 }
256                                 buffer_fadd(method_name, ".%s", method_type);
257
258                                 char* method = buffer_data(method_name);
259                                 buffer_free(method_name);
260
261                                 osrfHashSet( usrData, method, "methodname" );
262                                 osrfHashSet( usrData, strdup(method_type), "methodtype" );
263
264                                 osrfAppRegisterExtendedMethod(
265                                         MODULENAME,
266                                         method,
267                                         "dispatchCRUDMethod",
268                                         "",
269                                         1,
270                                         0,
271                                         (void*)usrData
272                                 );
273                         }
274                 }
275                 kid = kid->next;
276         }
277
278         return 0;
279 }
280
281 /**
282  * Connects to the database 
283  */
284 int osrfAppChildInit() {
285
286         osrfLogDebug(OSRF_LOG_MARK, "Attempting to initialize libdbi...");
287         dbi_initialize(NULL);
288         osrfLogDebug(OSRF_LOG_MARK, "... libdbi initialized.");
289
290         char* driver    = osrf_settings_host_value("/apps/%s/app_settings/driver", MODULENAME);
291         char* user      = osrf_settings_host_value("/apps/%s/app_settings/database/user", MODULENAME);
292         char* host      = osrf_settings_host_value("/apps/%s/app_settings/database/host", MODULENAME);
293         char* port      = osrf_settings_host_value("/apps/%s/app_settings/database/port", MODULENAME);
294         char* db        = osrf_settings_host_value("/apps/%s/app_settings/database/db", MODULENAME);
295         char* pw        = osrf_settings_host_value("/apps/%s/app_settings/database/pw", MODULENAME);
296
297         osrfLogDebug(OSRF_LOG_MARK, "Attempting to load the database driver [%s]...", driver);
298         dbhandle = dbi_conn_new(driver);
299
300         if(!dbhandle) {
301                 osrfLogError(OSRF_LOG_MARK, "Error loading database driver [%s]", driver);
302                 return -1;
303         }
304         osrfLogDebug(OSRF_LOG_MARK, "Database driver [%s] seems OK", driver);
305
306         osrfLogInfo(OSRF_LOG_MARK, "%s connecting to database.  host=%s, "
307                 "port=%s, user=%s, pw=%s, db=%s", MODULENAME, host, port, user, pw, db );
308
309         if(host) dbi_conn_set_option(dbhandle, "host", host );
310         if(port) dbi_conn_set_option_numeric( dbhandle, "port", atoi(port) );
311         if(user) dbi_conn_set_option(dbhandle, "username", user);
312         if(pw) dbi_conn_set_option(dbhandle, "password", pw );
313         if(db) dbi_conn_set_option(dbhandle, "dbname", db );
314
315         free(user);
316         free(host);
317         free(port);
318         free(db);
319         free(pw);
320
321         const char* err;
322         if (dbi_conn_connect(dbhandle) < 0) {
323                 dbi_conn_error(dbhandle, &err);
324                 osrfLogError( OSRF_LOG_MARK, "Error connecting to database: %s", err);
325                 return -1;
326         }
327
328         osrfLogInfo(OSRF_LOG_MARK, "%s successfully connected to the database", MODULENAME);
329
330         int attr;
331         unsigned short type;
332         int i = 0; 
333         char* classname;
334         osrfStringArray* classes = osrfHashKeys( idlHash );
335         
336         while ( (classname = osrfStringArrayGetString(classes, i++)) ) {
337                 osrfHash* class = osrfHashGet( idlHash, classname );
338                 osrfHash* fields = osrfHashGet( class, "fields" );
339                 
340                 growing_buffer* sql_buf = buffer_init(32);
341                 buffer_fadd( sql_buf, "SELECT * FROM %s WHERE 1=0;", osrfHashGet(class, "tablename") );
342
343                 char* sql = buffer_data(sql_buf);
344                 buffer_free(sql_buf);
345                 osrfLogDebug(OSRF_LOG_MARK, "%s Investigatory SQL = %s", MODULENAME, sql);
346
347                 dbi_result result = dbi_conn_query(dbhandle, sql);
348                 free(sql);
349
350                 if (result) {
351
352                         int columnIndex = 1;
353                         const char* columnName;
354                         osrfHash* _f;
355                         while( (columnName = dbi_result_get_field_name(result, columnIndex++)) ) {
356
357                                 osrfLogDebug(OSRF_LOG_MARK, "Looking for column named [%s]...", (char*)columnName);
358
359                                 /* fetch the fieldmapper index */
360                                 if( (_f = osrfHashGet(fields, (char*)columnName)) ) {
361
362                                         osrfLogDebug(OSRF_LOG_MARK, "Found [%s] in IDL hash...", (char*)columnName);
363
364                                         /* determine the field type and storage attributes */
365                                         type = dbi_result_get_field_type(result, columnName);
366                                         attr = dbi_result_get_field_attribs(result, columnName);
367
368                                         switch( type ) {
369
370                                                 case DBI_TYPE_INTEGER :
371
372                                                         osrfHashSet(_f,"number", "primitive");
373
374                                                         if( attr & DBI_INTEGER_SIZE8 ) 
375                                                                 osrfHashSet(_f,"INT8", "datatype");
376                                                         else 
377                                                                 osrfHashSet(_f,"INT", "datatype");
378                                                         break;
379
380                                                 case DBI_TYPE_DECIMAL :
381                                                         osrfHashSet(_f,"number", "primitive");
382                                                         osrfHashSet(_f,"NUMERIC", "datatype");
383                                                         break;
384
385                                                 case DBI_TYPE_STRING :
386                                                         osrfHashSet(_f,"string", "primitive");
387                                                         osrfHashSet(_f,"TEXT", "datatype");
388                                                         break;
389
390                                                 case DBI_TYPE_DATETIME :
391                                                         osrfHashSet(_f,"string", "primitive");
392                                                         osrfHashSet(_f,"TIMESTAMP", "datatype");
393                                                         break;
394
395                                                 case DBI_TYPE_BINARY :
396                                                         osrfHashSet(_f,"string", "primitive");
397                                                         osrfHashSet(_f,"BYTEA", "datatype");
398                                         }
399
400                                         osrfLogDebug(
401                                                 OSRF_LOG_MARK,
402                                                 "Setting [%s] to primitive [%s] and datatype [%s]...",
403                                                 (char*)columnName,
404                                                 osrfHashGet(_f, "primitive"),
405                                                 osrfHashGet(_f, "datatype")
406                                         );
407                                 }
408                         }
409                         dbi_result_free(result);
410                 } else {
411                         osrfLogDebug(OSRF_LOG_MARK, "No data found for class [%s]...", (char*)classname);
412                 }
413         }
414
415         osrfStringArrayFree(classes);
416
417         return 0;
418 }
419
420
421 int dispatchCRUDMethod ( osrfMethodContext* ctx ) {
422         OSRF_METHOD_VERIFY_CONTEXT(ctx);
423
424         osrfHash* meta = (osrfHash*) ctx->method->userData;
425
426         jsonObject * obj = NULL;
427         if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "create"))
428                 obj = doCreate(meta, ctx->params);
429
430         if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "retrieve"))
431                 obj = doRetrieve(meta, ctx->params);
432
433         if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "update"))
434                 obj = doUpdate(meta, ctx->params);
435
436         if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "delete"))
437                 obj = doDelete(meta, ctx->params);
438
439         osrfAppRespondComplete( ctx, obj );
440
441         jsonObjectFree(obj);
442
443         return 0;
444 }
445
446 jsonObject* doCreate( osrfHash* meta, jsonObject* params ) { return NULL; }
447
448 jsonObject* doRetrieve( osrfHash* meta, jsonObject* params ) {
449
450         jsonObject* obj;
451         char* id = jsonObjectToSimpleString(jsonObjectGetIndex(params, 0));
452
453         osrfLogDebug(
454                 OSRF_LOG_MARK,
455                 "%s retrieving %s object with id %s",
456                 MODULENAME,
457                 osrfHashGet(meta, "fieldmapper"),
458                 id
459         );
460
461         char* pkey = osrfHashGet(meta, "primarykey");
462         osrfHash* field = osrfHashGet( osrfHashGet(meta, "fields"), pkey );
463
464
465         growing_buffer* sql_buf = buffer_init(128);
466         if ( !strcmp(osrfHashGet(field, "primitive"), "number") ) {
467                 buffer_fadd(
468                         sql_buf,
469                         "SELECT * FROM %s WHERE %s = %d;",
470                         osrfHashGet(meta, "tablename"),
471                         osrfHashGet(meta, "primarykey"),
472                         atoi(id)
473                 );
474         } else {
475                 char* key_string;
476                 if ( dbi_conn_quote_string_copy(dbhandle, id, &key_string) ) {
477                         buffer_fadd(
478                                 sql_buf,
479                                 "SELECT * FROM %s WHERE %s = %s;",
480                                 osrfHashGet(meta, "tablename"),
481                                 osrfHashGet(meta, "primarykey"),
482                                 key_string
483                         );
484                 } else {
485                         obj = jsonNewObject(NULL);
486                         osrfLogDebug(OSRF_LOG_MARK, "%s: Error quoting key string [%s]", MODULENAME, id);
487                 }
488         }
489
490         char* sql = buffer_data(sql_buf);
491         buffer_free(sql_buf);
492         
493         osrfLogDebug(OSRF_LOG_MARK, "%s SQL =  %s", MODULENAME, sql);
494
495         dbi_result result = dbi_conn_query(dbhandle, sql);
496
497         if(result) {
498                 osrfLogDebug(OSRF_LOG_MARK, "Query returned with no errors");
499
500                 /* there should be one row at the most  */
501                 if (dbi_result_first_row(result)) {
502                         /* JSONify the result */
503                         osrfLogDebug(OSRF_LOG_MARK, "Query returned at least one row");
504                         obj = oilsMakeJSONFromResult( result, meta );
505                 } else {
506                         osrfLogDebug(OSRF_LOG_MARK, "%s returned no results for query %s", MODULENAME, sql);
507                         obj = jsonNewObject(NULL);
508                 }
509
510                 /* clean up the query */
511                 dbi_result_free(result); 
512
513         } else {
514                 obj = jsonNewObject(NULL);
515                 osrfLogDebug(OSRF_LOG_MARK, "%s: Error retrieving %s with key %s", MODULENAME, osrfHashGet(meta, "fieldmapper"), id);
516         }
517
518         free(sql);
519         free(id);
520
521         return obj;
522 }
523
524
525 jsonObject* doUpdate( osrfHash* meta, jsonObject* params ) { return NULL; }
526
527 jsonObject* doDelete( osrfHash* meta, jsonObject* params ) { return NULL; }
528
529
530 jsonObject* oilsMakeJSONFromResult( dbi_result result, osrfHash* meta) {
531         if(!(result && meta)) return NULL;
532
533         jsonObject* object = jsonParseString("[]");
534         jsonObjectSetClass(object, osrfHashGet(meta, "classname"));
535
536         osrfHash* fields = osrfHashGet(meta, "fields");
537
538         osrfLogDebug(OSRF_LOG_MARK, "Setting object class to %s ", object->classname);
539
540         osrfHash* _f;
541         time_t _tmp_dt;
542         char dt_string[256];
543         struct tm gmdt;
544
545         int fmIndex;
546         int columnIndex = 1;
547         int attr;
548         unsigned short type;
549         const char* columnName;
550
551         /* cycle through the column list */
552         while( (columnName = dbi_result_get_field_name(result, columnIndex++)) ) {
553
554                 osrfLogDebug(OSRF_LOG_MARK, "Looking for column named [%s]...", (char*)columnName);
555
556                 fmIndex = -1; // reset the position
557                 
558                 /* determine the field type and storage attributes */
559                 type = dbi_result_get_field_type(result, columnName);
560                 attr = dbi_result_get_field_attribs(result, columnName);
561
562                 /* fetch the fieldmapper index */
563                 if( (_f = osrfHashGet(fields, (char*)columnName)) ) {
564                         char* virt = (char*)osrfHashGet(_f, "virtual");
565                         char* pos = (char*)osrfHashGet(_f, "array_position");
566
567                         if ( !virt || !pos || !(strcmp( virt, "true" )) ) continue;
568
569                         fmIndex = atoi( pos );
570                         osrfLogDebug(OSRF_LOG_MARK, "... Found column at position [%s]...", pos);
571                 }
572
573                 if (dbi_result_field_is_null(result, columnName)) {
574                         jsonObjectSetIndex( object, fmIndex, jsonNewObject(NULL) );
575                 } else {
576
577                         switch( type ) {
578
579                                 case DBI_TYPE_INTEGER :
580
581                                         if( attr & DBI_INTEGER_SIZE8 ) 
582                                                 jsonObjectSetIndex( object, fmIndex, 
583                                                         jsonNewNumberObject(dbi_result_get_longlong(result, columnName)));
584                                         else 
585                                                 jsonObjectSetIndex( object, fmIndex, 
586                                                         jsonNewNumberObject(dbi_result_get_long(result, columnName)));
587
588                                         break;
589
590                                 case DBI_TYPE_DECIMAL :
591                                         jsonObjectSetIndex( object, fmIndex, 
592                                                         jsonNewNumberObject(dbi_result_get_double(result, columnName)));
593                                         break;
594
595                                 case DBI_TYPE_STRING :
596
597
598                                         jsonObjectSetIndex(
599                                                 object,
600                                                 fmIndex,
601                                                 jsonNewObject( dbi_result_get_string(result, columnName) )
602                                         );
603
604                                         break;
605
606                                 case DBI_TYPE_DATETIME :
607
608                                         memset(dt_string, '\0', 256);
609                                         memset(&gmdt, '\0', sizeof(gmdt));
610                                         memset(&_tmp_dt, '\0', sizeof(_tmp_dt));
611
612                                         _tmp_dt = dbi_result_get_datetime(result, columnName);
613
614                                         localtime_r( &_tmp_dt, &gmdt );
615
616                                         if (!(attr & DBI_DATETIME_DATE)) {
617                                                 strftime(dt_string, 255, "%T", &gmdt);
618                                         } else if (!(attr & DBI_DATETIME_TIME)) {
619                                                 strftime(dt_string, 255, "%F", &gmdt);
620                                         } else {
621                                                 /* XXX ARG! My eyes! The goggles, they do nothing! */
622
623                                                 strftime(dt_string, 255, "%FT%T%z", &gmdt);
624                                         }
625
626                                         jsonObjectSetIndex( object, fmIndex, jsonNewObject(dt_string) );
627
628                                         break;
629
630                                 case DBI_TYPE_BINARY :
631                                         osrfLogError( OSRF_LOG_MARK, 
632                                                 "Can't do binary at column %s : index %d", columnName, columnIndex - 1);
633                         }
634                 }
635         }
636
637         return object;
638 }
639