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.
- data/History.txt +50 -0
- data/License.txt +20 -0
- data/Manifest.txt +53 -0
- data/README.txt +35 -0
- data/Rakefile +126 -0
- data/examples/example.rb +37 -0
- data/ext/CommAPI.c +643 -0
- data/ext/Headers/CommAPI.h +1 -0
- data/ext/Headers/NetClient.h +42 -0
- data/ext/Headers/NetClientLib.h +41 -0
- data/ext/Headers/OB_Memory.h +69 -0
- data/ext/Headers/OpenBaseAdmin.h +227 -0
- data/ext/Headers/OpenBaseConnection.h +337 -0
- data/ext/Headers/OpenBaseEncoding.h +302 -0
- data/ext/Headers/OpenBasePrepare.h +1 -0
- data/ext/Headers/OpenBaseSupport.h +1 -0
- data/ext/Headers/Platform_Carbon_Header.h +5 -0
- data/ext/Headers/Platform_Classic_Header.h +6 -0
- data/ext/Headers/Platform_Linux.h +4 -0
- data/ext/Headers/Platform_Mach_Header.h +4 -0
- data/ext/Headers/Platform_Windows.h +3 -0
- data/ext/Headers/conversion.h +1 -0
- data/ext/Headers/datetime.h +26 -0
- data/ext/Headers/longlong.h +46 -0
- data/ext/Headers/platform.h +67 -0
- data/ext/Headers/stringConversion.h +15 -0
- data/ext/NetClient.c +888 -0
- data/ext/OpenBaseAdmin.c +1884 -0
- data/ext/OpenBaseConnection.c +1841 -0
- data/ext/OpenBaseEncoding.c +993 -0
- data/ext/OpenBaseEncoding_DOS.c +1 -0
- data/ext/OpenBaseEncoding_ISO8859.c +1 -0
- data/ext/OpenBaseEncoding_MacOS.c +1 -0
- data/ext/OpenBaseEncoding_Windows.c +1150 -0
- data/ext/OpenBasePrepare.c +1 -0
- data/ext/OpenBaseSupport.c +1 -0
- data/ext/conversion.c +1 -0
- data/ext/datetime.c +816 -0
- data/ext/depend +1 -0
- data/ext/extconf.rb +10 -0
- data/ext/longlong.c +1 -0
- data/ext/openbase.c +980 -0
- data/ext/stringConversion.c +169 -0
- data/lib/ruby-openbase/version.rb +9 -0
- data/scripts/txt2html +67 -0
- data/setup.rb +1585 -0
- data/test/test_helper.rb +2 -0
- data/test/test_openbase.rb +241 -0
- data/website/index.html +114 -0
- data/website/index.txt +59 -0
- data/website/javascripts/rounded_corners_lite.inc.js +285 -0
- data/website/stylesheets/screen.css +133 -0
- data/website/template.rhtml +47 -0
- 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
|
+
}
|