rubyfb 0.5.2-x86-linux
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/CHANGELOG +6 -0
- data/LICENSE +411 -0
- data/Manifest +73 -0
- data/README +460 -0
- data/Rakefile +20 -0
- data/examples/example01.rb +65 -0
- data/ext/AddUser.c +464 -0
- data/ext/AddUser.h +37 -0
- data/ext/Backup.c +783 -0
- data/ext/Backup.h +37 -0
- data/ext/Blob.c +421 -0
- data/ext/Blob.h +65 -0
- data/ext/Common.c +54 -0
- data/ext/Common.h +37 -0
- data/ext/Connection.c +863 -0
- data/ext/Connection.h +50 -0
- data/ext/DataArea.c +274 -0
- data/ext/DataArea.h +38 -0
- data/ext/Database.c +449 -0
- data/ext/Database.h +48 -0
- data/ext/FireRuby.c +240 -0
- data/ext/FireRuby.h +50 -0
- data/ext/FireRubyException.c +268 -0
- data/ext/FireRubyException.h +51 -0
- data/ext/Generator.c +689 -0
- data/ext/Generator.h +53 -0
- data/ext/RemoveUser.c +212 -0
- data/ext/RemoveUser.h +37 -0
- data/ext/Restore.c +855 -0
- data/ext/Restore.h +37 -0
- data/ext/ResultSet.c +809 -0
- data/ext/ResultSet.h +60 -0
- data/ext/Row.c +965 -0
- data/ext/Row.h +55 -0
- data/ext/ServiceManager.c +316 -0
- data/ext/ServiceManager.h +48 -0
- data/ext/Services.c +124 -0
- data/ext/Services.h +42 -0
- data/ext/Statement.c +785 -0
- data/ext/Statement.h +62 -0
- data/ext/Transaction.c +684 -0
- data/ext/Transaction.h +50 -0
- data/ext/TypeMap.c +1182 -0
- data/ext/TypeMap.h +51 -0
- data/ext/extconf.rb +28 -0
- data/ext/mkmf.bat +1 -0
- data/lib/SQLType.rb +224 -0
- data/lib/active_record/connection_adapters/rubyfb_adapter.rb +805 -0
- data/lib/mkdoc +1 -0
- data/lib/rubyfb.rb +2 -0
- data/lib/rubyfb_lib.so +0 -0
- data/lib/src.rb +1800 -0
- data/rubyfb.gemspec +31 -0
- data/test/AddRemoveUserTest.rb +56 -0
- data/test/BackupRestoreTest.rb +99 -0
- data/test/BlobTest.rb +57 -0
- data/test/CharacterSetTest.rb +63 -0
- data/test/ConnectionTest.rb +111 -0
- data/test/DDLTest.rb +54 -0
- data/test/DatabaseTest.rb +83 -0
- data/test/GeneratorTest.rb +50 -0
- data/test/KeyTest.rb +140 -0
- data/test/ResultSetTest.rb +162 -0
- data/test/RoleTest.rb +73 -0
- data/test/RowCountTest.rb +65 -0
- data/test/RowTest.rb +203 -0
- data/test/SQLTest.rb +182 -0
- data/test/SQLTypeTest.rb +101 -0
- data/test/ServiceManagerTest.rb +29 -0
- data/test/StatementTest.rb +135 -0
- data/test/TestSetup.rb +11 -0
- data/test/TransactionTest.rb +112 -0
- data/test/TypeTest.rb +92 -0
- data/test/UnitTest.rb +65 -0
- metadata +149 -0
data/ext/TypeMap.c
ADDED
@@ -0,0 +1,1182 @@
|
|
1
|
+
/*------------------------------------------------------------------------------
|
2
|
+
* TypeMap.c
|
3
|
+
*----------------------------------------------------------------------------*/
|
4
|
+
/**
|
5
|
+
* Copyright � Peter Wood, 2005
|
6
|
+
*
|
7
|
+
* The contents of this file are subject to the Mozilla Public License Version
|
8
|
+
* 1.1 (the "License"); you may not use this file except in compliance with the
|
9
|
+
* License. You may obtain a copy of the License at
|
10
|
+
*
|
11
|
+
* http://www.mozilla.org/MPL/
|
12
|
+
*
|
13
|
+
* Software distributed under the License is distributed on an "AS IS" basis,
|
14
|
+
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
|
15
|
+
* the specificlanguage governing rights and limitations under the License.
|
16
|
+
*
|
17
|
+
* The Original Code is the FireRuby extension for the Ruby language.
|
18
|
+
*
|
19
|
+
* The Initial Developer of the Original Code is Peter Wood. All Rights
|
20
|
+
* Reserved.
|
21
|
+
*
|
22
|
+
* @author Peter Wood
|
23
|
+
* @version 1.0
|
24
|
+
*/
|
25
|
+
|
26
|
+
/* Includes. */
|
27
|
+
#include "TypeMap.h"
|
28
|
+
#include <time.h>
|
29
|
+
#include <math.h>
|
30
|
+
#include <limits.h>
|
31
|
+
#include "Blob.h"
|
32
|
+
#include "Connection.h"
|
33
|
+
#include "Transaction.h"
|
34
|
+
#include "ResultSet.h"
|
35
|
+
#include "Statement.h"
|
36
|
+
#include "FireRuby.h"
|
37
|
+
|
38
|
+
#ifdef OS_UNIX
|
39
|
+
#include <inttypes.h>
|
40
|
+
#else
|
41
|
+
typedef short int16_t;
|
42
|
+
typedef long int32_t;
|
43
|
+
typedef long long int64_t;
|
44
|
+
#endif
|
45
|
+
|
46
|
+
/* Function prototypes. */
|
47
|
+
VALUE createDate(const struct tm *);
|
48
|
+
VALUE createDateTime(VALUE dt);
|
49
|
+
VALUE createTime(VALUE dt);
|
50
|
+
VALUE createSafeTime(const struct tm*);
|
51
|
+
VALUE getConstant(const char *, VALUE);
|
52
|
+
VALUE toDateTime(VALUE);
|
53
|
+
VALUE rescueConvert(VALUE, VALUE);
|
54
|
+
void storeBlob(VALUE, XSQLVAR *, ConnectionHandle *, TransactionHandle *);
|
55
|
+
void populateBlobField(VALUE, XSQLVAR *, VALUE);
|
56
|
+
void populateDoubleField(VALUE, XSQLVAR *);
|
57
|
+
void populateFloatField(VALUE, XSQLVAR *);
|
58
|
+
void populateInt64Field(VALUE, XSQLVAR *);
|
59
|
+
void populateLongField(VALUE, XSQLVAR *);
|
60
|
+
void populateShortField(VALUE, XSQLVAR *);
|
61
|
+
void populateTextField(VALUE, XSQLVAR *);
|
62
|
+
void populateDateField(VALUE, XSQLVAR *);
|
63
|
+
void populateTimeField(VALUE, XSQLVAR *);
|
64
|
+
void populateTimestampField(VALUE, XSQLVAR *);
|
65
|
+
|
66
|
+
|
67
|
+
/**
|
68
|
+
* This function converts a single XSQLVAR entry to a Ruby VALUE type.
|
69
|
+
*
|
70
|
+
* @param entry A pointer to the SQLVAR type containing the data to be
|
71
|
+
* converted.
|
72
|
+
* @param database A pointer to the database handle relating to the data.
|
73
|
+
* @param transaction A pointer to the transaction handle relating to the
|
74
|
+
* data.
|
75
|
+
*
|
76
|
+
* @return A Ruby type for the XSQLVAR entry. The actual type will depend on
|
77
|
+
* the field type referenced.
|
78
|
+
*
|
79
|
+
*/
|
80
|
+
VALUE toValue(XSQLVAR *entry,
|
81
|
+
isc_db_handle *database,
|
82
|
+
isc_tr_handle *transaction)
|
83
|
+
{
|
84
|
+
VALUE value = rb_ary_new();
|
85
|
+
|
86
|
+
/* Check for NULL values. */
|
87
|
+
if(!((entry->sqltype & 1) && (*entry->sqlind < 0)))
|
88
|
+
{
|
89
|
+
int type = (entry->sqltype & ~1);
|
90
|
+
char *array = NULL,
|
91
|
+
column[256],
|
92
|
+
table[256];
|
93
|
+
struct tm datetime;
|
94
|
+
short length;
|
95
|
+
double actual;
|
96
|
+
BlobHandle *blob = NULL;
|
97
|
+
VALUE setting = getFireRubySetting("DATE_AS_DATE"),
|
98
|
+
working = Qnil;
|
99
|
+
|
100
|
+
switch(type)
|
101
|
+
{
|
102
|
+
case SQL_ARRAY : /* Type: ARRAY */
|
103
|
+
/* TO BE DONE! */
|
104
|
+
break;
|
105
|
+
|
106
|
+
case SQL_BLOB: /* Type: BLOB */
|
107
|
+
memset(column, 0, 256);
|
108
|
+
memset(table, 0, 256);
|
109
|
+
memcpy(column, entry->sqlname, entry->sqlname_length);
|
110
|
+
memcpy(table, entry->relname, entry->relname_length);
|
111
|
+
blob = openBlob(*(ISC_QUAD *)entry->sqldata, column, table, database,
|
112
|
+
transaction);
|
113
|
+
working = Data_Wrap_Struct(cBlob, NULL, blobFree, blob);
|
114
|
+
rb_ary_push(value, initializeBlob(working));
|
115
|
+
rb_ary_push(value, getColumnType(entry));
|
116
|
+
break;
|
117
|
+
|
118
|
+
case SQL_TYPE_DATE : /* Type: DATE */
|
119
|
+
memset(&datetime, 0, sizeof(struct tm));
|
120
|
+
isc_decode_sql_date((ISC_DATE *)entry->sqldata, &datetime);
|
121
|
+
datetime.tm_sec = 0;
|
122
|
+
datetime.tm_min = 0;
|
123
|
+
datetime.tm_hour = 0;
|
124
|
+
if(setting == Qtrue)
|
125
|
+
{
|
126
|
+
rb_ary_push(value, createDate(&datetime));
|
127
|
+
}
|
128
|
+
else
|
129
|
+
{
|
130
|
+
rb_ary_push(value, createSafeTime(&datetime));
|
131
|
+
}
|
132
|
+
rb_ary_push(value, getColumnType(entry));
|
133
|
+
break;
|
134
|
+
|
135
|
+
case SQL_DOUBLE : /* Type: DOUBLE PRECISION, DECIMAL, NUMERIC */
|
136
|
+
rb_ary_push(value, rb_float_new(*((double *)entry->sqldata)));
|
137
|
+
rb_ary_push(value, getColumnType(entry));
|
138
|
+
break;
|
139
|
+
|
140
|
+
case SQL_FLOAT : /* Type: FLOAT */
|
141
|
+
rb_ary_push(value, rb_float_new(*((float *)entry->sqldata)));
|
142
|
+
rb_ary_push(value, getColumnType(entry));
|
143
|
+
break;
|
144
|
+
|
145
|
+
case SQL_INT64 : /* Type: DECIMAL, NUMERIC */
|
146
|
+
if(entry->sqlscale != 0)
|
147
|
+
{
|
148
|
+
double divisor = pow(10, abs(entry->sqlscale));
|
149
|
+
|
150
|
+
actual = *((long long *)entry->sqldata);
|
151
|
+
rb_ary_push(value, rb_float_new(actual / divisor));
|
152
|
+
}
|
153
|
+
else
|
154
|
+
{
|
155
|
+
rb_ary_push(value, LL2NUM(*((long long *)entry->sqldata)));
|
156
|
+
}
|
157
|
+
rb_ary_push(value, getColumnType(entry));
|
158
|
+
break;
|
159
|
+
|
160
|
+
case SQL_LONG : /* Type: INTEGER, DECIMAL, NUMERIC */
|
161
|
+
if(entry->sqlscale != 0)
|
162
|
+
{
|
163
|
+
double divisor = pow(10, abs(entry->sqlscale));
|
164
|
+
|
165
|
+
actual = *((int32_t *)entry->sqldata);
|
166
|
+
rb_ary_push(value, rb_float_new(actual / divisor));
|
167
|
+
}
|
168
|
+
else
|
169
|
+
{
|
170
|
+
rb_ary_push(value, LONG2NUM(*((int32_t *)entry->sqldata)));
|
171
|
+
}
|
172
|
+
rb_ary_push(value, getColumnType(entry));
|
173
|
+
break;
|
174
|
+
|
175
|
+
case SQL_SHORT : /* Type: SMALLINT, DECIMAL, NUMERIC */
|
176
|
+
if(entry->sqlscale != 0)
|
177
|
+
{
|
178
|
+
double divisor = pow(10, abs(entry->sqlscale));
|
179
|
+
|
180
|
+
actual = *((short *)entry->sqldata);
|
181
|
+
rb_ary_push(value, rb_float_new(actual / divisor));
|
182
|
+
}
|
183
|
+
else
|
184
|
+
{
|
185
|
+
rb_ary_push(value, INT2NUM(*((short *)entry->sqldata)));
|
186
|
+
}
|
187
|
+
rb_ary_push(value, getColumnType(entry));
|
188
|
+
break;
|
189
|
+
|
190
|
+
case SQL_TEXT : /* Type: CHAR */
|
191
|
+
array = ALLOC_N(char, entry->sqllen + 1);
|
192
|
+
if(array != NULL)
|
193
|
+
{
|
194
|
+
memset(array, 0, entry->sqllen + 1);
|
195
|
+
memcpy(array, entry->sqldata, entry->sqllen);
|
196
|
+
rb_ary_push(value, rb_str_new2(array));
|
197
|
+
rb_ary_push(value, getColumnType(entry));
|
198
|
+
free(array);
|
199
|
+
}
|
200
|
+
break;
|
201
|
+
|
202
|
+
case SQL_TYPE_TIME : /* Type: TIME */
|
203
|
+
isc_decode_sql_time((ISC_TIME *)entry->sqldata, &datetime);
|
204
|
+
datetime.tm_year = 70;
|
205
|
+
datetime.tm_mon = 0;
|
206
|
+
datetime.tm_mday = 1;
|
207
|
+
rb_ary_push(value, createSafeTime(&datetime));
|
208
|
+
rb_ary_push(value, getColumnType(entry));
|
209
|
+
break;
|
210
|
+
|
211
|
+
case SQL_TIMESTAMP : /* Type: TIMESTAMP */
|
212
|
+
isc_decode_timestamp((ISC_TIMESTAMP *)entry->sqldata, &datetime);
|
213
|
+
rb_ary_push(value, createSafeTime(&datetime));
|
214
|
+
rb_ary_push(value, getColumnType(entry));
|
215
|
+
break;
|
216
|
+
|
217
|
+
case SQL_VARYING :
|
218
|
+
memcpy(&length, entry->sqldata, 2);
|
219
|
+
if(length >= 0)
|
220
|
+
{
|
221
|
+
array = ALLOC_N(char, length + 1);
|
222
|
+
if(array != NULL)
|
223
|
+
{
|
224
|
+
memset(array, 0, length + 1);
|
225
|
+
memcpy(array, &entry->sqldata[2], length);
|
226
|
+
rb_ary_push(value, rb_str_new2(array));
|
227
|
+
rb_ary_push(value, getColumnType(entry));
|
228
|
+
free(array);
|
229
|
+
}
|
230
|
+
}
|
231
|
+
break;
|
232
|
+
|
233
|
+
default :
|
234
|
+
rb_ary_push(value, Qnil);
|
235
|
+
rb_ary_push(value, Qnil);
|
236
|
+
} /* End of switch. */
|
237
|
+
}
|
238
|
+
else
|
239
|
+
{
|
240
|
+
rb_ary_push(value, Qnil);
|
241
|
+
rb_ary_push(value, getColumnType(entry));
|
242
|
+
}
|
243
|
+
|
244
|
+
return(value);
|
245
|
+
}
|
246
|
+
|
247
|
+
|
248
|
+
/**
|
249
|
+
* This function attempts to convert the data contents of a XSQLDA to a Ruby
|
250
|
+
* array of values.
|
251
|
+
*
|
252
|
+
* @param results A reference to the ResultSet object to extract the data row
|
253
|
+
* from.
|
254
|
+
*
|
255
|
+
* @return A reference to the array containing the row data from the XSQLDA.
|
256
|
+
*
|
257
|
+
*/
|
258
|
+
VALUE toArray(VALUE results)
|
259
|
+
{
|
260
|
+
VALUE array = rb_ary_new(),
|
261
|
+
transaction = rb_iv_get(results, "@transaction"),
|
262
|
+
connection = rb_iv_get(results, "@connection");
|
263
|
+
XSQLVAR *entry = NULL;
|
264
|
+
ConnectionHandle *cHandle = NULL;
|
265
|
+
ResultsHandle *rHandle = NULL;
|
266
|
+
TransactionHandle *tHandle = NULL;
|
267
|
+
int i;
|
268
|
+
|
269
|
+
Data_Get_Struct(connection, ConnectionHandle, cHandle);
|
270
|
+
Data_Get_Struct(results, ResultsHandle, rHandle);
|
271
|
+
Data_Get_Struct(transaction, TransactionHandle, tHandle);
|
272
|
+
entry = rHandle->output->sqlvar;
|
273
|
+
for(i = 0; i < rHandle->output->sqln; i++, entry++)
|
274
|
+
{
|
275
|
+
VALUE value = toValue(entry, &cHandle->handle, &tHandle->handle);
|
276
|
+
|
277
|
+
rb_ary_push(array, value);
|
278
|
+
}
|
279
|
+
|
280
|
+
return(array);
|
281
|
+
}
|
282
|
+
|
283
|
+
|
284
|
+
/**
|
285
|
+
* This function takes an array of parameters and populates the parameter set
|
286
|
+
* for a Statement object with the details. Attempts are made to convert the
|
287
|
+
* parameter types where appropriate but, if this isn't possible then an
|
288
|
+
* exception is generated.
|
289
|
+
*
|
290
|
+
* @param parameters A pointer to the XSQLDA area that will be used to
|
291
|
+
* hold the parameter data.
|
292
|
+
* @param array A reference to an array containing the parameter data to
|
293
|
+
* be used.
|
294
|
+
* @param source Either a Statement or ResultSet object that can be used
|
295
|
+
* to get connection and transaction details.
|
296
|
+
*
|
297
|
+
*/
|
298
|
+
void setParameters(XSQLDA *parameters, VALUE array, VALUE source)
|
299
|
+
{
|
300
|
+
VALUE value;
|
301
|
+
int index,
|
302
|
+
size;
|
303
|
+
XSQLVAR *parameter = NULL;
|
304
|
+
|
305
|
+
/* Check that sufficient parameters have been provided. */
|
306
|
+
value = rb_funcall(array, rb_intern("size"), 0);
|
307
|
+
size = (TYPE(value) == T_FIXNUM ? FIX2INT(value) : NUM2INT(value));
|
308
|
+
parameter = parameters->sqlvar;
|
309
|
+
if(size != parameters->sqld)
|
310
|
+
{
|
311
|
+
rb_raise(rb_eException,
|
312
|
+
"Parameter set mismatch. Too many or too few parameters "\
|
313
|
+
"specified for a SQL statement.");
|
314
|
+
}
|
315
|
+
parameters->sqln = parameters->sqld;
|
316
|
+
parameters->version = 1;
|
317
|
+
|
318
|
+
/* Populate the parameters from the array's contents. */
|
319
|
+
for(index = 0; index < size; index++, parameter++)
|
320
|
+
{
|
321
|
+
int type = (parameter->sqltype & ~1);
|
322
|
+
|
323
|
+
value = rb_ary_entry(array, index);
|
324
|
+
/* Check for nils to indicate null values. */
|
325
|
+
if(value != Qnil)
|
326
|
+
{
|
327
|
+
VALUE name = rb_funcall(value, rb_intern("class"), 0);
|
328
|
+
|
329
|
+
parameter->sqlind = 0;
|
330
|
+
name = rb_funcall(name, rb_intern("name"), 0);
|
331
|
+
switch(type)
|
332
|
+
{
|
333
|
+
case SQL_ARRAY : /* Type: ARRAY */
|
334
|
+
/* TO BE DONE! */
|
335
|
+
break;
|
336
|
+
|
337
|
+
case SQL_BLOB: /* Type: BLOB */
|
338
|
+
populateBlobField(value, parameter, source);
|
339
|
+
break;
|
340
|
+
|
341
|
+
case SQL_DOUBLE : /* Type: DOUBLE PRECISION, DECIMAL, NUMERIC */
|
342
|
+
populateDoubleField(value, parameter);
|
343
|
+
break;
|
344
|
+
|
345
|
+
case SQL_FLOAT : /* Type: FLOAT */
|
346
|
+
populateFloatField(value, parameter);
|
347
|
+
break;
|
348
|
+
|
349
|
+
case SQL_INT64 : /* Type: DECIMAL, NUMERIC */
|
350
|
+
populateInt64Field(value, parameter);
|
351
|
+
break;
|
352
|
+
|
353
|
+
case SQL_LONG : /* Type: INTEGER, DECIMAL, NUMERIC */
|
354
|
+
populateLongField(value, parameter);
|
355
|
+
break;
|
356
|
+
|
357
|
+
case SQL_SHORT : /* Type: SMALLINT, DECIMAL, NUMERIC */
|
358
|
+
populateShortField(value, parameter);
|
359
|
+
break;
|
360
|
+
|
361
|
+
case SQL_TEXT : /* Type: CHAR */
|
362
|
+
populateTextField(value, parameter);
|
363
|
+
break;
|
364
|
+
|
365
|
+
case SQL_TYPE_DATE : /* Type: DATE */
|
366
|
+
populateDateField(value, parameter);
|
367
|
+
break;
|
368
|
+
|
369
|
+
case SQL_TYPE_TIME : /* Type: TIME */
|
370
|
+
populateTimeField(value, parameter);
|
371
|
+
break;
|
372
|
+
|
373
|
+
case SQL_TIMESTAMP : /* Type: TIMESTAMP */
|
374
|
+
populateTimestampField(value, parameter);
|
375
|
+
break;
|
376
|
+
|
377
|
+
case SQL_VARYING : /* Type: VARCHAR */
|
378
|
+
populateTextField(value, parameter);
|
379
|
+
break;
|
380
|
+
|
381
|
+
default :
|
382
|
+
rb_raise(rb_eException,
|
383
|
+
"Unknown SQL type encountered in statement parameter "\
|
384
|
+
"set.");
|
385
|
+
} /* End of the switch statement. */
|
386
|
+
}
|
387
|
+
else
|
388
|
+
{
|
389
|
+
/* Mark the field as a NULL value. */
|
390
|
+
memset(parameter->sqldata, 0, parameter->sqllen);
|
391
|
+
*parameter->sqlind = -1;
|
392
|
+
}
|
393
|
+
}
|
394
|
+
}
|
395
|
+
|
396
|
+
|
397
|
+
/**
|
398
|
+
* This function converts a struct tm to a Ruby Date instance.
|
399
|
+
*
|
400
|
+
* @param date A structure containing the date details.
|
401
|
+
*
|
402
|
+
* @return A Ruby Date object.
|
403
|
+
*
|
404
|
+
*/
|
405
|
+
VALUE createDate(const struct tm *date)
|
406
|
+
{
|
407
|
+
VALUE result = Qnil,
|
408
|
+
klass = Qnil;
|
409
|
+
|
410
|
+
klass = getClass("Date");
|
411
|
+
|
412
|
+
/* Check if we need to require date. */
|
413
|
+
if(klass == Qnil)
|
414
|
+
{
|
415
|
+
rb_require("date");
|
416
|
+
klass = getClass("Date");
|
417
|
+
}
|
418
|
+
|
419
|
+
/* Check that we got the Date class. */
|
420
|
+
if(klass != Qnil)
|
421
|
+
{
|
422
|
+
VALUE arguments[3];
|
423
|
+
|
424
|
+
/* Prepare the arguments. */
|
425
|
+
arguments[0] = INT2FIX(date->tm_year + 1900);
|
426
|
+
arguments[1] = INT2FIX(date->tm_mon + 1);
|
427
|
+
arguments[2] = INT2FIX(date->tm_mday);
|
428
|
+
|
429
|
+
/* Create the class instance. */
|
430
|
+
result = rb_funcall2(klass, rb_intern("new"), 3, arguments);
|
431
|
+
}
|
432
|
+
|
433
|
+
|
434
|
+
return(result);
|
435
|
+
}
|
436
|
+
|
437
|
+
|
438
|
+
/**
|
439
|
+
* This function converts a struct tm to a Ruby DateTime instance.
|
440
|
+
*
|
441
|
+
* @param datetime A structure containing the date/time details.
|
442
|
+
*
|
443
|
+
* @return A Ruby DateTime object.
|
444
|
+
*
|
445
|
+
*/
|
446
|
+
VALUE createDateTime(VALUE dt)
|
447
|
+
{
|
448
|
+
VALUE result = Qnil,
|
449
|
+
klass = Qnil;
|
450
|
+
|
451
|
+
struct tm *datetime;
|
452
|
+
Data_Get_Struct(dt, struct tm, datetime);
|
453
|
+
|
454
|
+
klass = getClass("DateTime");
|
455
|
+
|
456
|
+
/* Check if we need to require date. */
|
457
|
+
if(klass == Qnil)
|
458
|
+
{
|
459
|
+
rb_require("date");
|
460
|
+
klass = getClass("DateTime");
|
461
|
+
}
|
462
|
+
|
463
|
+
/* Check that we got the DateTime class. */
|
464
|
+
if(klass != Qnil)
|
465
|
+
{
|
466
|
+
VALUE arguments[7];
|
467
|
+
|
468
|
+
/* Prepare the arguments. */
|
469
|
+
arguments[0] = INT2FIX(datetime->tm_year + 1900);
|
470
|
+
arguments[1] = INT2FIX(datetime->tm_mon + 1);
|
471
|
+
arguments[2] = INT2FIX(datetime->tm_mday);
|
472
|
+
arguments[3] = INT2FIX(datetime->tm_hour);
|
473
|
+
arguments[4] = INT2FIX(datetime->tm_min);
|
474
|
+
arguments[5] = INT2FIX(datetime->tm_sec);
|
475
|
+
arguments[6] = rb_funcall(rb_funcall(klass, rb_intern("now"), 0), rb_intern("offset"), 0);
|
476
|
+
|
477
|
+
/* Create the class instance. */
|
478
|
+
result = rb_funcall2(klass, rb_intern("new"), 7, arguments);
|
479
|
+
}
|
480
|
+
|
481
|
+
return(result);
|
482
|
+
}
|
483
|
+
|
484
|
+
|
485
|
+
/**
|
486
|
+
* This function converts a struct tm to a Ruby Time instance.
|
487
|
+
*
|
488
|
+
* @param datetime A structure containing the date/time details.
|
489
|
+
*
|
490
|
+
* @return A Ruby Time object.
|
491
|
+
*
|
492
|
+
*/
|
493
|
+
VALUE createTime(VALUE dt)
|
494
|
+
{
|
495
|
+
VALUE result = Qnil,
|
496
|
+
klass = Qnil;
|
497
|
+
|
498
|
+
struct tm *datetime;
|
499
|
+
Data_Get_Struct(dt, struct tm, datetime);
|
500
|
+
|
501
|
+
klass = getClass("Time");
|
502
|
+
|
503
|
+
/* Check that we got the Time class. */
|
504
|
+
if(klass != Qnil)
|
505
|
+
{
|
506
|
+
VALUE arguments[6];
|
507
|
+
|
508
|
+
/* Prepare the arguments. */
|
509
|
+
/*fprintf(stderr, "%d-%d-%d %d:%d:%d\n", datetime->tm_year + 1900,
|
510
|
+
datetime->tm_mon + 1, datetime->tm_mday, datetime->tm_hour,
|
511
|
+
datetime->tm_min, datetime->tm_sec);*/
|
512
|
+
arguments[0] = INT2FIX(datetime->tm_year + 1900);
|
513
|
+
arguments[1] = INT2FIX(datetime->tm_mon + 1);
|
514
|
+
arguments[2] = INT2FIX(datetime->tm_mday);
|
515
|
+
arguments[3] = INT2FIX(datetime->tm_hour);
|
516
|
+
arguments[4] = INT2FIX(datetime->tm_min);
|
517
|
+
arguments[5] = INT2FIX(datetime->tm_sec);
|
518
|
+
|
519
|
+
/* Create the class instance. */
|
520
|
+
result = rb_funcall2(klass, rb_intern("local"), 6, arguments);
|
521
|
+
}
|
522
|
+
|
523
|
+
return(result);
|
524
|
+
}
|
525
|
+
|
526
|
+
/**
|
527
|
+
* This function converts a struct tm to a Ruby Time instance.
|
528
|
+
* If the conversion process results in an out of range error then
|
529
|
+
* it will convert the struct to a DateTime instance.
|
530
|
+
*
|
531
|
+
* @param datetime A structure containing the date/time details.
|
532
|
+
*
|
533
|
+
* @return A Ruby Time object if the arguments are in range, otherwise
|
534
|
+
* a Ruby DateTime object.
|
535
|
+
*
|
536
|
+
*/
|
537
|
+
VALUE createSafeTime(const struct tm *datetime)
|
538
|
+
{
|
539
|
+
VALUE dt = Data_Wrap_Struct(rb_cObject, NULL, NULL, datetime);
|
540
|
+
return rb_rescue(createTime, dt, createDateTime, dt);
|
541
|
+
}
|
542
|
+
|
543
|
+
/**
|
544
|
+
* This method fetches a Ruby constant definition. If the module specified to
|
545
|
+
* the function is nil then the top level is assume
|
546
|
+
*
|
547
|
+
* @param name The name of the constant to be retrieved.
|
548
|
+
* @param module A reference to the Ruby module that should contain the
|
549
|
+
* constant.
|
550
|
+
*
|
551
|
+
* @return A Ruby VALUE representing the constant.
|
552
|
+
*
|
553
|
+
*/
|
554
|
+
VALUE getConstant(const char *name, VALUE module)
|
555
|
+
{
|
556
|
+
VALUE owner = module,
|
557
|
+
constants,
|
558
|
+
string,
|
559
|
+
exists,
|
560
|
+
entry;
|
561
|
+
|
562
|
+
/* Check that we've got somewhere to look. */
|
563
|
+
if(owner == Qnil)
|
564
|
+
{
|
565
|
+
owner = rb_cModule;
|
566
|
+
}
|
567
|
+
constants = rb_funcall(owner, rb_intern("constants"), 0),
|
568
|
+
string = rb_str_new2(name),
|
569
|
+
exists = rb_funcall(constants, rb_intern("include?"), 1, string);
|
570
|
+
|
571
|
+
if(exists != Qfalse)
|
572
|
+
{
|
573
|
+
ID id = rb_intern(name);
|
574
|
+
VALUE symbol = ID2SYM(id);
|
575
|
+
|
576
|
+
entry = rb_funcall(owner, rb_intern("const_get"), 1, symbol);
|
577
|
+
}
|
578
|
+
|
579
|
+
return(entry);
|
580
|
+
}
|
581
|
+
|
582
|
+
|
583
|
+
/**
|
584
|
+
* This method fetches a Ruby module definition object based on a class name.
|
585
|
+
* The method is assumed to have been defined at the top level.
|
586
|
+
*
|
587
|
+
* @return A Ruby VALUE representing the Module requested, or nil if the
|
588
|
+
* module could not be located.
|
589
|
+
*
|
590
|
+
*/
|
591
|
+
VALUE getModule(const char *name)
|
592
|
+
{
|
593
|
+
VALUE module = getConstant(name, Qnil);
|
594
|
+
|
595
|
+
if(module != Qnil)
|
596
|
+
{
|
597
|
+
VALUE type = rb_funcall(module, rb_intern("class"), 0);
|
598
|
+
|
599
|
+
if(type != rb_cModule)
|
600
|
+
{
|
601
|
+
module = Qnil;
|
602
|
+
}
|
603
|
+
}
|
604
|
+
|
605
|
+
return(module);
|
606
|
+
}
|
607
|
+
|
608
|
+
|
609
|
+
/**
|
610
|
+
* This method fetches a Ruby class definition object based on a class name.
|
611
|
+
* The class is assumed to have been defined at the top level.
|
612
|
+
*
|
613
|
+
* @return A Ruby VALUE representing the requested class, or nil if the class
|
614
|
+
* could not be found.
|
615
|
+
*
|
616
|
+
*/
|
617
|
+
VALUE getClass(const char *name)
|
618
|
+
{
|
619
|
+
VALUE klass = getConstant(name, Qnil);
|
620
|
+
|
621
|
+
if(klass != Qnil)
|
622
|
+
{
|
623
|
+
VALUE type = rb_funcall(klass, rb_intern("class"), 0);
|
624
|
+
|
625
|
+
if(type != rb_cClass)
|
626
|
+
{
|
627
|
+
klass = Qnil;
|
628
|
+
}
|
629
|
+
}
|
630
|
+
|
631
|
+
return(klass);
|
632
|
+
}
|
633
|
+
|
634
|
+
|
635
|
+
/**
|
636
|
+
* This method fetches a module from a specified module.
|
637
|
+
*
|
638
|
+
* @param name The name of the class to fetch.
|
639
|
+
* @param owner The module to search for the module in.
|
640
|
+
*
|
641
|
+
* @return A Ruby VALUE representing the requested module, or nil if it could
|
642
|
+
* not be located.
|
643
|
+
*
|
644
|
+
*/
|
645
|
+
VALUE getModuleInModule(const char *name, VALUE owner)
|
646
|
+
{
|
647
|
+
VALUE module = getConstant(name, owner);
|
648
|
+
|
649
|
+
if(module != Qnil)
|
650
|
+
{
|
651
|
+
VALUE type = rb_funcall(module, rb_intern("class"), 0);
|
652
|
+
|
653
|
+
if(type != rb_cModule)
|
654
|
+
{
|
655
|
+
module = Qnil;
|
656
|
+
}
|
657
|
+
}
|
658
|
+
|
659
|
+
return(module);
|
660
|
+
}
|
661
|
+
|
662
|
+
|
663
|
+
/**
|
664
|
+
* This function fetches a class from a specified module.
|
665
|
+
*
|
666
|
+
* @param name The name of the class to be retrieved.
|
667
|
+
* @param owner The module to search for the class in.
|
668
|
+
*
|
669
|
+
* @return A Ruby VALUE representing the requested module, or nil if it could
|
670
|
+
* not be located.
|
671
|
+
*
|
672
|
+
*/
|
673
|
+
VALUE getClassInModule(const char *name, VALUE owner)
|
674
|
+
{
|
675
|
+
VALUE klass = getConstant(name, owner);
|
676
|
+
|
677
|
+
if(klass != Qnil)
|
678
|
+
{
|
679
|
+
VALUE type = rb_funcall(klass, rb_intern("class"), 0);
|
680
|
+
|
681
|
+
if(type != rb_cClass)
|
682
|
+
{
|
683
|
+
klass = Qnil;
|
684
|
+
}
|
685
|
+
}
|
686
|
+
|
687
|
+
return(klass);
|
688
|
+
}
|
689
|
+
|
690
|
+
|
691
|
+
/**
|
692
|
+
* This function attempts to convert a VALUE to a series of date/time values.
|
693
|
+
*
|
694
|
+
* @param value A reference to the value to be converted.
|
695
|
+
*
|
696
|
+
* @return A VALUE that represents an array containing the date/time details
|
697
|
+
* in the order year, month, day of month, hours, minutes and seconds.
|
698
|
+
*
|
699
|
+
*/
|
700
|
+
VALUE toDateTime(VALUE value)
|
701
|
+
{
|
702
|
+
VALUE result,
|
703
|
+
klass = rb_funcall(value, rb_intern("class"), 0);
|
704
|
+
|
705
|
+
if(klass == rb_cTime)
|
706
|
+
{
|
707
|
+
VALUE data;
|
708
|
+
|
709
|
+
result = rb_ary_new();
|
710
|
+
|
711
|
+
data = rb_funcall(value, rb_intern("year"), 0);
|
712
|
+
rb_ary_push(result, INT2FIX(FIX2INT(data) - 1900));
|
713
|
+
data = rb_funcall(value, rb_intern("month"), 0);
|
714
|
+
rb_ary_push(result, INT2FIX(FIX2INT(data) - 1));
|
715
|
+
rb_ary_push(result, rb_funcall(value, rb_intern("day"), 0));
|
716
|
+
rb_ary_push(result, rb_funcall(value, rb_intern("hour"), 0));
|
717
|
+
rb_ary_push(result, rb_funcall(value, rb_intern("min"), 0));
|
718
|
+
rb_ary_push(result, rb_funcall(value, rb_intern("sec"), 0));
|
719
|
+
}
|
720
|
+
else if(klass == getClass("Date"))
|
721
|
+
{
|
722
|
+
VALUE data;
|
723
|
+
|
724
|
+
result = rb_ary_new();
|
725
|
+
|
726
|
+
data = rb_funcall(value, rb_intern("year"), 0);
|
727
|
+
rb_ary_push(result, INT2FIX(FIX2INT(data) - 1900));
|
728
|
+
data = rb_funcall(value, rb_intern("month"), 0);
|
729
|
+
rb_ary_push(result, INT2FIX(FIX2INT(data) - 1));
|
730
|
+
rb_ary_push(result, rb_funcall(value, rb_intern("mday"), 0));
|
731
|
+
rb_ary_push(result, INT2FIX(0));
|
732
|
+
rb_ary_push(result, INT2FIX(0));
|
733
|
+
rb_ary_push(result, INT2FIX(0));
|
734
|
+
}
|
735
|
+
else
|
736
|
+
{
|
737
|
+
rb_raise(rb_eException, "Value conversion error.");
|
738
|
+
}
|
739
|
+
|
740
|
+
return(result);
|
741
|
+
}
|
742
|
+
|
743
|
+
|
744
|
+
/**
|
745
|
+
* This function represents the rescue block for data conversions.
|
746
|
+
*
|
747
|
+
* @param arguments An array of VALUEs. The first is expected to contain the
|
748
|
+
* field offset of the value being converted. The second a
|
749
|
+
* string containing the name of the data type being
|
750
|
+
* converted from and the third a string containing the name
|
751
|
+
* of the data type being converted to.
|
752
|
+
* @param error Will be populates with error details of the exception
|
753
|
+
* raised.
|
754
|
+
*
|
755
|
+
*/
|
756
|
+
VALUE rescueConvert(VALUE arguments, VALUE error)
|
757
|
+
{
|
758
|
+
VALUE message;
|
759
|
+
char text[512];
|
760
|
+
|
761
|
+
sprintf(text, "Error converting input column %d from a %s to a %s.",
|
762
|
+
FIX2INT(rb_ary_entry(arguments, 0)),
|
763
|
+
STR2CSTR(rb_ary_entry(arguments, 1)),
|
764
|
+
STR2CSTR(rb_ary_entry(arguments, 2)));
|
765
|
+
message = rb_str_new2(text);
|
766
|
+
|
767
|
+
return(rb_funcall(rb_eException, rb_intern("exception"), 1, &message));
|
768
|
+
}
|
769
|
+
|
770
|
+
|
771
|
+
/**
|
772
|
+
* This function creates a new blob and returns the identifier for it.
|
773
|
+
*
|
774
|
+
* @param info A pointer to a string containing the blob data.
|
775
|
+
* @param field The field that the blob identifier needs to be inserted
|
776
|
+
* into.
|
777
|
+
* @param database A pointer to the database handle to be used in creating
|
778
|
+
* the blob.
|
779
|
+
* @param transaction A pointer to the transaction handle to be used in
|
780
|
+
* creating the blob.
|
781
|
+
*
|
782
|
+
* @return An ISC_QUAD value containing the identifier for the blob created.
|
783
|
+
*
|
784
|
+
*/
|
785
|
+
void storeBlob(VALUE info,
|
786
|
+
XSQLVAR *field,
|
787
|
+
ConnectionHandle *connection,
|
788
|
+
TransactionHandle *transaction)
|
789
|
+
{
|
790
|
+
ISC_STATUS status[20];
|
791
|
+
isc_blob_handle handle = 0;
|
792
|
+
ISC_QUAD *blobId = (ISC_QUAD *)field->sqldata;
|
793
|
+
VALUE number = rb_funcall(info, rb_intern("length"), 0);
|
794
|
+
long length = 0;
|
795
|
+
char *data = STR2CSTR(info);
|
796
|
+
|
797
|
+
length = TYPE(number) == T_FIXNUM ? FIX2INT(number) : NUM2INT(number);
|
798
|
+
field->sqltype = SQL_BLOB;
|
799
|
+
if(isc_create_blob(status, &connection->handle, &transaction->handle,
|
800
|
+
&handle, blobId) == 0)
|
801
|
+
{
|
802
|
+
long offset = 0;
|
803
|
+
unsigned short size = 0;
|
804
|
+
|
805
|
+
while(offset < length)
|
806
|
+
{
|
807
|
+
char *buffer = &data[offset];
|
808
|
+
|
809
|
+
size = (length - offset) > USHRT_MAX ? USHRT_MAX : length - offset;
|
810
|
+
if(isc_put_segment(status, &handle, size, buffer) != 0)
|
811
|
+
{
|
812
|
+
ISC_STATUS other[20];
|
813
|
+
|
814
|
+
isc_close_blob(other, &handle);
|
815
|
+
rb_fireruby_raise(status, "Error writing blob data.");
|
816
|
+
}
|
817
|
+
|
818
|
+
offset = offset + size;
|
819
|
+
}
|
820
|
+
|
821
|
+
if(isc_close_blob(status, &handle) != 0)
|
822
|
+
{
|
823
|
+
rb_fireruby_raise(status, "Error closing blob.");
|
824
|
+
}
|
825
|
+
}
|
826
|
+
else
|
827
|
+
{
|
828
|
+
rb_fireruby_raise(status, "Error storing blob data.");
|
829
|
+
}
|
830
|
+
}
|
831
|
+
|
832
|
+
|
833
|
+
/**
|
834
|
+
* This function populates a blob output parameter.
|
835
|
+
*
|
836
|
+
* @param value The value to be insert into the blob.
|
837
|
+
* @param field A pointer to the output field to be populated.
|
838
|
+
* @param source A reference to either a Statement or ResultSet object that
|
839
|
+
* contains the connection and transaction details.
|
840
|
+
*
|
841
|
+
*/
|
842
|
+
void populateBlobField(VALUE value, XSQLVAR *field, VALUE source)
|
843
|
+
{
|
844
|
+
VALUE attribute;
|
845
|
+
ConnectionHandle *connection = NULL;
|
846
|
+
TransactionHandle *transaction = NULL;
|
847
|
+
|
848
|
+
if(TYPE(value) != T_STRING)
|
849
|
+
{
|
850
|
+
rb_fireruby_raise(NULL, "Error converting input parameter to blob.");
|
851
|
+
}
|
852
|
+
|
853
|
+
/* Fetch the connection and transaction details. */
|
854
|
+
attribute = rb_iv_get(source, "@connection");
|
855
|
+
Data_Get_Struct(attribute, ConnectionHandle, connection);
|
856
|
+
attribute = rb_iv_get(source, "@transaction");
|
857
|
+
Data_Get_Struct(attribute, TransactionHandle, transaction);
|
858
|
+
storeBlob(value, field, connection, transaction);
|
859
|
+
field->sqltype = SQL_BLOB;
|
860
|
+
}
|
861
|
+
|
862
|
+
|
863
|
+
/**
|
864
|
+
* This method populates a date output field.
|
865
|
+
*
|
866
|
+
* @param value A reference to the value to be used to populate the field.
|
867
|
+
* @param field A pointer to the output field to be populated.
|
868
|
+
*
|
869
|
+
*/
|
870
|
+
void populateDateField(VALUE value, XSQLVAR *field)
|
871
|
+
{
|
872
|
+
struct tm datetime;
|
873
|
+
VALUE arguments = rb_ary_new();
|
874
|
+
|
875
|
+
rb_ary_push(arguments, rb_str_new2("date"));
|
876
|
+
value = rb_rescue(toDateTime, value, rescueConvert, arguments);
|
877
|
+
if(TYPE(value) != T_ARRAY)
|
878
|
+
{
|
879
|
+
VALUE message = rb_funcall(value, rb_intern("message"), 0);
|
880
|
+
rb_fireruby_raise(NULL, STR2CSTR(message));
|
881
|
+
}
|
882
|
+
datetime.tm_year = FIX2INT(rb_ary_entry(value, 0));
|
883
|
+
datetime.tm_mon = FIX2INT(rb_ary_entry(value, 1));
|
884
|
+
datetime.tm_mday = FIX2INT(rb_ary_entry(value, 2));
|
885
|
+
isc_encode_sql_date(&datetime, (ISC_DATE *)field->sqldata);
|
886
|
+
field->sqltype = SQL_TYPE_DATE;
|
887
|
+
}
|
888
|
+
|
889
|
+
|
890
|
+
/**
|
891
|
+
* This method populates a double output field.
|
892
|
+
*
|
893
|
+
* @param value A reference to the value to be used to populate the field.
|
894
|
+
* @param field A pointer to the output field to be populated.
|
895
|
+
*
|
896
|
+
*/
|
897
|
+
void populateDoubleField(VALUE value, XSQLVAR *field)
|
898
|
+
{
|
899
|
+
double store;
|
900
|
+
VALUE actual;
|
901
|
+
|
902
|
+
if(TYPE(value) != T_FLOAT)
|
903
|
+
{
|
904
|
+
if(rb_obj_is_kind_of(value, rb_cNumeric) || TYPE(value) == T_STRING)
|
905
|
+
{
|
906
|
+
actual = rb_funcall(value, rb_intern("to_f"), 0);
|
907
|
+
}
|
908
|
+
else
|
909
|
+
{
|
910
|
+
rb_fireruby_raise(NULL,
|
911
|
+
"Error converting input parameter to double.");
|
912
|
+
}
|
913
|
+
}
|
914
|
+
|
915
|
+
store = NUM2DBL(value);
|
916
|
+
memcpy(field->sqldata, &store, field->sqllen);
|
917
|
+
field->sqltype = SQL_DOUBLE;
|
918
|
+
}
|
919
|
+
|
920
|
+
|
921
|
+
/**
|
922
|
+
* This method populates a double output field.
|
923
|
+
*
|
924
|
+
* @param value A reference to the value to be used to populate the field.
|
925
|
+
* @param field A pointer to the output field to be populated.
|
926
|
+
*
|
927
|
+
*/
|
928
|
+
void populateFloatField(VALUE value, XSQLVAR *field)
|
929
|
+
{
|
930
|
+
double full = 0.0;
|
931
|
+
float store = 0.0;
|
932
|
+
VALUE actual;
|
933
|
+
|
934
|
+
if(TYPE(value) != T_FLOAT)
|
935
|
+
{
|
936
|
+
if(rb_obj_is_kind_of(value, rb_cNumeric) || TYPE(value) == T_STRING)
|
937
|
+
{
|
938
|
+
actual = rb_funcall(value, rb_intern("to_f"), 0);
|
939
|
+
}
|
940
|
+
else
|
941
|
+
{
|
942
|
+
rb_fireruby_raise(NULL,
|
943
|
+
"Error converting input parameter to double.");
|
944
|
+
}
|
945
|
+
}
|
946
|
+
|
947
|
+
full = NUM2DBL(value);
|
948
|
+
store = (float)full;
|
949
|
+
memcpy(field->sqldata, &store, field->sqllen);
|
950
|
+
field->sqltype = SQL_FLOAT;
|
951
|
+
}
|
952
|
+
|
953
|
+
|
954
|
+
/**
|
955
|
+
* This function populates a output parameter field with the data of a Ruby
|
956
|
+
* value.
|
957
|
+
*
|
958
|
+
* @param value A reference to the Ruby value to be inserted into the field.
|
959
|
+
* @param field A pointer to the XSQLVAR field that the value will go into.
|
960
|
+
*
|
961
|
+
*/
|
962
|
+
void populateInt64Field(VALUE value, XSQLVAR *field)
|
963
|
+
{
|
964
|
+
VALUE actual = Qnil;
|
965
|
+
long long store = 0;
|
966
|
+
|
967
|
+
if(rb_obj_is_kind_of(value, rb_cInteger))
|
968
|
+
{
|
969
|
+
actual = value;
|
970
|
+
}
|
971
|
+
else if(TYPE(value) == T_FLOAT)
|
972
|
+
{
|
973
|
+
double number = NUM2DBL(value);
|
974
|
+
|
975
|
+
if(field->sqlscale != 0)
|
976
|
+
{
|
977
|
+
number = number * pow(10, abs(field->sqlscale));
|
978
|
+
actual = INT2NUM((long)number);
|
979
|
+
}
|
980
|
+
}
|
981
|
+
else if(TYPE(value) == T_STRING)
|
982
|
+
{
|
983
|
+
actual = rb_funcall(value, rb_intern("to_i"), 0);
|
984
|
+
}
|
985
|
+
else
|
986
|
+
{
|
987
|
+
rb_fireruby_raise(NULL,
|
988
|
+
"Error converting input parameter to 64 bit integer.");
|
989
|
+
}
|
990
|
+
|
991
|
+
store = TYPE(actual) == T_FIXNUM ? FIX2INT(actual) : NUM2INT(actual);
|
992
|
+
memcpy(field->sqldata, &store, field->sqllen);
|
993
|
+
field->sqltype = SQL_INT64;
|
994
|
+
}
|
995
|
+
|
996
|
+
|
997
|
+
/**
|
998
|
+
* This function populates a output parameter field with the data of a Ruby
|
999
|
+
* value.
|
1000
|
+
*
|
1001
|
+
* @param value A reference to the Ruby value to be inserted into the field.
|
1002
|
+
* @param field A pointer to the XSQLVAR field that the value will go into.
|
1003
|
+
*
|
1004
|
+
*/
|
1005
|
+
void populateLongField(VALUE value, XSQLVAR *field)
|
1006
|
+
{
|
1007
|
+
VALUE actual = Qnil;
|
1008
|
+
long long full = 0;
|
1009
|
+
long store = 0;
|
1010
|
+
|
1011
|
+
if(rb_obj_is_kind_of(value, rb_cInteger))
|
1012
|
+
{
|
1013
|
+
actual = value;
|
1014
|
+
}
|
1015
|
+
else if(TYPE(value) == T_FLOAT)
|
1016
|
+
{
|
1017
|
+
double number = NUM2DBL(value);
|
1018
|
+
|
1019
|
+
if(field->sqlscale != 0)
|
1020
|
+
{
|
1021
|
+
number = number * pow(10, abs(field->sqlscale));
|
1022
|
+
actual = INT2NUM((long)number);
|
1023
|
+
}
|
1024
|
+
}
|
1025
|
+
else if(TYPE(value) == T_STRING)
|
1026
|
+
{
|
1027
|
+
actual = rb_funcall(value, rb_intern("to_i"), 0);
|
1028
|
+
}
|
1029
|
+
else
|
1030
|
+
{
|
1031
|
+
rb_fireruby_raise(NULL,
|
1032
|
+
"Error converting input parameter to long integer.");
|
1033
|
+
}
|
1034
|
+
|
1035
|
+
full = TYPE(actual) == T_FIXNUM ? FIX2INT(actual) : NUM2INT(actual);
|
1036
|
+
store = (long)full;
|
1037
|
+
memcpy(field->sqldata, &store, field->sqllen);
|
1038
|
+
field->sqltype = SQL_LONG;
|
1039
|
+
}
|
1040
|
+
|
1041
|
+
|
1042
|
+
/**
|
1043
|
+
* This function populates a output parameter field with the data of a Ruby
|
1044
|
+
* value.
|
1045
|
+
*
|
1046
|
+
* @param value A reference to the Ruby value to be inserted into the field.
|
1047
|
+
* @param field A pointer to the XSQLVAR field that the value will go into.
|
1048
|
+
*
|
1049
|
+
*/
|
1050
|
+
void populateShortField(VALUE value, XSQLVAR *field)
|
1051
|
+
{
|
1052
|
+
VALUE actual = Qnil;
|
1053
|
+
long long full = 0;
|
1054
|
+
short store = 0;
|
1055
|
+
|
1056
|
+
if(rb_obj_is_kind_of(value, rb_cInteger))
|
1057
|
+
{
|
1058
|
+
actual = value;
|
1059
|
+
}
|
1060
|
+
else if(TYPE(value) == T_FLOAT)
|
1061
|
+
{
|
1062
|
+
double number = NUM2DBL(value);
|
1063
|
+
|
1064
|
+
if(field->sqlscale != 0)
|
1065
|
+
{
|
1066
|
+
number = number * pow(10, abs(field->sqlscale));
|
1067
|
+
actual = INT2NUM((long)number);
|
1068
|
+
}
|
1069
|
+
}
|
1070
|
+
else if(TYPE(value) == T_STRING)
|
1071
|
+
{
|
1072
|
+
actual = rb_funcall(value, rb_intern("to_i"), 0);
|
1073
|
+
}
|
1074
|
+
else
|
1075
|
+
{
|
1076
|
+
rb_fireruby_raise(NULL,
|
1077
|
+
"Error converting input parameter to short integer.");
|
1078
|
+
}
|
1079
|
+
|
1080
|
+
full = TYPE(actual) == T_FIXNUM ? FIX2INT(actual) : NUM2INT(actual);
|
1081
|
+
store = (short)full;
|
1082
|
+
memcpy(field->sqldata, &store, field->sqllen);
|
1083
|
+
field->sqltype = SQL_SHORT;
|
1084
|
+
}
|
1085
|
+
|
1086
|
+
|
1087
|
+
/**
|
1088
|
+
* This function populates a output parameter field with the data of a Ruby
|
1089
|
+
* value.
|
1090
|
+
*
|
1091
|
+
* @param value A reference to the Ruby value to be inserted into the field.
|
1092
|
+
* @param field A pointer to the XSQLVAR field that the value will go into.
|
1093
|
+
*
|
1094
|
+
*/
|
1095
|
+
void populateTextField(VALUE value, XSQLVAR *field)
|
1096
|
+
{
|
1097
|
+
VALUE actual;
|
1098
|
+
char *text = NULL;
|
1099
|
+
short length = 0;
|
1100
|
+
|
1101
|
+
if(TYPE(value) != T_STRING)
|
1102
|
+
{
|
1103
|
+
actual = value;
|
1104
|
+
}
|
1105
|
+
else
|
1106
|
+
{
|
1107
|
+
actual = rb_funcall(value, rb_intern("to_s"), 0);
|
1108
|
+
}
|
1109
|
+
|
1110
|
+
text = STR2CSTR(actual);
|
1111
|
+
length = strlen(text) > field->sqllen ? field->sqllen : strlen(text);
|
1112
|
+
|
1113
|
+
if((field->sqltype & ~1) == SQL_TEXT)
|
1114
|
+
{
|
1115
|
+
memcpy(field->sqldata, text, length);
|
1116
|
+
field->sqltype = SQL_TEXT;
|
1117
|
+
}
|
1118
|
+
else
|
1119
|
+
{
|
1120
|
+
memcpy(field->sqldata, &length, sizeof(short));
|
1121
|
+
memcpy(&field->sqldata[sizeof(short)], text, length);
|
1122
|
+
field->sqltype = SQL_VARYING;
|
1123
|
+
}
|
1124
|
+
field->sqllen = length;
|
1125
|
+
}
|
1126
|
+
|
1127
|
+
|
1128
|
+
/**
|
1129
|
+
* This method populates a date output field.
|
1130
|
+
*
|
1131
|
+
* @param value A reference to the value to be used to populate the field.
|
1132
|
+
* @param field A pointer to the output field to be populated.
|
1133
|
+
*
|
1134
|
+
*/
|
1135
|
+
void populateTimeField(VALUE value, XSQLVAR *field)
|
1136
|
+
{
|
1137
|
+
struct tm datetime;
|
1138
|
+
VALUE arguments = rb_ary_new();
|
1139
|
+
|
1140
|
+
rb_ary_push(arguments, rb_str_new2("time"));
|
1141
|
+
value = rb_rescue(toDateTime, value, rescueConvert, arguments);
|
1142
|
+
if(TYPE(value) != T_ARRAY)
|
1143
|
+
{
|
1144
|
+
VALUE message = rb_funcall(value, rb_intern("message"), 0);
|
1145
|
+
rb_fireruby_raise(NULL, STR2CSTR(message));
|
1146
|
+
}
|
1147
|
+
datetime.tm_hour = FIX2INT(rb_ary_entry(value, 3));
|
1148
|
+
datetime.tm_min = FIX2INT(rb_ary_entry(value, 4));
|
1149
|
+
datetime.tm_sec = FIX2INT(rb_ary_entry(value, 5));
|
1150
|
+
isc_encode_sql_time(&datetime, (ISC_TIME *)field->sqldata);
|
1151
|
+
field->sqltype = SQL_TYPE_TIME;
|
1152
|
+
}
|
1153
|
+
|
1154
|
+
|
1155
|
+
/**
|
1156
|
+
* This method populates a date output field.
|
1157
|
+
*
|
1158
|
+
* @param value A reference to the value to be used to populate the field.
|
1159
|
+
* @param field A pointer to the output field to be populated.
|
1160
|
+
*
|
1161
|
+
*/
|
1162
|
+
void populateTimestampField(VALUE value, XSQLVAR *field)
|
1163
|
+
{
|
1164
|
+
struct tm datetime;
|
1165
|
+
VALUE arguments = rb_ary_new();
|
1166
|
+
|
1167
|
+
rb_ary_push(arguments, rb_str_new2("timestamp"));
|
1168
|
+
value = rb_rescue(toDateTime, value, rescueConvert, arguments);
|
1169
|
+
if(TYPE(value) != T_ARRAY)
|
1170
|
+
{
|
1171
|
+
VALUE message = rb_funcall(value, rb_intern("message"), 0);
|
1172
|
+
rb_fireruby_raise(NULL, STR2CSTR(message));
|
1173
|
+
}
|
1174
|
+
datetime.tm_year = FIX2INT(rb_ary_entry(value, 0));
|
1175
|
+
datetime.tm_mon = FIX2INT(rb_ary_entry(value, 1));
|
1176
|
+
datetime.tm_mday = FIX2INT(rb_ary_entry(value, 2));
|
1177
|
+
datetime.tm_hour = FIX2INT(rb_ary_entry(value, 3));
|
1178
|
+
datetime.tm_min = FIX2INT(rb_ary_entry(value, 4));
|
1179
|
+
datetime.tm_sec = FIX2INT(rb_ary_entry(value, 5));
|
1180
|
+
isc_encode_timestamp(&datetime, (ISC_TIMESTAMP *)field->sqldata);
|
1181
|
+
field->sqltype = SQL_TIMESTAMP;
|
1182
|
+
}
|