openbase 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. data/History.txt +50 -0
  2. data/License.txt +20 -0
  3. data/Manifest.txt +53 -0
  4. data/README.txt +35 -0
  5. data/Rakefile +126 -0
  6. data/examples/example.rb +37 -0
  7. data/ext/CommAPI.c +643 -0
  8. data/ext/Headers/CommAPI.h +1 -0
  9. data/ext/Headers/NetClient.h +42 -0
  10. data/ext/Headers/NetClientLib.h +41 -0
  11. data/ext/Headers/OB_Memory.h +69 -0
  12. data/ext/Headers/OpenBaseAdmin.h +227 -0
  13. data/ext/Headers/OpenBaseConnection.h +337 -0
  14. data/ext/Headers/OpenBaseEncoding.h +302 -0
  15. data/ext/Headers/OpenBasePrepare.h +1 -0
  16. data/ext/Headers/OpenBaseSupport.h +1 -0
  17. data/ext/Headers/Platform_Carbon_Header.h +5 -0
  18. data/ext/Headers/Platform_Classic_Header.h +6 -0
  19. data/ext/Headers/Platform_Linux.h +4 -0
  20. data/ext/Headers/Platform_Mach_Header.h +4 -0
  21. data/ext/Headers/Platform_Windows.h +3 -0
  22. data/ext/Headers/conversion.h +1 -0
  23. data/ext/Headers/datetime.h +26 -0
  24. data/ext/Headers/longlong.h +46 -0
  25. data/ext/Headers/platform.h +67 -0
  26. data/ext/Headers/stringConversion.h +15 -0
  27. data/ext/NetClient.c +888 -0
  28. data/ext/OpenBaseAdmin.c +1884 -0
  29. data/ext/OpenBaseConnection.c +1841 -0
  30. data/ext/OpenBaseEncoding.c +993 -0
  31. data/ext/OpenBaseEncoding_DOS.c +1 -0
  32. data/ext/OpenBaseEncoding_ISO8859.c +1 -0
  33. data/ext/OpenBaseEncoding_MacOS.c +1 -0
  34. data/ext/OpenBaseEncoding_Windows.c +1150 -0
  35. data/ext/OpenBasePrepare.c +1 -0
  36. data/ext/OpenBaseSupport.c +1 -0
  37. data/ext/conversion.c +1 -0
  38. data/ext/datetime.c +816 -0
  39. data/ext/depend +1 -0
  40. data/ext/extconf.rb +10 -0
  41. data/ext/longlong.c +1 -0
  42. data/ext/openbase.c +980 -0
  43. data/ext/stringConversion.c +169 -0
  44. data/lib/ruby-openbase/version.rb +9 -0
  45. data/scripts/txt2html +67 -0
  46. data/setup.rb +1585 -0
  47. data/test/test_helper.rb +2 -0
  48. data/test/test_openbase.rb +241 -0
  49. data/website/index.html +114 -0
  50. data/website/index.txt +59 -0
  51. data/website/javascripts/rounded_corners_lite.inc.js +285 -0
  52. data/website/stylesheets/screen.css +133 -0
  53. data/website/template.rhtml +47 -0
  54. metadata +105 -0
@@ -0,0 +1,1841 @@
1
+ // ------------------------------------------------------------------------------
2
+ //
3
+ // Copyright (c) 1996-2006 OpenBase International Ltd.
4
+ // All rights reserved.
5
+ //
6
+ // ------------------------------------------------------------------------------
7
+ //
8
+ // [jsh] 11/07/2003
9
+ // Added missing prototypes.
10
+ // Factored ob_newNetConn function out of ob_newConnection.
11
+ // Moved ob_releaseBuffers and releasConnBuffers here from OT_NetClient.cpp,
12
+ // replacing redundant code in ob_newConnection.
13
+ // Added const keyword to bind functions.
14
+ // Replaced pointer typedefs.
15
+ // Other miscellaneous changes.
16
+ // Limited the number of attempts at autoreconnection.
17
+ // Added date and time formatting preferences.
18
+ //
19
+ // ----------------------------------------------------------------------------
20
+ #include "platform.h"
21
+
22
+ #include "OpenBaseConnection.h"
23
+ #include "OpenBaseEncoding.h"
24
+
25
+ #include <stdio.h>
26
+ #include <stdlib.h>
27
+ #include <string.h>
28
+
29
+ #ifdef MACOS_CARBON
30
+ #include <Processes.h>
31
+ #include <Threads.h>
32
+ #include "MacCarbon_NetClient.h"
33
+ #endif
34
+
35
+ #ifdef WINNT
36
+ #include "AllOthers_NetClient.h"
37
+ #endif
38
+ #ifdef LINUX
39
+ #include "AllOthers_NetClient.h"
40
+ #endif
41
+
42
+
43
+ #ifndef _OB_MEMORY_H
44
+ #include "OB_Memory.h"
45
+ #endif
46
+
47
+ #include "longlong.h"
48
+ #include "OpenBaseSupport.h"
49
+ #include "OpenBasePrepare.h"
50
+
51
+ #include "CommAPI.h"
52
+ #include "conversion.h"
53
+
54
+ // ----------------------------------------------------------------------------
55
+
56
+ #define YIELD_THREAD /*YieldToAnyThread()*/
57
+ #define OB_DEALLOC(ptr) if (ptr) { free(ptr); ptr = NULL; }
58
+
59
+ //[jsh] 11/07/2003 New. Replaced some magic numbers.
60
+ #define DICTIONARY_BUFFER_SIZE 500
61
+ #define SQL_BUFFER_SIZE 500
62
+
63
+ void _setErrorMessage(OpenBasePtr conn, int errorCode); // ��dmr
64
+ void _initEncoding(OpenBasePtr conn);
65
+ int _ob_connectToDatabase(OpenBasePtr conn, char *databaseName, char *databaseHost, int *returnCode, int secondaryConnectionFlag); //[jsh] 11/07/2003
66
+ int _ob_executeCommand(OpenBasePtr conn); //[jsh] 11/07/2003
67
+ static void releasConnBuffers(NetConnPtr conn); //[jsh] 11/07/2003
68
+
69
+ // -----------------------------------------------------------------------------
70
+ // date and time formatting used in ob_nextCursorRow
71
+ // -----------------------------------------------------------------------------
72
+
73
+ static int dateFormatType = dateFormat_D_dot_M_dot_YYYY;
74
+ static int timeFormatType = timeFormat_0H_colon_0M;
75
+
76
+ int getDateFormatType()
77
+ {
78
+ return dateFormatType;
79
+ }
80
+
81
+ void setDateFormatType(int dateFormat)
82
+ {
83
+ dateFormatType = dateFormat;
84
+ }
85
+
86
+ int getTimeFormatType()
87
+ {
88
+ return timeFormatType;
89
+ }
90
+
91
+ void setTimeFormatType(int timeFormat)
92
+ {
93
+ timeFormatType = timeFormat;
94
+ }
95
+
96
+
97
+ // -----------------------------------------------------------------------------
98
+ // encoding conversion
99
+ // -----------------------------------------------------------------------------
100
+ int convertStringToDatabaseEncoding(OpenBasePtr conn, const char *source, char *target)
101
+ {
102
+ unsigned char *result = NULL;
103
+ int len = strlen(source);
104
+
105
+ if (conn->clientEncoding == 0) {
106
+ strcpy(target, source);
107
+ return strlen(target);
108
+ }
109
+
110
+ result = (unsigned char *)ob_convertCharacters(conn->clientEncoding, conn->databaseEncoding, (const unsigned char *)source, &len);
111
+ strncpy(target, (char *)result, len);
112
+ free(result);
113
+ target[len] = '\0';
114
+ return len;
115
+ }
116
+
117
+ int convertStringFromDatabaseEncoding(OpenBasePtr conn, const char *source, char *target)
118
+ {
119
+ unsigned char *result = NULL;
120
+ int len = strlen(source);
121
+
122
+ if (conn->clientEncoding == 0) {
123
+ strcpy(target, source);
124
+ return strlen(target);
125
+ }
126
+ result = (unsigned char *)ob_convertCharacters(conn->databaseEncoding, conn->clientEncoding, (const unsigned char *)source, &len);
127
+ strncpy(target, (char *)result, len);
128
+ free(result);
129
+ target[len] = '\0';
130
+ return len;
131
+ }
132
+
133
+ int convertStringToDatabaseEncodingLength(OpenBasePtr conn, const char *source, char *target, int len)
134
+ {
135
+ unsigned char *result = NULL;
136
+
137
+ if (conn->clientEncoding == 0) {
138
+ strncpy(target, source, len);
139
+ target[len] = '\0';
140
+ return len;
141
+ }
142
+
143
+ result = (unsigned char *)ob_convertCharacters(conn->clientEncoding, conn->databaseEncoding, (const unsigned char *)source, &len);
144
+ strcpy(target, (char *)result);
145
+ free(result);
146
+ return len;
147
+ }
148
+
149
+
150
+ int convertStringFromDatabaseEncodingLength(OpenBasePtr conn, const char *source, char *target, int len)
151
+ {
152
+ unsigned char *result = NULL;
153
+
154
+ if (conn->clientEncoding == 0) {
155
+ strncpy(target, source, len);
156
+ target[len] = '\0';
157
+ return len;
158
+ }
159
+
160
+ result = (unsigned char *)ob_convertCharacters(conn->databaseEncoding, conn->clientEncoding, (const unsigned char *)source, &len);
161
+ strncpy(target, (char *)result, len);
162
+ free(result);
163
+ target[len] = '\0';
164
+ return len;
165
+ }
166
+
167
+ int ob_databaseEncoding(OpenBasePtr conn)
168
+ {
169
+ return conn->databaseEncoding;
170
+ }
171
+
172
+ int ob_clientEncoding(OpenBasePtr conn)
173
+ {
174
+ return conn->clientEncoding;
175
+ }
176
+
177
+ void ob_setClientEncoding(OpenBasePtr conn, int encoding)
178
+ {
179
+ conn->clientEncoding = encoding;
180
+ }
181
+
182
+
183
+ void _initEncoding(OpenBasePtr conn)
184
+ {
185
+ int len;
186
+ char* result;
187
+
188
+ conn->databaseEncoding = OB_ENCODING_ASCII;
189
+
190
+ prepareDictionary (conn->connection);
191
+ addDictionaryPair (conn->connection, "action", "call_getencoding");
192
+ if (sendBuffer (conn->connection) == 0)
193
+ {
194
+ return;
195
+ }
196
+ YIELD_THREAD;
197
+ if (readResult (conn->connection) == 0)
198
+ {
199
+ return;
200
+ }
201
+
202
+ result = resultValueForKey (conn->connection, "encoding", &len);
203
+
204
+ if (result != NULL)
205
+ {
206
+ if (strcmp(result,"NSISOLatin1StringEncoding") == 0) {
207
+ conn->databaseEncoding = OB_ENCODING_LATIN1;
208
+ } else if (strcmp(result,"NSISOLatin2StringEncoding") == 0) {
209
+ conn->databaseEncoding = OB_ENCODING_LATIN2;
210
+ } else if (strcmp(result,"NSNEXTSTEPStringEncoding") == 0) {
211
+ conn->databaseEncoding = OB_ENCODING_ASCII;
212
+ } else if (strcmp(result,"NSISO2022JPStringEncoding") == 0) {
213
+ conn->databaseEncoding = OB_ENCODING_ISO2022JP;
214
+ } else if (strcmp(result,"NSJapaneseEUCStringEncoding") == 0) {
215
+ conn->databaseEncoding = OB_ENCODING_EUC;
216
+ } else if (strcmp(result,"NSShiftJISStringEncoding") == 0) {
217
+ conn->databaseEncoding = OB_ENCODING_SHIFTJIS;
218
+ } else if (strcmp(result,"NSUTF8StringEncoding") == 0) {
219
+ conn->databaseEncoding = OB_ENCODING_UTF8;
220
+ } else if (strcmp(result,"NSNonLossyASCIIStringEncoding") == 0) {
221
+ conn->databaseEncoding = OB_ENCODING_UNICODE;
222
+ }
223
+ }
224
+
225
+ return;
226
+ }
227
+
228
+ //Allocates memory for a page of result data for an OpenBaseCursor. The page does
229
+ //not initially contain any data, which is ultimately stored in resultData.
230
+ //resultData may be filled with a data block that is owned by the cursor, in which case
231
+ //the resultDataNeedsDealloc flag is set to 1. Or a data block owned by the parent
232
+ //OpenBase connection may be held in resultData. In particular, resultData will
233
+ //normally hold an element of the resultKeys array. In this case, resultDataNeedsDealloc
234
+ //remains 0.
235
+ //OpenBaseResultData is implemented as a linked list, as indicated by the next attribute.
236
+ //Because of these features, it is necessary to call ob_deallocResultDataList to dispose
237
+ //of an OpenBaseResultData allocation. This is all taken care of by higher level functions.
238
+ OpenBaseResultDataPtr ob_newResultData()
239
+ {
240
+ OpenBaseResultDataPtr resultData;
241
+
242
+ resultData = (OpenBaseResultDataPtr)ob_malloc(sizeof(OpenBaseResultData));
243
+ resultData->resultData = NULL;
244
+ resultData->resultDataLength = 0;
245
+ resultData->next = NULL;
246
+ resultData->resultDataNeedsDealloc = 0;
247
+ return resultData;
248
+ }
249
+
250
+ //Allocates memory for an OpenBaseCursor. It includes one empty result page by default.
251
+ //Normally, a cursor does not own the data fetched from the server and disposing of the
252
+ //cursor will be taken care of by ob_deallocConnection. However, a call to
253
+ //ob_retrieveCursor will pull all result pages into memory owned by the cursor. At that
254
+ //point, the cursor can still be used to step through the result rows, even after the
255
+ //connection is disposed of. The application must take responsiblity for disposing of
256
+ //the cursor by calling ob_deallocCursor. Note that in either case, you may only step
257
+ //forward through a cursor and only once.
258
+ OpenBaseCursorPtr ob_newResult()
259
+ {
260
+ OpenBaseCursorPtr resultset;
261
+
262
+ resultset = (OpenBaseCursorPtr)ob_malloc(sizeof(OpenBaseCursor));
263
+
264
+ resultset->readMoreResult = 0;
265
+ resultset->readPosition = 0;
266
+ resultset->columnsReturned = 0;
267
+ resultset->maxVariablesBound = 0;
268
+ resultset->maxInitializedTables = 0;
269
+ resultset->maxInitializedColumns = 0;
270
+ /*for (ct=0; ct < 400 ;ct++) {
271
+ resultset->tableNames[ct] = NULL;
272
+ resultset->columnNames[ct] = NULL;
273
+ }*/
274
+ resultset->skipConvert = 0;
275
+ resultset->resultPage = ob_newResultData();
276
+ resultset->pushedResult = NULL;
277
+ return resultset;
278
+ }
279
+
280
+
281
+ //[jsh] 11/07/2003. Factored out of ob_newConnection().
282
+ //This is more or less a private method for ob_newConnection, which requires the
283
+ //construction of two NetConn data blocks. There is no corresponding disposal method.
284
+ //That is taken care of by ob_deallocConnection.
285
+ NetConnPtr ob_newNetConn()
286
+ {
287
+ NetConnPtr netConnection;
288
+
289
+ netConnection = (NetConnPtr)ob_malloc(sizeof(NetConn));
290
+ //[jsh] 11/07/2003. Redundant; see dmr below
291
+ //conn->connection->socketConnection = (TEndpoint*)(-1);
292
+ netConnection->didInit = 0;
293
+ netConnection->dictionaryBuffer = (unsigned char*)ob_malloc(DICTIONARY_BUFFER_SIZE);
294
+ netConnection->dictionaryBufferSize = DICTIONARY_BUFFER_SIZE;
295
+ netConnection->readPosition = 0;
296
+ netConnection->socketConnection = -1; // ��dmr
297
+ netConnection->privateEncriptionMap = NULL;
298
+ netConnection->privateDecriptionMap = NULL;
299
+ netConnection->clientAddress[0] = 0;
300
+ netConnection->serverAddress[0] = 0;
301
+ return netConnection;
302
+ }
303
+
304
+ void ob_deallocNetConn(NetConnPtr conn)
305
+ {
306
+ if (conn->dictionaryBuffer) ob_free(conn->dictionaryBuffer);
307
+ if (conn->privateEncriptionMap) ob_free(conn->privateEncriptionMap);
308
+ if (conn->privateDecriptionMap) ob_free(conn->privateDecriptionMap);
309
+ ob_free(conn);
310
+ }
311
+
312
+
313
+ // ----------------------------------------------------------------------------
314
+ //Allocates memory for an OpenBase connection. The connection is not actually
315
+ //made. (See ob_connectToDatabase) Rather, the OpenBase data block is initialized
316
+ //in preparation for a connection. This memory must be released by the application
317
+ //with a call to ob_deallocConnection.
318
+ #ifdef MACOS_CARBON
319
+ #ifdef TARGET_API_MAC_CARBON
320
+ OpenBasePtr ob_newConnection(OTClientContextPtr newClientContext)
321
+ #else
322
+ OpenBasePtr ob_newConnection(void)
323
+ #endif
324
+ #else
325
+ OpenBasePtr ob_newConnection(void)
326
+ #endif
327
+ {
328
+ OpenBasePtr conn = NULL;
329
+
330
+ #ifdef MACOS_CARBON
331
+ static bool initialized = false;
332
+ #endif
333
+
334
+ int ct = 0;
335
+
336
+ conn = (OpenBasePtr)ob_malloc(sizeof(OpenBase));
337
+
338
+ conn->connection = ob_newNetConn(); //[jsh] 11/07/2003
339
+ conn->altConnection = ob_newNetConn(); //[jsh] 11/07/2003
340
+
341
+ conn->invalidate = 0;
342
+ conn->autoReconnectFlag = 1;
343
+ conn->transactionInProgress = 0;
344
+
345
+ #ifdef MACOS_CARBON
346
+ #ifdef TARGET_API_MAC_CARBON
347
+ conn->outClientContext = newClientContext;
348
+ conn->connection->outClientContext = conn->outClientContext;
349
+ conn->altConnection->outClientContext = conn->outClientContext;
350
+ #else
351
+ if(!initialized)
352
+ {
353
+ initialized = true;
354
+ InitOpenTransport();
355
+ }
356
+ #endif
357
+ #endif
358
+
359
+ conn->sqlBuffer = (char*)ob_malloc(SQL_BUFFER_SIZE); //[jsh] 11/07/2003
360
+ conn->sqlBufferSize = SQL_BUFFER_SIZE; //[jsh] 11/07/2003
361
+
362
+ conn->databaseEncoding = OB_ENCODING_ASCII;
363
+ conn->clientEncoding = OB_ENCODING_MACOS_ROMAN;
364
+
365
+ conn->position = 0;
366
+
367
+ for (ct=0; ct < OB_MAX_COLUMNS ;ct++) {
368
+ conn->preparedSQL[ct] = NULL;
369
+ }
370
+
371
+ //[jsh] 11/07/2003. Redundant. Initialized in the loop above.
372
+ //conn->preparedSQL[0] = NULL;
373
+
374
+ conn->resultset = ob_newResult();
375
+
376
+ conn->resultset->errorMessage = NULL; // ��dmr ��� LD 9/4/2001 - Add 'resultSet'
377
+
378
+ conn->secondaryHost[0] = '\0';
379
+ conn->secondaryDatabase[0] = '\0';
380
+ strcpy(conn->softwareId,"C-API");
381
+ strcpy(conn->clientName,"C-API");
382
+
383
+ clearComm(conn->connection); // ��dmr
384
+ clearComm(conn->altConnection); // ��dmr
385
+
386
+ return conn;
387
+ }
388
+
389
+
390
+ // extern int out ( const char* );
391
+
392
+
393
+ // ----------------------------------------------------------------------------
394
+ //This function is the high level mechanism for properly disposing of an
395
+ //OpenBase connection. It will ensure that the connection is closed and then
396
+ //dispose of all memory associated with it, including the current cursor.
397
+ void ob_deallocConnection(OpenBasePtr conn)
398
+ {
399
+ if(conn)
400
+ {
401
+ /*
402
+ char s[100];
403
+ sprintf ( s, "ob_deallocConnection 0x%x", conn );
404
+ out ( s );
405
+ */
406
+
407
+ ob_invalidate(conn);
408
+ ob_releaseBuffers(conn); //[jsh] 11/07/2003
409
+
410
+ ob_deallocCursor(conn->resultset);
411
+ conn->resultset = NULL;
412
+ ob_free(conn);
413
+ }
414
+ }
415
+
416
+ // ----------------------------------------------------------------------------
417
+ // [jsh] 11/07/2003
418
+ // Moved this method and releasConnBuffers here from OT_NetClient.cpp
419
+ // Made use of the DEALLOC macro.
420
+ //This function disposes of the non-cursor memory allocations associated with
421
+ //an OpenBase connection, not including the OpenBase connection itself. It is
422
+ //called by ob_deallocConnection.
423
+ void ob_releaseBuffers (OpenBasePtr conn)
424
+ {
425
+ int ct = 0;
426
+
427
+ if (conn->connection != NULL)
428
+ {
429
+ releasConnBuffers (conn->connection);
430
+
431
+ ob_free (conn->connection);
432
+ conn->connection = NULL;
433
+ }
434
+
435
+ if (conn->altConnection != NULL)
436
+ {
437
+ releasConnBuffers (conn->altConnection);
438
+
439
+ ob_free (conn->altConnection);
440
+ conn->altConnection = NULL;
441
+ }
442
+
443
+ OB_DEALLOC(conn->sqlBuffer);
444
+
445
+ for (ct = 0; ct < OB_MAX_COLUMNS; ct++) {
446
+ OB_DEALLOC(conn->preparedSQL[ct]) ;
447
+ }
448
+ conn->numberOfPreparedValues = 0;
449
+ }
450
+
451
+
452
+ //Called by ob_releaseBuffers.
453
+ static void releasConnBuffers (NetConnPtr conn)
454
+ {
455
+ int ct;
456
+ for (ct=0; ct < OB_MAX_KEYS; ct++)
457
+ {
458
+ OB_DEALLOC(conn->resultKeys[ct]) ;
459
+ OB_DEALLOC(conn->resultValues[ct]) ;
460
+ }
461
+ OB_DEALLOC(conn->dictionaryBuffer) ;
462
+ }
463
+
464
+ // ----------------------------------------------------------------------------
465
+ //Called by ob_deallocResultDataList.
466
+ void ob_deallocResultData(OpenBaseResultDataPtr resultData)
467
+ {
468
+
469
+ if (!resultData) return;
470
+
471
+ if (resultData->resultDataNeedsDealloc) {
472
+ OB_DEALLOC(resultData->resultData);
473
+ }
474
+ ob_free(resultData); //[jsh] 11/07/2003
475
+ }
476
+
477
+ // ----------------------------------------------------------------------------
478
+ //Disposes of the linked list result pages in a cursor.
479
+ void ob_deallocResultDataList(OpenBaseResultDataPtr resultData)
480
+ {
481
+
482
+ if (!resultData) return;
483
+ ob_deallocResultDataList(resultData->next);
484
+ ob_deallocResultData(resultData);
485
+ }
486
+
487
+ // ----------------------------------------------------------------------------
488
+ //This function disposes of an OpenBaseCursor. It is normally called by various
489
+ //functions that manage cursors, including ob_deallocConnection. It must be
490
+ //called by the application to dispose of cursors returned via ob_retrieveCursor.
491
+ void ob_deallocCursor(OpenBaseCursorPtr cursor){
492
+ int ct;
493
+
494
+ if (!cursor) return;
495
+
496
+ for (ct=0; ct < cursor->maxInitializedColumns ;ct++) {
497
+ OB_DEALLOC(cursor->columnNames[ct]);
498
+ }
499
+ for (ct=0; ct < cursor->maxInitializedTables ;ct++) {
500
+ OB_DEALLOC(cursor->tableNames[ct]);
501
+ }
502
+ ob_deallocResultDataList(cursor->resultPage);
503
+ ob_free(cursor); //[jsh] 11/07/2003
504
+ }
505
+
506
+
507
+ // ----------------------------------------------------------------------------
508
+ //This function closes the connection to the server. The OpenBase connection
509
+ //remains in a state that allows the connection to be reopened via a call to
510
+ //ob_connectToDatabase.
511
+ void ob_invalidate(OpenBasePtr conn)
512
+ {
513
+ if(!conn->invalidate) {
514
+ conn->invalidate = 1;
515
+ // SEND EXIT SIGNAL TO NOTIFY SERVER THAT CONNECTION IS CLOSING
516
+ // CLOSE THE CONNECTION TO THE SERVER
517
+ if (conn->connection->socketConnection != -1) { // ��dmr
518
+ sendExitSignal(conn->connection);
519
+ netClose(conn->connection->socketConnection);
520
+ }
521
+ if (conn->altConnection->socketConnection != -1) { // ��dmr
522
+ sendExitSignal(conn->altConnection);
523
+ netClose(conn->altConnection->socketConnection);
524
+ }
525
+ conn->connection->socketConnection = -1;
526
+ conn->altConnection->socketConnection = -1;
527
+
528
+ OB_DEALLOC(conn->connection->privateEncriptionMap);
529
+ OB_DEALLOC(conn->connection->privateDecriptionMap);
530
+ OB_DEALLOC(conn->altConnection->privateEncriptionMap);
531
+ OB_DEALLOC(conn->altConnection->privateDecriptionMap);
532
+ }
533
+ }
534
+
535
+ // ----------------------------------------------------------------------------
536
+
537
+ int ob_beginTransaction(OpenBasePtr conn)
538
+ {
539
+ ob_clearCommands(conn);
540
+ ob_makeCommand(conn,"START TRANSACTION");
541
+ if (ob_executeCommand(conn)) {
542
+ conn->transactionInProgress = 1;
543
+ return 1;
544
+ }
545
+ return 0;
546
+ }
547
+
548
+ // ----------------------------------------------------------------------------
549
+
550
+ int ob_beginPassiveTransaction(OpenBasePtr conn)
551
+ {
552
+ ob_clearCommands(conn);
553
+ ob_makeCommand(conn,"START PASSIVE TRANSACTION");
554
+ if (ob_executeCommand(conn)) {
555
+ conn->transactionInProgress = 1;
556
+ return 1;
557
+ }
558
+ return 0;
559
+ }
560
+
561
+ // ----------------------------------------------------------------------------
562
+
563
+ int ob_isTransactionInProgress(OpenBasePtr conn)
564
+ {
565
+ return conn->transactionInProgress;
566
+ }
567
+
568
+
569
+ // ----------------------------------------------------------------------------
570
+
571
+
572
+ // [jsh] 11/07/2003 Added const keyword to bind functions.
573
+ void ob_bindDouble(OpenBasePtr conn, const double *var)
574
+ {
575
+ conn->resultset->bindTargetTypes[conn->resultset->maxVariablesBound]='F';
576
+ conn->resultset->bindVariables[conn->resultset->maxVariablesBound] = (char *)var;
577
+ conn->resultset->maxVariablesBound = conn->resultset->maxVariablesBound + 1;
578
+
579
+ }
580
+
581
+ // ----------------------------------------------------------------------------
582
+
583
+
584
+ void ob_bindInt(OpenBasePtr conn, const int *var)
585
+ {
586
+ conn->resultset->bindTargetTypes[conn->resultset->maxVariablesBound]='I';
587
+ conn->resultset->bindVariables[conn->resultset->maxVariablesBound] = (char *)var;
588
+ conn->resultset->maxVariablesBound = conn->resultset->maxVariablesBound + 1;
589
+ }
590
+
591
+ // ----------------------------------------------------------------------------
592
+
593
+
594
+ void ob_bindLongLong(OpenBasePtr conn, const int *var)
595
+ {
596
+ conn->resultset->bindTargetTypes[conn->resultset->maxVariablesBound]='Q';
597
+ conn->resultset->bindVariables[conn->resultset->maxVariablesBound] = (char *)var;
598
+ conn->resultset->maxVariablesBound = conn->resultset->maxVariablesBound + 1;
599
+ }
600
+
601
+ // ----------------------------------------------------------------------------
602
+
603
+
604
+ void ob_bindLong(OpenBasePtr conn, const long *var)
605
+ {
606
+ conn->resultset->bindTargetTypes[conn->resultset->maxVariablesBound]='L';
607
+ conn->resultset->bindVariables[conn->resultset->maxVariablesBound] = (char *)var;
608
+ conn->resultset->maxVariablesBound = conn->resultset->maxVariablesBound + 1;
609
+ }
610
+
611
+ // ----------------------------------------------------------------------------
612
+
613
+
614
+ void ob_bindString(OpenBasePtr conn, const char *var)
615
+ {
616
+ conn->resultset->bindTargetTypes[conn->resultset->maxVariablesBound]='C';
617
+ conn->resultset->bindVariables[conn->resultset->maxVariablesBound] = (char *)var;
618
+ conn->resultset->maxVariablesBound = conn->resultset->maxVariablesBound + 1;
619
+ }
620
+
621
+ // ----------------------------------------------------------------------------
622
+
623
+
624
+ void ob_bindBinary(OpenBasePtr conn, const char *var)
625
+ {
626
+ conn->resultset->bindTargetTypes[conn->resultset->maxVariablesBound]='B';
627
+ conn->resultset->bindVariables[conn->resultset->maxVariablesBound] = (char *)var;
628
+ conn->resultset->maxVariablesBound = conn->resultset->maxVariablesBound + 1;
629
+ }
630
+ // ----------------------------------------------------------------------------
631
+
632
+ void ob_bindBoolean(OpenBasePtr conn, const int *var)
633
+ {
634
+ conn->resultset->bindTargetTypes[conn->resultset->maxVariablesBound]='b';
635
+ conn->resultset->bindVariables[conn->resultset->maxVariablesBound] = (char *)var;
636
+ conn->resultset->maxVariablesBound = conn->resultset->maxVariablesBound + 1;
637
+ }
638
+
639
+ // ----------------------------------------------------------------------------
640
+
641
+
642
+
643
+ int ob_bufferHasCommands(OpenBasePtr conn)
644
+ {
645
+ if (conn->position) return 1;
646
+ return 0;
647
+ }
648
+
649
+ // ----------------------------------------------------------------------------
650
+
651
+
652
+ void ob_clearCommands(OpenBasePtr conn)
653
+ {
654
+ conn->position = 0;
655
+ return;
656
+ }
657
+
658
+ // ----------------------------------------------------------------------------
659
+
660
+
661
+ char *ob_commandBuffer(OpenBasePtr conn)
662
+ {
663
+ return conn->sqlBuffer;
664
+ }
665
+
666
+ // ----------------------------------------------------------------------------
667
+
668
+
669
+ int ob_commitTransaction(OpenBasePtr conn)
670
+ {
671
+ ob_clearCommands(conn);
672
+ ob_makeCommand(conn,"COMMIT");
673
+ conn->transactionInProgress = 0;
674
+ return ob_executeCommand(conn);
675
+ }
676
+
677
+ // ----------------------------------------------------------------------------
678
+
679
+
680
+ const char *ob_connectErrorMessage(OpenBasePtr conn )
681
+ {
682
+ return conn->resultset->errorMessage;
683
+ }
684
+
685
+ // [jsh] 11/07/2003 Use default.
686
+ void _setErrorMessage(OpenBasePtr conn, int errorCode)
687
+ {
688
+ switch(errorCode) {
689
+ case ERR_DBSUSRLIM: conn->resultset->errorMessage = "The user limit has been exceeded. You may need to purchase additional licenses in order to connect to OpenBase. Your action has been aborted. "; break;
690
+ case ERR_NOSERVER: conn->resultset->errorMessage = "The database specified has not been started or can not be found. Your action has been aborted. "; break;
691
+ case ERR_INCORRECT_LOGIN: conn->resultset->errorMessage = "Your login and password are not valid for the specified database. If no passwords have been set in the database you can use the 'root' user with no password."; break;
692
+ case ERR_WEBOBJECTS_VIOLATION: conn->resultset->errorMessage = "You need to purchase an internet license to use OpenBase with WebObjects. Please contact OpenBase International at 603-547-8404 for more information. "; break;
693
+ case ERR_LITE_VIOLATION: conn->resultset->errorMessage = "OpenBase Lite is for single-user deployment only. It is not to be used with software development tools or WebObjects. Please contact OpenBase at 603-547-8404 to purchase the appropriate license to work with these products. Thank you."; break;
694
+ default: conn->resultset->errorMessage = "";
695
+ }
696
+ }
697
+
698
+ // ----------------------------------------------------------------------------
699
+
700
+
701
+
702
+ int _ob_connectToDatabase(OpenBasePtr conn, char *databaseName, char *databaseHost, int *returnCode, int secondaryConnectionFlag )
703
+ {
704
+ int len;
705
+ char *values;
706
+ char processIdString[50];
707
+ static int counter = 0;
708
+ #ifdef MACOS_CARBON
709
+ char buffer[128] ;
710
+ #endif
711
+
712
+ if (databaseName[0] != '#') {
713
+
714
+ if (!connectToPort(conn->connection, 20222, databaseHost))
715
+ {
716
+ _setErrorMessage(conn, ERR_NOSERVER); *returnCode = ERR_NOSERVER;
717
+ //printf("\ntrying to connect to openexec failed\n"); //��dmr
718
+ return 0;
719
+ }
720
+ // setup block send
721
+ prepareDictionary(conn->connection);
722
+ addDictionaryPair(conn->connection, "findPort", databaseName);
723
+ #ifdef MACOS_CARBON
724
+ addDictionaryPair(conn->connection, "portHost", MapNameToAddress (databaseHost, buffer, conn->outClientContext));
725
+ #else
726
+ addDictionaryPair(conn->connection, "portHost", databaseHost);
727
+ #endif
728
+ sendBuffer(conn->connection);
729
+ YIELD_THREAD;
730
+ if (!readResult(conn->connection)) {
731
+ //printf("no result returned from nameserver\n");
732
+ _setErrorMessage(conn, ERR_NOSERVER); *returnCode = ERR_NOSERVER;
733
+ return 0;
734
+ }
735
+ if (!resultValueForKey(conn->connection, "portNumber", &len)) {
736
+ //printf("could not find database\n");
737
+ _setErrorMessage(conn, ERR_NOSERVER); *returnCode = ERR_NOSERVER;
738
+ return 0;
739
+ }
740
+ // primary connection
741
+
742
+ // FOR MAC SYSTEMS NAME RESOLUTION DOESN'T WORK
743
+ //strcpy(conn->databaseHost, resultValueForKey( conn->connection,
744
+ // "portHostAddress", &len));
745
+
746
+ netClose(conn->connection->socketConnection);
747
+ conn->connection->socketConnection = -1; // ��dmr
748
+
749
+ conn->connection->connectionPort =
750
+ atoi(resultValueForKey(conn->connection, "portNumber", &len)); //��dmr
751
+ } else {
752
+ conn->connection->connectionPort = atoi(&databaseName[1]);
753
+ }
754
+ if (!connectToPort( conn->connection,
755
+ conn->connection->connectionPort,
756
+ databaseHost)) {
757
+ printf("could not find database %s@%s\n",databaseName,databaseHost); // ��dmr
758
+ return 0;
759
+ }
760
+
761
+
762
+ // secondary connection (for blob transport)
763
+ conn->altConnection->connectionPort = conn->connection->connectionPort;
764
+ netClose(conn->altConnection->socketConnection);
765
+ conn->altConnection->socketConnection = -1; // ��dmr
766
+
767
+ if (!connectToPort( conn->altConnection, conn->altConnection->connectionPort, databaseHost)) {
768
+ //printf("could not find database\n"); ��dmr
769
+ return 0;
770
+ }
771
+
772
+ // check to see if we can log on.
773
+ prepareDictionary(conn->connection);
774
+ addDictionaryPair(conn->connection, "action", "call_checkcanconnect");
775
+ if (!sendBuffer(conn->connection)) {
776
+ _setErrorMessage(conn, ERR_NOSERVER); *returnCode = ERR_NOSERVER;
777
+ return 0;
778
+ }
779
+
780
+ YIELD_THREAD;
781
+
782
+ if (!readResult(conn->connection)) {
783
+ _setErrorMessage(conn, ERR_NOSERVER); *returnCode = ERR_NOSERVER;
784
+ return 0;
785
+ }
786
+
787
+ if ((values = resultValueForKey(conn->connection, "result", &len)) != NULL) {
788
+ if (strcmp(values,"no") == 0) {
789
+ // reconnect to failover server
790
+ if ((conn->secondaryHost[0] == '\0') || (conn->secondaryDatabase[0] == '\0')) {
791
+ if ((values = resultValueForKey(conn->connection, "secondaryHost", &len)) != NULL) {
792
+ strcpy(conn->secondaryHost, values);
793
+ if ((values = resultValueForKey(conn->connection, "secondaryDatabase", &len)) != NULL) {
794
+ strcpy(conn->secondaryDatabase, values);
795
+ }
796
+ }
797
+ }
798
+
799
+ // now connect to the secondary server
800
+ return _ob_connectToDatabase(conn, conn->secondaryDatabase, conn->secondaryHost, returnCode, 1);
801
+ }
802
+ }
803
+
804
+ // setup encryption
805
+ startPrivateTransmission(conn->connection);
806
+ startPrivateTransmission(conn->altConnection);
807
+
808
+ sprintf(processIdString,"%s_%d", conn->databaseLogin, counter++);
809
+
810
+
811
+ // log into database
812
+ prepareDictionary(conn->connection);
813
+ addDictionaryPair(conn->connection, "action", "call_register");
814
+ addDictionaryPair(conn->connection, "usersAllowed", "1000");
815
+ addDictionaryPair(conn->connection, "dblogin", conn->databaseLogin);
816
+ addDictionaryPair(conn->connection, "dbpassword", conn->databasePassword);
817
+ addDictionaryPair(conn->connection, "userlogin", conn->databaseLogin);
818
+ addDictionaryPair(conn->connection, "hostName", conn->databaseHost);
819
+ addDictionaryPair(conn->connection, "databaseName", conn->databaseName);
820
+ addDictionaryPair(conn->connection, "softwareId", conn->softwareId);
821
+ addDictionaryPair(conn->connection, "processId", processIdString);
822
+ if (!sendBuffer(conn->connection)) {
823
+ _setErrorMessage(conn, ERR_NOSERVER); *returnCode = ERR_NOSERVER;
824
+ return 0;
825
+ }
826
+
827
+ YIELD_THREAD;
828
+
829
+ if (!readResult(conn->connection)) {
830
+ _setErrorMessage(conn, ERR_NOSERVER); *returnCode = ERR_NOSERVER;
831
+ return 0;
832
+ }
833
+
834
+ if ((values = resultValueForKey(conn->connection, "result", &len)) == NULL) {
835
+ _setErrorMessage(conn, ERR_NOSERVER); *returnCode = ERR_NOSERVER;
836
+ return 0;
837
+ }
838
+ if (strcmp(values,"succeed") != 0) {
839
+ if ((values = resultValueForKey(conn->connection, "error", &len)) != NULL) {
840
+ _setErrorMessage(conn, atoi(values)); *returnCode = atoi(values);
841
+ } else {
842
+ _setErrorMessage(conn, ERR_NOSERVER); *returnCode = ERR_NOSERVER;
843
+ }
844
+ return 0;
845
+ }
846
+
847
+ if (secondaryConnectionFlag) {
848
+ // tell the server that this is a secondary connection
849
+ prepareDictionary(conn->connection);
850
+ addDictionaryPair(conn->connection, "action", "call_alternateConnection");
851
+ if (!sendBuffer(conn->connection)){
852
+ _setErrorMessage(conn, ERR_NOSERVER); *returnCode = ERR_NOSERVER;
853
+ return 0;
854
+ }
855
+ YIELD_THREAD;
856
+
857
+ if (!readResult(conn->connection)) {
858
+ _setErrorMessage(conn, ERR_NOSERVER); *returnCode = ERR_NOSERVER;
859
+ return 0;
860
+ }
861
+
862
+ } else {
863
+ // get the secondaryHost and secondaryDatabase
864
+ if ((conn->secondaryHost[0] == '\0') || (conn->secondaryDatabase[0] == '\0')) {
865
+ if ((values = resultValueForKey(conn->connection, "secondaryHost", &len)) != NULL) {
866
+ strcpy(conn->secondaryHost, values);
867
+ if ((values = resultValueForKey(conn->connection, "secondaryDatabase", &len)) != NULL) {
868
+ strcpy(conn->secondaryDatabase, values);
869
+ }
870
+ }
871
+ }
872
+ }
873
+
874
+ // setup max buffer size
875
+ // ��� WAS COMMENTED OUT !!!
876
+ #ifdef MACOS_CARBON
877
+ prepareDictionary(conn->connection);
878
+ addDictionaryPair(conn->connection, "action", "setMaxBufferSize");
879
+ addDictionaryPair(conn->connection, "size", "20000");
880
+ if (!sendBuffer(conn->connection)){
881
+ _setErrorMessage(conn, ERR_NOSERVER); *returnCode = ERR_NOSERVER;
882
+ return 0;
883
+ }
884
+ // ��� END OF WAS COMMENTED OUT SECTION
885
+
886
+ YIELD_THREAD;
887
+
888
+ if (!readResult(conn->connection)) {
889
+ _setErrorMessage(conn, ERR_NOSERVER); *returnCode = ERR_NOSERVER;
890
+ return 0;
891
+ }
892
+ #endif
893
+
894
+ conn->tmp[0] = 0; // ��dmr
895
+ (void)_initEncoding(conn); // ��dmr
896
+
897
+ *returnCode = 0; //[jsh] 11/07/2003
898
+ return 1;
899
+ }
900
+
901
+ int ob_checkConnectionToDatabase(OpenBasePtr conn, const char *dbHostName){
902
+ strcpy(conn->databaseHost, dbHostName);
903
+ if (!connectToPort(conn->connection, 20222, conn->databaseHost)){
904
+ return 0;
905
+ }
906
+ return 1;
907
+ }
908
+
909
+ //Open a connection to the server. softwareId and clientName are identifiers that
910
+ //appear in various server side log files.
911
+ int ob_connectToDatabase(OpenBasePtr conn, const char *dbName, const char *dbHostName,
912
+ const char *loginName, const char *passwordString,
913
+ const char* softwareId, const char* clientName, int *returnCode )
914
+ {
915
+ // copy in login information
916
+ strcpy(conn->databaseName, dbName);
917
+ strcpy(conn->databaseHost, dbHostName);
918
+ strcpy(conn->databaseLogin, loginName);
919
+ strcpy(conn->databasePassword, passwordString);
920
+ strcpy(conn->softwareId, softwareId);
921
+ strcpy(conn->clientName, clientName);
922
+
923
+ return _ob_connectToDatabase(conn, conn->databaseName, conn->databaseHost, returnCode, 0);
924
+ }
925
+
926
+ // ----------------------------------------------------------------------------
927
+
928
+ char *ob_databaseName(OpenBasePtr conn)
929
+ {
930
+ return conn->databaseName;
931
+ }
932
+
933
+ // ----------------------------------------------------------------------------
934
+
935
+ int ob_abortFetch(OpenBasePtr conn)
936
+ {
937
+ prepareDictionary(conn->connection);
938
+ addDictionaryPair(conn->connection, "action", "abort");
939
+
940
+ // send the command to the server
941
+ if (!sendBuffer(conn->connection)){
942
+ _setErrorMessage(conn, ERR_NOSERVER);
943
+ return 0;
944
+ }
945
+ YIELD_THREAD;
946
+ if (readResult(conn->connection) == 0) return 0; // failure
947
+
948
+ return 1;
949
+ }
950
+
951
+
952
+ //This function sends SQL to the server for execution, setting the resultSet as warranted. There are three possible return values.
953
+ // 1 success
954
+ // -1 server connection failure
955
+ // 0 other errors returned by the server, stored in errorMessage
956
+ int _ob_executeCommand(OpenBasePtr conn)
957
+ {
958
+ int len;
959
+ char *values;
960
+ int ct;
961
+
962
+ if (conn->connection == NULL) {
963
+ return 0;
964
+ }
965
+
966
+ // check to see if we need to abort the fetch
967
+ if (conn->resultset->readMoreResult) {
968
+ // send abort
969
+ ob_abortFetch(conn);
970
+ conn->resultset->readMoreResult = 0;
971
+ }
972
+
973
+ conn->insertedRowidValue[0] = '\0';
974
+ conn->position = 0; // restart sql buffer
975
+ conn->resultset->columnsReturned = 0;
976
+ conn->resultset->rowsAffected = 0;
977
+ conn->resultset->maxVariablesBound = 0;
978
+ conn->resultset->readPosition = 0;
979
+
980
+ //printf("ob_executeCommand SQL BUFFER <%s>\n", conn->sqlBuffer);
981
+
982
+ prepareDictionary(conn->connection);
983
+ addDictionaryPair(conn->connection, "action", "call_executeSQL");
984
+ addDictionaryPair(conn->connection, "SQLCommand", conn->sqlBuffer);
985
+
986
+ // send the command to the server
987
+ if (!sendBuffer(conn->connection)){
988
+ _setErrorMessage(conn, ERR_NOSERVER);
989
+ return -1;
990
+ }
991
+ YIELD_THREAD;
992
+
993
+ if (!conn->connection || (readResult(conn->connection) <= 0)) return -1; // failure
994
+
995
+ conn->resultset->errorMessage = resultValueForKey(conn->connection, "error", &len);
996
+ if (conn->resultset->errorMessage) {
997
+ // there was an error
998
+ return 0;
999
+ }
1000
+
1001
+ //[jsh] 11/07/2003 Once upon a time, there was an OpenBase bug that caused the number of table
1002
+ //names to sometimes be less than the number of column names, so I changed this code to set
1003
+ //columnsReturned based on the number of columns (titles), rather than the number of tables.
1004
+ //This change is probably no longer necessary, but...
1005
+ if ((values = resultValueForKey(conn->connection, "titles", &len)) != NULL)
1006
+ {
1007
+ conn->resultset->columnsReturned = copyIntoArray(conn->resultset->columnNames, values, &(conn->resultset->maxInitializedColumns));
1008
+
1009
+ values = resultValueForKey(conn->connection, "tables", &len);
1010
+ copyIntoArray( conn->resultset->tableNames,
1011
+ values,
1012
+ &(conn->resultset->maxInitializedTables));
1013
+
1014
+ values = resultValueForKey(conn->connection, "columnTypes", &len);
1015
+ strcpy(conn->resultset->targetTypes,values);
1016
+ //printf("TYPES = %s\n", conn->resultset->targetTypes);
1017
+
1018
+ if ((values = resultValueForKey(conn->connection, "count", &len)) != NULL) {
1019
+ conn->resultset->rowsAffected = atoi(values);
1020
+ }
1021
+
1022
+ // clear old bound variable pointers
1023
+ for (ct=0; ct < conn->resultset->columnsReturned; ct++){
1024
+ conn->resultset->bindVariables[ct] = NULL;
1025
+ }
1026
+
1027
+ //get first data block
1028
+ prepareDictionary(conn->connection);
1029
+ addDictionaryPair(conn->connection, "action", "ready");
1030
+ if (!sendBuffer(conn->connection)){
1031
+ _setErrorMessage(conn, ERR_NOSERVER);
1032
+ return 0;
1033
+ }
1034
+ YIELD_THREAD;
1035
+ if (readResult(conn->connection) <= 0) return -1; // failure
1036
+
1037
+ // get result data
1038
+ conn->resultset->resultPage->resultData = resultValueForKey(conn->connection, "data", &(conn->resultset->resultPage->resultDataLength));
1039
+ values = resultValueForKey(conn->connection, "action", &len);
1040
+ if (values && (strcmp(values,"more") == 0)) {
1041
+ conn->resultset->readMoreResult = 1;
1042
+ } else {
1043
+ conn->resultset->readMoreResult = 0;
1044
+ }
1045
+ } else {
1046
+ values = resultValueForKey(conn->connection, "parameter", &len);
1047
+ conn->resultset->rowsAffected = 0;
1048
+ if (values) {
1049
+ conn->resultset->rowsAffected = atoi(values);
1050
+ }
1051
+
1052
+ values = resultValueForKey(conn->connection, "_rowid", &len);
1053
+ if (values) {
1054
+ strcpy(conn->insertedRowidValue,values);
1055
+ }
1056
+
1057
+ }
1058
+ //printf("rows affected = %d\n",conn->rowsAffected);
1059
+ return 1;
1060
+ }
1061
+
1062
+
1063
+ //This function sends SQL to the server for execution, setting the resultSet as
1064
+ //warranted. If there is a connection failure then this function will try to
1065
+ //re-establish the connection. If a connection cannot be established to the
1066
+ //primary server then the secondary (mirrored) server will be tried, if one has
1067
+ //been installed.
1068
+ //There are two possible return values.
1069
+ //1 success
1070
+ //0 other errors returned by the server, stored in errorMessage
1071
+ //[jsh] 11/07/2003 modified to give up on connecting after a few tries.
1072
+ int ob_executeCommand(OpenBasePtr conn)
1073
+ {
1074
+ int ret = 0;
1075
+ int returnCode = 0;
1076
+ int tries = 3;
1077
+
1078
+ ob_makeCommand(conn, " ");
1079
+
1080
+ if (conn->connection == NULL) {
1081
+ return 0;
1082
+ }
1083
+
1084
+ while (1) {
1085
+ ret = _ob_executeCommand(conn);
1086
+ if (ret == -1) {
1087
+ if (!conn->autoReconnectFlag) {
1088
+ return 0;
1089
+ }
1090
+ while (tries) {
1091
+ // first reconnect to the original server
1092
+ ret = _ob_connectToDatabase(conn, conn->databaseName,
1093
+ conn->databaseHost,
1094
+ &returnCode, 0);
1095
+
1096
+ if ((ret != 1) && conn->secondaryHost[0] != '\0' && conn->secondaryDatabase[0] != '\0') {
1097
+ // if reconnect fails then connect to the secondary server
1098
+ ret = _ob_connectToDatabase(conn, conn->secondaryDatabase,
1099
+ conn->secondaryHost,
1100
+ &returnCode, 1);
1101
+ }
1102
+ if (1 == ret) break;
1103
+ if (!--tries) return 0;
1104
+ }
1105
+ } else {
1106
+ break;
1107
+ }
1108
+ }
1109
+
1110
+ return ret;
1111
+ }
1112
+
1113
+ const char *ob_insertedRowid(OpenBasePtr conn)
1114
+ {
1115
+ return conn->insertedRowidValue;
1116
+ }
1117
+
1118
+
1119
+
1120
+ // ----------------------------------------------------------------------------
1121
+
1122
+ char *ob_hostName(OpenBasePtr conn)
1123
+ {
1124
+ return conn->databaseHost;
1125
+ }
1126
+
1127
+ // ----------------------------------------------------------------------------
1128
+
1129
+ int ob_isColumnNULL(OpenBasePtr conn, int col)
1130
+ {
1131
+ return (int)conn->resultset->resultIsNull[col];
1132
+ }
1133
+
1134
+ // ----------------------------------------------------------------------------
1135
+
1136
+ int ob_isCursorColumnNULL(OpenBaseCursorPtr cursor, int col)
1137
+ {
1138
+ return (int)cursor->resultIsNull[col];
1139
+ }
1140
+
1141
+ // ----------------------------------------------------------------------------
1142
+
1143
+ const char *ob_loginName(OpenBasePtr conn)
1144
+ {
1145
+ return conn->databaseLogin;
1146
+ }
1147
+
1148
+ // ----------------------------------------------------------------------------
1149
+
1150
+ void ob_makeCommandLength(OpenBasePtr conn, const char *cmd, int length)
1151
+ {
1152
+ conn->position = conn->position + copyString((unsigned char **)&(conn->sqlBuffer),
1153
+ &(conn->sqlBufferSize),
1154
+ conn->position, cmd, length);
1155
+ return;
1156
+ }
1157
+
1158
+ // ----------------------------------------------------------------------------
1159
+
1160
+ void ob_makeCommand(OpenBasePtr conn, const char *cmd)
1161
+ {
1162
+ conn->position = conn->position + copyString((unsigned char **)&(conn->sqlBuffer),
1163
+ &(conn->sqlBufferSize),
1164
+ conn->position, cmd, strlen(cmd));
1165
+ return;
1166
+ }
1167
+
1168
+ // ----------------------------------------------------------------------------
1169
+
1170
+
1171
+ void ob_makeCommandLengthAndEncode(OpenBasePtr conn, const char *cmd, int length)
1172
+ {
1173
+ unsigned char* result = (unsigned char *)ob_convertCharacters(conn->clientEncoding, conn->databaseEncoding, (const unsigned char *)cmd, &length);
1174
+
1175
+ conn->position = conn->position + copyString((unsigned char **)&(conn->sqlBuffer),
1176
+ &(conn->sqlBufferSize),
1177
+ conn->position, (const char *)result, length);
1178
+ free(result);
1179
+ return;
1180
+ }
1181
+
1182
+ // ----------------------------------------------------------------------------
1183
+
1184
+ void ob_makeCommandAndEncode(OpenBasePtr conn, const char *cmd)
1185
+ {
1186
+ unsigned char* result = NULL;
1187
+ int len = strlen(cmd);
1188
+
1189
+ result = (unsigned char*)ob_convertCharacters(conn->clientEncoding, conn->databaseEncoding, (const unsigned char *)cmd, &len);
1190
+
1191
+ conn->position = conn->position + copyString((unsigned char **)&(conn->sqlBuffer),
1192
+ &(conn->sqlBufferSize),
1193
+ conn->position, (const char *)result, len);
1194
+ free(result);
1195
+ }
1196
+
1197
+
1198
+ // ----------------------------------------------------------------------------
1199
+
1200
+ int ob_markRow(OpenBasePtr conn, const char *anId, const char *tableName)
1201
+ {
1202
+ char line[150];
1203
+
1204
+ sprintf(line,"lock record %s %s", anId, tableName); //��dmr sans ''
1205
+
1206
+ ob_makeCommand(conn,line);
1207
+ if (!ob_executeCommand(conn)) {
1208
+ return 0;
1209
+ }
1210
+
1211
+ return 1;
1212
+ }
1213
+
1214
+ // ----------------------------------------------------------------------------
1215
+
1216
+ int ob_markRowAlreadyMarkedByUser(OpenBasePtr conn, const char *anId, const char *tableName, char *userName)
1217
+ {
1218
+ char buff[256];
1219
+
1220
+ if(ob_markRow(conn, anId, tableName)) {
1221
+ if (userName) {
1222
+ userName[0] = '\0';
1223
+ }
1224
+ return 1;
1225
+ }
1226
+ // get the userName
1227
+ strcpy(buff,ob_serverMessage(conn));
1228
+ if (strncmp(buff,"Record already locked by ",25)==0) {
1229
+ strcpy(userName, &buff[25]);
1230
+ }
1231
+ return 0; //��dmr 1 not 0 // sk, no actually 0 not 1
1232
+ }
1233
+
1234
+ // ----------------------------------------------------------------------------
1235
+
1236
+ void _ob_estimateColumnWidths(OpenBasePtr conn)
1237
+ {
1238
+ int readPosition = 0;
1239
+ int ct, i;
1240
+
1241
+ for (ct=0; ct < (conn->resultset->columnsReturned+1); ct++) {
1242
+ conn->resultset->columnWidths[ct] = 0;
1243
+ }
1244
+ while ((readPosition < conn->resultset->resultPage->resultDataLength) &&
1245
+ (conn->resultset->resultPage->resultData != NULL)) {
1246
+ for (ct=0; ct < conn->resultset->columnsReturned; ct++) {
1247
+ i = strlen(&(conn->resultset->resultPage->resultData[readPosition]));
1248
+ if (conn->resultset->columnWidths[ct] < i) {
1249
+ conn->resultset->columnWidths[ct] = i;
1250
+ }
1251
+ readPosition = readPosition + strlen(&(conn->resultset->resultPage->resultData[readPosition]))+1;
1252
+ }
1253
+ }
1254
+ for (ct=0; ct < conn->resultset->columnsReturned; ct++) {
1255
+ if ( conn->resultset->columnWidths[ct] < strlen(conn->resultset->columnNames[ct]) )
1256
+ conn->resultset->columnWidths[ct] = strlen(conn->resultset->columnNames[ct]);
1257
+ }
1258
+
1259
+ }
1260
+
1261
+ // ----------------------------------------------------------------------------
1262
+
1263
+ int _ob_widthForColumn(OpenBasePtr conn, int col)
1264
+ {
1265
+ return conn->resultset->columnWidths[col];
1266
+ }
1267
+
1268
+ // ----------------------------------------------------------------------------
1269
+ //Each call to this function returns the next available row in the cursor. The
1270
+ //values of the row are copied to the bound variables in the bindVariables array
1271
+ //using the appropriate data conversions as determined by the bindTargetTypes
1272
+ //array. The cursor may only be stepped forward through the result rows. It may
1273
+ //not be reset or accessed randomly or stepped backward. Normal operation would
1274
+ //be to execute a search using the ob_executeCommand and then step through the
1275
+ //result rows via the ob_nextRow function, which calls this one as needed.
1276
+ //However, ob_retrieveCursor can be used to return the complete contents of a
1277
+ //result that will persist beyond the life of an OpenBase connection. In that
1278
+ //case, this function must be used to step through the result rows. Call
1279
+ //ob_deallocCursor to dispose of the cursor afterwards.
1280
+ //There are two possible return values.
1281
+ //1 next row is returned
1282
+ //0 no rows left to return
1283
+ int ob_nextCursorRow(OpenBaseCursorPtr cursor)
1284
+ {
1285
+ int ct, len;
1286
+
1287
+ int *bInt;
1288
+ double *bfloat;
1289
+ long *bL;
1290
+ long long *bLL;
1291
+
1292
+ if (!cursor->resultPage->resultData) return 0;
1293
+
1294
+ if (cursor->readPosition >= cursor->resultPage->resultDataLength){
1295
+ OpenBaseResultDataPtr hold = cursor->resultPage;
1296
+
1297
+ cursor->readPosition = 0;
1298
+ if (!cursor->resultPage->next) {
1299
+ return 0;
1300
+ }
1301
+ cursor->resultPage = cursor->resultPage->next;
1302
+ ob_deallocResultData(hold);
1303
+ // now make sure the new data object actually has records
1304
+ if (cursor->readPosition >= cursor->resultPage->resultDataLength){
1305
+ return 0;
1306
+ }
1307
+ }
1308
+
1309
+ for (ct=0; ct < cursor->columnsReturned; ct++) {
1310
+ cursor->resultIsNull[ct] = 0;
1311
+ len = 0;
1312
+ if (cursor->bindVariables[ct] != NULL) {
1313
+ len = strlen(&(cursor->resultPage->resultData[cursor->readPosition]));
1314
+ switch(cursor->bindTargetTypes[ct]) {
1315
+ case 'I':
1316
+ bInt = (int *)cursor->bindVariables[ct];
1317
+ if (IS_NULL_VALUE(&cursor->resultPage->resultData[cursor->readPosition])) {
1318
+ cursor->resultIsNull[ct] = 1;
1319
+ *bInt = 0;
1320
+ } else {
1321
+ *bInt = atoi(&(cursor->resultPage->resultData[cursor->readPosition]));
1322
+ }
1323
+ //printf("INT VALUE(%d) = %d\n", ct, *bInt);
1324
+ break;
1325
+ case 'Q': // LONG LONG
1326
+ bLL = (long long *)cursor->bindVariables[ct];
1327
+ if (IS_NULL_VALUE(&cursor->resultPage->resultData[cursor->readPosition])) {
1328
+ cursor->resultIsNull[ct] = 1;
1329
+ *bLL = 0LL;
1330
+ } else {
1331
+ // this is the same either way.
1332
+ if ((cursor->targetTypes[ct]=='!') || (cursor->targetTypes[ct]=='S')) // OBTYPE_DATETIME
1333
+ {
1334
+ *bLL = (long long) (double) atof (&(cursor->resultPage->resultData[cursor->readPosition]));
1335
+ // keep it as seconds since the NeXT epoch!
1336
+ } else
1337
+ {
1338
+ *bLL = ob_atoll(&(cursor->resultPage->resultData[cursor->readPosition]));
1339
+ }
1340
+
1341
+ }
1342
+ break;
1343
+ case 'L':
1344
+ bL = (long *)cursor->bindVariables[ct];
1345
+ if (IS_NULL_VALUE(&cursor->resultPage->resultData[cursor->readPosition])) {
1346
+ cursor->resultIsNull[ct] = 1;
1347
+ *bL = 0L;
1348
+ } else {
1349
+ *bL = atol(&(cursor->resultPage->resultData[cursor->readPosition]));
1350
+ }
1351
+ //printf("LONG VALUE(%d) = %d\n", ct, *bL);
1352
+ break;
1353
+ case 'F':
1354
+ case '!':
1355
+ case 'S':
1356
+ bfloat = (double *)cursor->bindVariables[ct];
1357
+ if (IS_NULL_VALUE(&cursor->resultPage->resultData[cursor->readPosition])) {
1358
+ cursor->resultIsNull[ct] = 1;
1359
+ *bfloat = 0.0;
1360
+ } else {
1361
+ *bfloat = atof(&(cursor->resultPage->resultData[cursor->readPosition]));
1362
+ if (cursor->targetTypes[ct]=='M'){
1363
+ *bfloat = *bfloat / 100;
1364
+ }
1365
+ }
1366
+ break;
1367
+ case 'B':
1368
+ if (IS_NULL_VALUE(&cursor->resultPage->resultData[cursor->readPosition])) {
1369
+ cursor->resultIsNull[ct] = 1;
1370
+ strcpy(cursor->bindVariables[ct],"");
1371
+ } else {
1372
+ strcpy(cursor->bindVariables[ct], &(cursor->resultPage->resultData[cursor->readPosition]));
1373
+ }
1374
+ break;
1375
+ case 'b':
1376
+ bInt = (int *)cursor->bindVariables[ct];
1377
+ if (IS_NULL_VALUE(&cursor->resultPage->resultData[cursor->readPosition])) {
1378
+ cursor->resultIsNull[ct] = 1;
1379
+ *bInt = 0;
1380
+ } else {
1381
+ if (atoi(&(cursor->resultPage->resultData[cursor->readPosition])) != 0) {
1382
+ *bInt = 1;
1383
+ } else {
1384
+ *bInt = 0;
1385
+ }
1386
+ }
1387
+ break;
1388
+ case 'C':
1389
+ case 'D':
1390
+ case 'T':
1391
+ default:
1392
+ if (IS_NULL_VALUE(&cursor->resultPage->resultData[cursor->readPosition])) {
1393
+ cursor->resultIsNull[ct] = 1;
1394
+ strcpy(cursor->bindVariables[ct],"");
1395
+ }
1396
+ //#if defined(TARGET_OS_MAC)
1397
+ else if ((cursor->targetTypes[ct]=='!') || (cursor->targetTypes[ct]=='S')) // OBTYPE_DATETIME
1398
+ {
1399
+ ob_NSDateTimeToDatetimeString(&(cursor->resultPage->resultData[cursor->readPosition]), cursor->bindVariables[ct], 1);
1400
+ }
1401
+ //#endif
1402
+ else if (cursor->targetTypes[ct]=='D')
1403
+ {
1404
+ strcpy(cursor->bindVariables[ct], &(cursor->resultPage->resultData[cursor->readPosition]));
1405
+ if (cursor->skipConvert == 0)
1406
+ {
1407
+ //convert_convertFromDate(cursor->bindVariables[ct], 0);
1408
+ convert_convertFromDate(cursor->bindVariables[ct], dateFormatType); //[jsh] 11/07/2003
1409
+ }
1410
+ } else if (cursor->targetTypes[ct]=='T'){
1411
+ strcpy(cursor->bindVariables[ct], &(cursor->resultPage->resultData[cursor->readPosition]));
1412
+ if (cursor->skipConvert == 0)
1413
+ {
1414
+ //convert_convertFromTime(cursor->bindVariables[ct], 0);
1415
+ convert_convertFromTime(cursor->bindVariables[ct], timeFormatType); //[jsh] 11/07/2003
1416
+ }
1417
+ } else if (cursor->targetTypes[ct]=='M'){
1418
+ if (cursor->skipConvert == 0)
1419
+ {
1420
+ convert_convertToMoney(ob_atoll(&cursor->resultPage->resultData[cursor->readPosition]), cursor->bindVariables[ct],"$","");
1421
+ }
1422
+ else
1423
+ {
1424
+ strcpy(cursor->bindVariables[ct], &(cursor->resultPage->resultData[cursor->readPosition]));
1425
+ convert_movePointToLeft(cursor->bindVariables[ct]);
1426
+ }
1427
+ } else {
1428
+ strcpy(cursor->bindVariables[ct],
1429
+ &(cursor->resultPage->resultData[cursor->readPosition]));
1430
+ }
1431
+ //printf("CHAR VALUE(%d) = %s\n", ct, conn->bindVariables[ct]);
1432
+ break;
1433
+
1434
+ }
1435
+ } else {
1436
+ //printf("BIND VALUE (%d) = NULL\n", ct);
1437
+ len = strlen(&(cursor->resultPage->resultData[cursor->readPosition]));
1438
+ }
1439
+ cursor->readPosition = cursor->readPosition + len + 1; //strlen(&(conn->resultData[conn->readPosition]))+1;
1440
+ }
1441
+ return 1;
1442
+ }
1443
+
1444
+ // ----------------------------------------------------------------------------
1445
+ //Use this function to return the complete contents of a result that can persist
1446
+ //beyond the life of an OpenBase connection or beyond the context of a particular
1447
+ //command execution. Use ob_nextCursorRow to step through the result rows. Call
1448
+ //ob_deallocCursor to dispose of the cursor afterwards.
1449
+ OpenBaseCursorPtr ob_retrieveCursor(OpenBasePtr conn)
1450
+ {
1451
+ char *values;
1452
+ int len;
1453
+ OpenBaseCursorPtr cursor = conn->resultset;
1454
+ //OpenBaseResultData *startData = NULL; //[jsh] 11/07/2003 not used
1455
+ OpenBaseResultDataPtr currentData = NULL;
1456
+ char *holdData;
1457
+
1458
+ cursor->readPosition = 0;
1459
+
1460
+ // reallocate data for datapage
1461
+ holdData = (char *)ob_malloc(cursor->resultPage->resultDataLength);
1462
+ copyBytes(holdData, cursor->resultPage->resultData, cursor->resultPage->resultDataLength);
1463
+
1464
+ // now set the resultData to the copied location
1465
+ cursor->resultPage->resultData = holdData;
1466
+ cursor->resultPage->resultDataNeedsDealloc = 1;
1467
+
1468
+ // before we forget, replace the result set for the main connection;
1469
+ conn->resultset = ob_newResult();
1470
+
1471
+ // now loop through all of the result pages and retrieve the data
1472
+ //startData = cursor->resultPage; //[jsh] 11/07/2003 not used
1473
+ currentData = cursor->resultPage;
1474
+ while (cursor->readMoreResult) {
1475
+ currentData->next = ob_newResultData();
1476
+ currentData = currentData->next;
1477
+
1478
+ // get next block of data
1479
+ prepareDictionary(conn->connection);
1480
+ addDictionaryPair(conn->connection, "action", "ready");
1481
+ if (!sendBuffer(conn->connection)){
1482
+ _setErrorMessage(conn, ERR_NOSERVER);
1483
+ ob_deallocCursor(cursor);
1484
+ return NULL;
1485
+ }
1486
+ YIELD_THREAD;
1487
+ if (readResult(conn->connection) == 0) {
1488
+ ob_deallocCursor(cursor);
1489
+ return NULL; // failure
1490
+ }
1491
+
1492
+ // get result data
1493
+ currentData->resultData = resultValueForKey(conn->connection, "data", &(currentData->resultDataLength));
1494
+
1495
+ // reallocate data for datapage
1496
+ holdData = (char *)ob_malloc(currentData->resultDataLength);
1497
+ copyBytes(holdData, currentData->resultData, currentData->resultDataLength);
1498
+
1499
+ // now set the resultData to the copied location
1500
+ currentData->resultData = holdData;
1501
+ currentData->resultDataNeedsDealloc = 1;
1502
+
1503
+ // now see if there is more in the result
1504
+ values = resultValueForKey(conn->connection, "action", &len);
1505
+ if (values && (strcmp(values,"more") == 0)) {
1506
+ cursor->readMoreResult = 1;
1507
+ } else {
1508
+ cursor->readMoreResult = 0;
1509
+ }
1510
+ }
1511
+
1512
+ return cursor;
1513
+ }
1514
+
1515
+ // ----------------------------------------------------------------------------
1516
+ //Use this function to step through the rows of a result after a call to
1517
+ //ob_executeCommand. There is no way to access the result rows except by stepping
1518
+ //through them once, one row at a time from the beginning. Use this function only
1519
+ //on open connections. If you want to step though a result set after tearing down
1520
+ //the connection that fetched it then call ob_retrieveCursor, which will pull the
1521
+ //entire result into a cursor in memory; even after disposing of the OpenBase
1522
+ //connection. In that case, do not use this function to step through the rows.
1523
+ //Instead, use ob_nextCursorRow.
1524
+ //There are two possible return values.
1525
+ //1 next row is returned
1526
+ //0 no rows left to return
1527
+ int ob_nextRow(OpenBasePtr conn)
1528
+ {
1529
+ char *values;
1530
+ int len;
1531
+
1532
+
1533
+ if (!conn->resultset->resultPage->resultData) return 0;
1534
+
1535
+ if (!ob_nextCursorRow(conn->resultset)) {
1536
+ if (!conn->resultset->readMoreResult) {
1537
+ conn->resultset->readPosition = 0;
1538
+ return 0;
1539
+ }
1540
+
1541
+ // get next block of data
1542
+ prepareDictionary(conn->connection);
1543
+ addDictionaryPair(conn->connection, "action", "ready");
1544
+ if (!sendBuffer(conn->connection)){
1545
+ _setErrorMessage(conn, ERR_NOSERVER);
1546
+ return 0;
1547
+ }
1548
+ YIELD_THREAD;
1549
+ if (readResult(conn->connection) == 0) {
1550
+ return 0; // failure
1551
+ }
1552
+
1553
+ // get result data
1554
+ conn->resultset->resultPage->resultData = resultValueForKey(conn->connection, "data", &(conn->resultset->resultPage->resultDataLength));
1555
+ values = resultValueForKey(conn->connection, "action", &len);
1556
+ if (values && (strcmp(values,"more") == 0)) {
1557
+ conn->resultset->readMoreResult = 1;
1558
+ } else {
1559
+ conn->resultset->readMoreResult = 0;
1560
+ }
1561
+ conn->resultset->readPosition = 0;
1562
+ if (!ob_nextCursorRow(conn->resultset)) {
1563
+ return 0;
1564
+ }
1565
+ }
1566
+
1567
+ return 1;
1568
+ }
1569
+
1570
+ // ----------------------------------------------------------------------------
1571
+
1572
+
1573
+ char *ob_password(OpenBasePtr conn)
1574
+ {
1575
+ return conn->databasePassword;
1576
+ }
1577
+
1578
+ // ----------------------------------------------------------------------------
1579
+
1580
+ int ob_removeMarkOnRow(OpenBasePtr conn, const char *anId, const char *tableName)
1581
+ {
1582
+ char line[150];
1583
+
1584
+ sprintf(line,"unlock record '%s' %s", anId, tableName);
1585
+
1586
+ ob_makeCommand(conn, line);
1587
+ if (!ob_executeCommand(conn)) {
1588
+ return 0;
1589
+ }
1590
+
1591
+ return 1;
1592
+ }
1593
+
1594
+ // ----------------------------------------------------------------------------
1595
+
1596
+ int ob_resultColumnCount(OpenBasePtr conn)
1597
+ {
1598
+ return conn->resultset->columnsReturned;
1599
+ }
1600
+
1601
+ // ----------------------------------------------------------------------------
1602
+
1603
+ char *ob_resultColumnName(OpenBasePtr conn, int col)
1604
+ {
1605
+ if (col < 0) return NULL;
1606
+ if (col >= conn->resultset->columnsReturned) {
1607
+ return NULL;
1608
+ }
1609
+ return conn->resultset->columnNames[col];
1610
+ }
1611
+
1612
+ char *ob_cursorColumnName(OpenBaseCursorPtr cursor, int col)
1613
+ {
1614
+ if (col < 0) return NULL;
1615
+ if (col >= cursor->columnsReturned) {
1616
+ return NULL;
1617
+ }
1618
+ return cursor->columnNames[col];
1619
+ }
1620
+
1621
+ // ----------------------------------------------------------------------------
1622
+
1623
+ int ob_resultColumnType(OpenBasePtr conn, int col)
1624
+ {
1625
+ if ((col<0) || (col >= conn->resultset->columnsReturned))
1626
+ return -1;
1627
+ switch(conn->resultset->targetTypes[col]){
1628
+ case 'C': return OBTYPE_CHAR;
1629
+ case 'I': return OBTYPE_INT;
1630
+ case 'F': return OBTYPE_FLOAT;
1631
+ case 'L': return OBTYPE_LONG;
1632
+ case 'M': return OBTYPE_MONEY;
1633
+ case 'D': return OBTYPE_DATE;
1634
+ case 'T': return OBTYPE_TIME;
1635
+ case 'O': return OBTYPE_OBJECT;
1636
+ case '!': return OBTYPE_DATETIME;
1637
+ case 'Q': return OBTYPE_LONGLONG;
1638
+ case 'b': return OBTYPE_BOOLEAN; //[jsh] 11/07/2003
1639
+ case 'B': return OBTYPE_BINARY; //[jsh] 11/07/2003
1640
+ case 'X': return OBTYPE_OBJECT_TEXT;
1641
+ case 'S': return OBTYPE_TIMESTAMP;
1642
+ }
1643
+ return 0;
1644
+ }
1645
+
1646
+ // ----------------------------------------------------------------------------
1647
+
1648
+ int ob_resultReturned(OpenBasePtr conn)
1649
+ {
1650
+ if (conn->resultset->columnsReturned && (conn->resultset->rowsAffected > 0)) {
1651
+ return 1;
1652
+ }
1653
+ return 0;
1654
+ }
1655
+
1656
+ // ----------------------------------------------------------------------------
1657
+
1658
+ char *ob_resultTableName(OpenBasePtr conn, int col)
1659
+ {
1660
+ if (col < 0) return NULL;
1661
+ if (col >= conn->resultset->columnsReturned) {
1662
+ return NULL;
1663
+ }
1664
+ return conn->resultset->tableNames[col];
1665
+ }
1666
+
1667
+ // ----------------------------------------------------------------------------
1668
+
1669
+ int ob_rollbackTransaction(OpenBasePtr conn)
1670
+ {
1671
+ ob_clearCommands(conn);
1672
+ ob_makeCommand(conn,"ROLLBACK");
1673
+ conn->transactionInProgress = 0;
1674
+
1675
+ return ob_executeCommand(conn);
1676
+ }
1677
+
1678
+ // ----------------------------------------------------------------------------
1679
+
1680
+ int ob_rowsAffected(OpenBasePtr conn)
1681
+ {
1682
+ return conn->resultset->rowsAffected;
1683
+ }
1684
+
1685
+ // ----------------------------------------------------------------------------
1686
+
1687
+ const char *ob_serverMessage(OpenBasePtr conn)
1688
+ {
1689
+ char *values;
1690
+ int length;
1691
+
1692
+ prepareDictionary(conn->connection);
1693
+ addDictionaryPair(conn->connection, "action", "call_message");
1694
+ if (!sendBuffer(conn->connection)){
1695
+ _setErrorMessage(conn, ERR_NOSERVER);
1696
+ return 0;
1697
+ }
1698
+ YIELD_THREAD;
1699
+ if (readResult(conn->connection) == 0) return NULL; // failure
1700
+
1701
+ // get result data
1702
+ values = resultValueForKey(conn->connection, "result", &length);
1703
+ if (values) {
1704
+ return values;
1705
+ }
1706
+ return "";
1707
+ }
1708
+
1709
+ // ----------------------------------------------------------------------------
1710
+
1711
+ const char *ob_uniqueRowIdForTable(OpenBasePtr conn, const char *tblname)
1712
+ {
1713
+ char line[100];
1714
+
1715
+ strcpy(conn->tmp,"");
1716
+
1717
+ sprintf(line,"newid for %s ", tblname);
1718
+ ob_clearCommands(conn);
1719
+ ob_makeCommand(conn, line);
1720
+ if (ob_executeCommand(conn)) {
1721
+ ob_bindString(conn,conn->tmp);
1722
+ if (ob_nextRow(conn)) {
1723
+ return conn->tmp;
1724
+ }
1725
+ }
1726
+ return "";
1727
+ }
1728
+
1729
+ // ----------------------------------------------------------------------------
1730
+
1731
+ const char *ob_uniqueRowIdForTableColumn( OpenBasePtr conn,
1732
+ const char *tblname,
1733
+ const char *colname)
1734
+ {
1735
+ char line[100];
1736
+
1737
+ strcpy(conn->tmp,"");
1738
+
1739
+ sprintf(line,"newid for %s %s ", tblname, colname);
1740
+ ob_clearCommands(conn);
1741
+ ob_makeCommand(conn, line);
1742
+ if (ob_executeCommand(conn)) {
1743
+ ob_bindString(conn,conn->tmp);
1744
+ if (ob_nextRow(conn)) {
1745
+ return conn->tmp;
1746
+ }
1747
+ }
1748
+ return NULL; //��dmr
1749
+ }
1750
+
1751
+ // ----------------------------------------------------------------------------
1752
+ //Calling this function stores the blob value in the database associated with
1753
+ //the open connection. A blob identifier is returned. This identifier is then
1754
+ //stored in the object type column in place of the actual blob value. This, of
1755
+ //course, necessitates storing the blob first and then inserting or updating
1756
+ //the appropriate row. The identifier is a string value owned by the open
1757
+ //connection. The application must not dispose of it, nor should it attempt to
1758
+ //use it after disposing of the connection.
1759
+ const char *ob_insertBinary(OpenBasePtr conn, const char *data, int size)
1760
+ {
1761
+ const char *resultValue;
1762
+ int length;
1763
+
1764
+ //out ( "1" );
1765
+ prepareData(conn->connection, data, size, "", "call_insertFile");
1766
+ // out ( "2" );
1767
+ if (!sendBuffer(conn->connection)){
1768
+ // out ( "3" );
1769
+ _setErrorMessage(conn, ERR_NOSERVER);
1770
+ return "";
1771
+ }
1772
+ // out ( "4" );
1773
+ YIELD_THREAD;
1774
+ // out ( "5" );
1775
+ if (readResult(conn->connection) == 0) return ""; // failure
1776
+ // out ( "6" );
1777
+
1778
+ // get result data
1779
+ resultValue = resultValueForKey(conn->connection, "result", &length);
1780
+ // out ( "7" );
1781
+
1782
+ if (!resultValue) return "";
1783
+ // out ( "8" );
1784
+ return resultValue;
1785
+ }
1786
+
1787
+ // ----------------------------------------------------------------------------
1788
+ //This function retrieves a blob value from the database associated with the
1789
+ //open connection. A blob identifier is required to identify the blob value to
1790
+ //retrieve. Normally, the blob identifier is fetched as a value from an object
1791
+ //column of a row. returnSize points to a memory location to receive the size of
1792
+ //the blob value retrieved.
1793
+ const char *ob_retrieveBinary( OpenBasePtr conn,
1794
+ const char *blobIdentifier,
1795
+ int *returnSize)
1796
+ {
1797
+ const char *resultValue;
1798
+
1799
+ prepareDictionary(conn->altConnection);
1800
+ addDictionaryPair(conn->altConnection, "action", "call_getFile");
1801
+ addDictionaryPair(conn->altConnection, "fileKey", blobIdentifier);
1802
+ if (!sendBuffer(conn->altConnection)){
1803
+ _setErrorMessage(conn, ERR_NOSERVER);
1804
+ return 0;
1805
+ }
1806
+ YIELD_THREAD;
1807
+
1808
+ if (readResult(conn->altConnection) == 0) {
1809
+ *returnSize = 0;
1810
+ ob_invalidate(conn);
1811
+ return NULL; // failure
1812
+ }
1813
+
1814
+ resultValue = resultValueForKey(conn->altConnection, "data", returnSize);
1815
+ if (!resultValue) {
1816
+ *returnSize = 0;
1817
+ ob_invalidate(conn);
1818
+ return NULL; // failure
1819
+ }
1820
+ return resultValue;
1821
+ }
1822
+
1823
+ // ----------------------------------------------------------------------------
1824
+ //This function may be used to dispose of a blob value. Note that this is an
1825
+ //actual blob value, not a blob identifier.
1826
+ void ob_deallocBinary(const char * blob)
1827
+ {
1828
+ if(blob)
1829
+ {
1830
+ ob_free((void *)blob);
1831
+ }
1832
+ }
1833
+
1834
+ // ----------------------------------------------------------------------------
1835
+
1836
+ const int ob_isConnected(OpenBase *conn) {
1837
+ if((conn->connection->socketConnection != -1) && (conn->altConnection->socketConnection != -1)) {
1838
+ return YES;
1839
+ }
1840
+ return NO;
1841
+ }