-
Notifications
You must be signed in to change notification settings - Fork 19
Expand file tree
/
Copy pathIscColumnsResultSet.cpp
More file actions
448 lines (387 loc) · 12.3 KB
/
IscColumnsResultSet.cpp
File metadata and controls
448 lines (387 loc) · 12.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
/*
*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed on
* an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
* express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
*
* The Original Code was created by James A. Starkey for IBPhoenix.
*
* Copyright (c) 1999, 2000, 2001 James A. Starkey
* All Rights Reserved.
*
*
* 2003-03-24 IscColumnsResultSet.cpp
* Contributed by Norbert Meyer
* o Add some breaks to case statements in adjustResults()
* VARCHAR storage length is set in function ::setCharLen
* o In IscColumnsResultSet::getBLRLiteral use delete[] s
* instead of delete.s
*
* 2002-11-24 IscColumnsResultSet.cpp
* Contributed by C. G. Alvarez
* Improve handling of NUMERIC and DECIMAL fields
*
*/
// IscColumnsResultSet.cpp: implementation of the IscColumnsResultSet class.
//
//////////////////////////////////////////////////////////////////////
#ifdef DEBUG
#ifdef _WINDOWS
#include <windows.h>
#endif
#endif
#include <stdio.h>
#include <string.h>
#include "IscDbc.h"
#include "IscColumnsResultSet.h"
#include "IscConnection.h"
#include "IscDatabaseMetaData.h"
#include "IscResultSet.h"
#include "IscPreparedStatement.h"
#include "IscBlob.h"
#include "IscSqlType.h"
#include "JString.h"
#define TYPE_NAME 6
#define DEF_VAL 13
#define BUFF_LEN 256
namespace IscDbcLibrary {
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
IscColumnsResultSet::IscColumnsResultSet(IscDatabaseMetaData *metaData)
: IscMetaDataResultSet(metaData)
{
sqlType.appOdbcVersion = metaData->connection->getUseAppOdbcVersion(); // SQL_OV_ODBC2 or SQL_OV_ODBC3
}
void IscColumnsResultSet::initResultSet(IscStatement *stmt)
{
IscResultSet::initResultSet ( stmt );
blob.statement = stmt;
}
void IscColumnsResultSet::getColumns(const char * catalog, const char * schemaPattern, const char * tableNamePattern, const char * fieldNamePattern)
{
char sql[4096] = "";
char * pt = sql;
addString(pt, "select cast( '");
if (catalog && *catalog)
addString(pt, catalog);
addString(pt, "' as varchar(255)) as table_cat,\n" // 1 - VARCHAR
"\tcast (tbl.rdb$owner_name as varchar(" MACRO_TO_STR(MAX_META_IDENT_LEN) ")) as table_schem,\n" // 2 - VARCHAR
"\tcast (rfr.rdb$relation_name as varchar(" MACRO_TO_STR(MAX_META_IDENT_LEN) ")) as table_name,\n" // 3 - VARCHAR NOT NULL
"\tcast (rfr.rdb$field_name as varchar(" MACRO_TO_STR(MAX_META_IDENT_LEN) ")) as column_name,\n" // 4 - VARCHAR NOT NULL
"\tfld.rdb$field_type as data_type,\n" // 5 - SMALLINT NOT NULL
"\tcast (fld.rdb$field_name as varchar(" MACRO_TO_STR(MAX_META_IDENT_LEN) ")) as type_name,\n" // 6 - VARCHAR NOT NULL
"\tcast (fld.rdb$collation_id as integer) as column_size,\n" // 7 - INTEGER
"\tcast (fld.rdb$character_set_id as integer) as buffer_length,\n" // 8 - INTEGER
"\tcast (fld.rdb$field_scale as smallint) as decimal_digits,\n" // 9 - SMALLINT
"\tfld.rdb$field_scale as num_prec_radix,\n" // 10 - SMALLINT
"\trfr.rdb$null_flag as nullable,\n" // 11 - SMALLINT NOT NULL
"\tcast (NULL as char(10)) as remarks,\n" // 12 - VARCHAR
"\tcast (rfr.rdb$field_name as varchar(512)) as column_def,\n" // 13 - VARCHAR
"\tfld.rdb$field_type as SQL_DATA_TYPE,\n" // 14 - SMALLINT NOT NULL
"\tfld.rdb$field_sub_type as SQL_DATETIME_SUB,\n" // 15 - SMALLINT
"\t10 as CHAR_OCTET_LENGTH,\n" // 16 - INTEGER
"\t10 as ordinal_position,\n" // 17 - INTEGER NOT NULL
"\tcast ('YES' as varchar(3)) as IS_NULLABLE,\n" // 18 - VARCHAR
"\tfld.rdb$character_length as char_len,\n" // 19
"\tfld.rdb$default_source as f_def_source,\n" // 20
"\tfld.rdb$dimensions as array_dim,\n" // 21
"\tfld.rdb$null_flag as null_flag,\n" // 22
"\trfr.rdb$field_position as column_position,\n" // 23
"\tfld.rdb$field_length as column_length,\n" // 24
"\tfld.rdb$field_precision as column_precision,\n" // 25
"\trfr.rdb$default_source as column_def\n" // 26
"from rdb$relation_fields rfr, rdb$fields fld, rdb$relations tbl\n"
"where rfr.rdb$field_source = fld.rdb$field_name\n"
" and rfr.rdb$relation_name = tbl.rdb$relation_name\n");
char * ptFirst = sql + strlen(sql);
if (schemaPattern && *schemaPattern)
expandPattern (ptFirst, " and ","tbl.rdb$owner_name", schemaPattern);
if (tableNamePattern && *tableNamePattern)
expandPattern (ptFirst, " and ","rfr.rdb$relation_name", tableNamePattern);
if (fieldNamePattern && *fieldNamePattern)
expandPattern (ptFirst, " and ","rfr.rdb$field_name", fieldNamePattern);
addString(ptFirst, " order by rfr.rdb$relation_name, rfr.rdb$field_position\n");
#ifdef DEBUG
OutputDebugString (sql);
#endif
prepareStatement (sql);
// SELECT returns 26 columns,
// But all interests only 18
// This line is forbidden for modifying!!!
numberColumns = 18;
}
// Legacy types converter
void IscColumnsResultSet::LegacyTypesConversion()
{
if (!sqlda) {
return;
}
static const short INT128_MAX_CHARS = 255;
auto blrType = sqlda->getShort(5);
switch (blrType)
{
case blr_dec64:
case blr_dec128:
sqlda->updateShort(5, blr_double);
sqlda->updateShort(24, 8);
break;
case blr_int128:
sqlda->updateShort(5, blr_varying);
sqlda->updateInt(7, 0); //collation none
sqlda->updateInt(8, 2); //charset ANSI
sqlda->updateInt(16, INT128_MAX_CHARS); //char/octet length
sqlda->updateShort(19, INT128_MAX_CHARS);
sqlda->updateShort(24, INT128_MAX_CHARS);
break;
case blr_sql_time_tz:
case blr_ex_time_tz:
sqlda->updateShort(5, blr_sql_time);
sqlda->updateShort(24, 4);
break;
case blr_timestamp_tz:
case blr_ex_timestamp_tz:
sqlda->updateShort(5, blr_timestamp);
sqlda->updateShort(24, 8);
break;
default:
break;
}
}
bool IscColumnsResultSet::nextFetch()
{
if (!IscResultSet::nextFetch())
{
blob.clear();
return false;
}
//Since I don't know how to implement INT128, DECFLOAT & TIMIZONE just now
//because there are NO appropriate ODBC SQL types in ODBC spec
//we'll tempopary use a legacy types conversion here.
LegacyTypesConversion();
if ( !metaData->getUseSchemaIdentifier() )
sqlda->setNull(2);
int &charLength = sqlType.lengthCharIn;
int &len = sqlType.lengthIn;
charLength = sqlda->getShort (19);
len = sqlda->getShort (24);
sqlType.collationId = sqlda->getInt (7); // COLLATION_ID
sqlType.characterId = sqlda->getInt (8); // CHARACTER_SET_ID
sqlda->updateInt (7, len); // COLUMN_SIZE
sqlda->updateInt (8, len); // BUFFER_LENGTH
sqlda->updateShort (10, 10); // NUM_PREC_RADIX
sqlda->updateInt (16, len); // CHAR_OCTET_LENGTH
sqlda->updateInt (17, sqlda->getShort (23)+1); // ORDINAL_POSITION
//translate to the SQL type information
sqlType.blrType = sqlda->getShort (5); // DATA_TYPE
sqlType.subType = sqlda->getShort (15); // SUB_TYPE
sqlType.scale = sqlda->getShort (9); // DECIMAL_DIGITS
int array = sqlda->getShort (21); // ARRAY_DIMENSION
sqlType.precision = sqlda->getShort (25); // COLUMN_PRECISION
sqlType.dialect = statement->connection->getDatabaseDialect();
sqlType.buildType();
if ( array )
{
int len;
char * relation_name = (char*)sqlda->getVarying ( 3, len);
relation_name[len] = '\0';
char * field_name = (char*)sqlda->getVarying ( 4, len);
field_name[len] = '\0';
arrAttr.loadAttributes ( statement, relation_name, field_name, sqlType.subType );
sqlda->updateVarying (6, arrAttr.getFbSqlType());
sqlda->updateInt (7, arrAttr.arrOctetLength );
sqlda->updateInt (8, arrAttr.getBufferLength());
if ( arrAttr.arrOctetLength < MAX_VARCHAR_LENGTH )
sqlda->updateShort (5, JDBC_VARCHAR);
else
sqlda->updateShort (5, JDBC_LONGVARCHAR);
sqlda->updateInt (16, arrAttr.arrOctetLength );
}
else
{
sqlda->updateVarying (6, sqlType.typeName);
setCharLen (7, 8, sqlType);
sqlda->updateShort (5, sqlType.type);
//Octet length
switch (sqlType.type)
{
case JDBC_VARCHAR:
case JDBC_CHAR:
sqlda->updateInt (16, sqlda->getInt (8));
break;
case JDBC_WVARCHAR:
case JDBC_WCHAR:
sqlda->updateInt (16, sqlType.bufferLength);
break;
default:
sqlda->setNull (16);
}
}
adjustResults (sqlType);
return true;
}
bool IscColumnsResultSet::getDefSource (int indexIn, int indexTarget)
{
if ( sqlda->isNull (indexIn) )
{
sqlda->updateVarying (indexTarget, "NULL");
return false;
}
//XSQLVAR *var = sqlda->Var(indexIn);
auto * var = sqlda->Var( indexIn );
char buffer[1024];
char * beg = buffer + 7; // sizeof("default")
char * end;
int lenRead;
blob.directOpenBlob ((char*)var->sqldata);
blob.directFetchBlob (buffer, 1024, lenRead);
blob.directCloseBlob();
end = buffer + lenRead;
while ( *++beg == ' ' );
while ( *end == ' ' ) end--;
if ( *beg == '\'' && *(beg + 1) != '\'' )
{
++beg;
--end;
}
*end = '\0';
sqlda->updateVarying (indexTarget, beg);
return true;
}
void IscColumnsResultSet::setCharLen (int charLenInd,
int fldLenInd,
IscSqlType &sqlType)
{
int fldLen = sqlda->getInt (fldLenInd);
int charLen = sqlda->getInt (charLenInd);
if ( sqlda->isNull(charLenInd) )
charLen = fldLen;
if (sqlType.type != JDBC_VARCHAR &&
sqlType.type != JDBC_CHAR)
{
charLen = sqlType.length;
fldLen = sqlType.bufferLength;
}
sqlda->updateInt (fldLenInd, fldLen);
if (!charLen)
sqlda->setNull (charLenInd);
else
sqlda->updateInt (charLenInd, charLen);
}
void IscColumnsResultSet::checkQuotes (IscSqlType &sqlType, JString stringVal)
{
// Revolting ODBC wants the default value quoted unless its a
// number or a pseudo-literal
JString string = stringVal;
string.upcase (string);
switch (sqlType.type)
{
case JDBC_DATE:
case JDBC_SQL_DATE:
case JDBC_TIME:
case JDBC_SQL_TIME:
case JDBC_TIMESTAMP:
case JDBC_SQL_TIMESTAMP:
if (string == "CURRENT DATE" ||
string == "CURRENT TIME" ||
string == "CURRENT TIMESTAMP" ||
string == "CURRENT ROLE")
{
stringVal = string;
return;
}
case JDBC_CHAR:
case JDBC_VARCHAR:
if (string == "USER")
{
stringVal = string;
return;
}
}
stringVal.Format ("\'%s\'", (const char *) stringVal);
return;
}
void IscColumnsResultSet::adjustResults (IscSqlType &sqlType)
{
// Data sourcedependent data type name
switch (sqlType.type)
{
case JDBC_LONGVARCHAR:
sqlda->updateVarying (6, "BLOB SUB_TYPE TEXT");
break;
case JDBC_LONGVARBINARY:
sqlda->updateVarying (6, "BLOB SUB_TYPE BLR");
break;
}
// decimal digits have no meaning for some columns
// radix - doesn't mean much for some colums either
switch (sqlType.type)
{
case JDBC_NUMERIC:
case JDBC_DECIMAL:
sqlda->updateShort (9, sqlda->getShort(9)*-1); // Scale > 0
break;
case JDBC_REAL:
case JDBC_FLOAT:
case JDBC_DOUBLE:
sqlda->setNull (9);
sqlda->updateShort (10, 2);
break;
case JDBC_CHAR:
case JDBC_WCHAR:
case JDBC_VARCHAR:
case JDBC_WVARCHAR:
case JDBC_LONGVARCHAR:
case JDBC_LONGVARBINARY:
case JDBC_DATE:
case JDBC_SQL_DATE:
sqlda->setNull (9);
sqlda->setNull (10);
break;
case JDBC_TIME:
case JDBC_SQL_TIME:
case JDBC_TIMESTAMP:
case JDBC_SQL_TIMESTAMP:
sqlda->updateShort (9, -ISC_TIME_SECONDS_PRECISION_SCALE);
sqlda->setNull (10);
}
// nullable
short nullable = !sqlda->getShort (11) || sqlda->isNull(11);
sqlda->updateShort (11, nullable);
// default source
if (!getDefSource (26, 13))
getDefSource (20, 13);
switch (sqlType.type)
{
case JDBC_DATE:
case JDBC_SQL_DATE:
sqlda->updateShort (14, 9);
sqlda->updateShort (15, 1);
break;
case JDBC_TIME:
case JDBC_SQL_TIME:
sqlda->updateShort (14, 9);
sqlda->updateShort (15, 2);
break;
case JDBC_TIMESTAMP:
case JDBC_SQL_TIMESTAMP:
sqlda->updateShort (14, 9);
sqlda->updateShort (15, 3);
break;
default:
sqlda->updateShort (14, sqlda->getShort(5));
sqlda->setNull (15);
}
// Is Nullable - I'm seeing everything twice
if ( !nullable )
sqlda->updateVarying (18, "NO");
}
}; // end namespace IscDbcLibrary