Line data Source code
1 : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2 : * Copyright (C) 2014 Frediano Ziglio
3 : *
4 : * This library is free software; you can redistribute it and/or
5 : * modify it under the terms of the GNU Library General Public
6 : * License as published by the Free Software Foundation; either
7 : * version 2 of the License, or (at your option) any later version.
8 : *
9 : * This library is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : * Library General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU Library General Public
15 : * License along with this library; if not, write to the
16 : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 : * Boston, MA 02111-1307, USA.
18 : */
19 :
20 : #include <config.h>
21 :
22 : #include <stdarg.h>
23 : #include <stdio.h>
24 :
25 : #if HAVE_STDLIB_H
26 : #include <stdlib.h>
27 : #endif /* HAVE_STDLIB_H */
28 :
29 : #if HAVE_STRING_H
30 : #include <string.h>
31 : #endif /* HAVE_STRING_H */
32 :
33 : #include <assert.h>
34 : #include <ctype.h>
35 :
36 : #include <freetds/odbc.h>
37 : #include <freetds/iconv.h>
38 : #include <odbcss.h>
39 :
40 : #define SET_INFO(type, prefix, suffix) do { \
41 : drec->sql_desc_literal_prefix = prefix; \
42 : drec->sql_desc_literal_suffix = suffix; \
43 : drec->sql_desc_type_name = type; \
44 : return; \
45 : } while(0)
46 : #define SET_INFO2(type, prefix, suffix, len) do { \
47 : drec->sql_desc_length = (len); \
48 : SET_INFO(type, prefix, suffix); \
49 : } while(0)
50 :
51 : static void
52 224 : data_msdatetime_set_type_info(TDSCOLUMN * col, struct _drecord *drec, SQLINTEGER odbc_ver TDS_UNUSED)
53 : {
54 224 : int decimals = col->column_prec ? col->column_prec + 1: 0;
55 :
56 224 : switch (col->on_server.column_type) {
57 78 : case SYBMSTIME:
58 78 : drec->sql_desc_octet_length = sizeof(SQL_SS_TIME2_STRUCT);
59 78 : drec->sql_desc_concise_type = SQL_SS_TIME2;
60 : /* always hh:mm:ss[.fff] */
61 78 : drec->sql_desc_display_size = 8 + decimals;
62 78 : SET_INFO2("time", "'", "'", 8 + decimals);
63 82 : case SYBMSDATE:
64 82 : drec->sql_desc_octet_length = sizeof(DATE_STRUCT);
65 82 : drec->sql_desc_concise_type = SQL_TYPE_DATE;
66 : /* always yyyy-mm-dd ?? */
67 82 : drec->sql_desc_display_size = 10;
68 82 : SET_INFO2("date", "'", "'", 10);
69 26 : case SYBMSDATETIMEOFFSET:
70 26 : drec->sql_desc_octet_length = sizeof(SQL_SS_TIMESTAMPOFFSET_STRUCT);
71 26 : drec->sql_desc_concise_type = SQL_SS_TIMESTAMPOFFSET;
72 : /* we always format using yyyy-mm-dd hh:mm:ss[.fff] +HH:MM, see convert_tds2sql.c */
73 26 : drec->sql_desc_display_size = 26 + decimals;
74 26 : SET_INFO2("datetimeoffset", "'", "'", 26 + decimals);
75 38 : case SYBMSDATETIME2:
76 38 : drec->sql_desc_octet_length = sizeof(TIMESTAMP_STRUCT);
77 38 : drec->sql_desc_concise_type = SQL_TYPE_TIMESTAMP;
78 38 : drec->sql_desc_datetime_interval_code = SQL_CODE_TIMESTAMP;
79 : /* we always format using yyyy-mm-dd hh:mm:ss[.fff], see convert_tds2sql.c */
80 38 : drec->sql_desc_display_size = 19 + decimals;
81 38 : SET_INFO2("datetime2", "'", "'", 19 + decimals);
82 : default:
83 : break;
84 : }
85 : }
86 :
87 : static void
88 606 : data_variant_set_type_info(TDSCOLUMN * col TDS_UNUSED, struct _drecord *drec, SQLINTEGER odbc_ver TDS_UNUSED)
89 : {
90 606 : drec->sql_desc_concise_type = SQL_SS_VARIANT;
91 606 : drec->sql_desc_display_size = 8000;
92 606 : drec->sql_desc_octet_length = 0;
93 606 : SET_INFO2("sql_variant", "", "", 8000);
94 : }
95 :
96 : static void
97 838 : data_numeric_set_type_info(TDSCOLUMN * col, struct _drecord *drec, SQLINTEGER odbc_ver TDS_UNUSED)
98 : {
99 838 : const char *type_name =
100 838 : col->on_server.column_type == SYBNUMERIC ? "numeric" : "decimal";
101 :
102 838 : drec->sql_desc_concise_type = SQL_NUMERIC;
103 838 : drec->sql_desc_octet_length = col->column_prec + 2;
104 838 : drec->sql_desc_display_size = col->column_prec + 2;
105 838 : drec->sql_desc_num_prec_radix = 10;
106 838 : SET_INFO2(type_name, "", "", col->column_prec);
107 : }
108 :
109 : static void
110 8 : data_clrudt_set_type_info(TDSCOLUMN * col, struct _drecord *drec, SQLINTEGER odbc_ver TDS_UNUSED)
111 : {
112 8 : drec->sql_desc_concise_type = SQL_LONGVARBINARY;
113 : /* TODO ??? */
114 8 : drec->sql_desc_display_size = col->column_size * 2;
115 8 : }
116 :
117 : static void
118 20 : data_sybbigtime_set_type_info(TDSCOLUMN * col, struct _drecord *drec, SQLINTEGER odbc_ver TDS_UNUSED)
119 : {
120 20 : if (col->on_server.column_type == SYB5BIGTIME) {
121 10 : drec->sql_desc_concise_type = SQL_SS_TIME2;
122 : /* we always format using hh:mm:ss[.ffffff], see convert_tds2sql.c */
123 10 : drec->sql_desc_display_size = 15;
124 10 : drec->sql_desc_octet_length = sizeof(SQL_SS_TIME2_STRUCT);
125 10 : drec->sql_desc_precision = 6;
126 10 : drec->sql_desc_scale = 6;
127 10 : drec->sql_desc_datetime_interval_code = SQL_CODE_TIMESTAMP;
128 10 : SET_INFO2("bigtime", "'", "'", 15);
129 : }
130 :
131 10 : assert(col->on_server.column_type == SYB5BIGDATETIME);
132 :
133 10 : drec->sql_desc_concise_type = SQL_TYPE_TIMESTAMP;
134 10 : drec->sql_desc_display_size = 26;
135 10 : drec->sql_desc_octet_length = sizeof(TIMESTAMP_STRUCT);
136 10 : drec->sql_desc_precision = 6;
137 10 : drec->sql_desc_scale = 6;
138 10 : drec->sql_desc_datetime_interval_code = SQL_CODE_TIMESTAMP;
139 10 : SET_INFO2("bigdatetime", "'", "'", 26);
140 : }
141 :
142 : static void
143 0 : data_mstabletype_set_type_info(TDSCOLUMN *col TDS_UNUSED, struct _drecord *drec, SQLINTEGER odbc_ver TDS_UNUSED)
144 : {
145 0 : drec->sql_desc_concise_type = SQL_SS_TABLE;
146 0 : drec->sql_desc_octet_length = 0;
147 0 : }
148 :
149 : static void
150 17997 : data_generic_set_type_info(TDSCOLUMN * col, struct _drecord *drec, SQLINTEGER odbc_ver)
151 : {
152 17997 : TDS_SERVER_TYPE col_type = col->on_server.column_type;
153 17997 : int col_size = col->on_server.column_size;
154 :
155 17997 : switch (tds_get_conversion_type(col_type, col_size)) {
156 40 : case XSYBNCHAR:
157 40 : drec->sql_desc_concise_type = SQL_WCHAR;
158 40 : drec->sql_desc_display_size = col->on_server.column_size / 2;
159 40 : SET_INFO2("nchar", "'", "'", col->on_server.column_size / 2);
160 :
161 178 : case XSYBCHAR:
162 : case SYBCHAR:
163 178 : drec->sql_desc_concise_type = SQL_CHAR;
164 178 : drec->sql_desc_display_size = col->on_server.column_size;
165 178 : SET_INFO("char", "'", "'");
166 :
167 : /* TODO really sure ?? SYBNVARCHAR sybase only ?? */
168 2333 : case SYBNVARCHAR:
169 : case XSYBNVARCHAR:
170 2333 : drec->sql_desc_concise_type = SQL_WVARCHAR;
171 2333 : drec->sql_desc_display_size = col->on_server.column_size / 2;
172 2333 : drec->sql_desc_length = col->on_server.column_size / 2u;
173 2333 : if (col->char_conv) {
174 2331 : unsigned char bytes_per_char = ODBC_CLAMP(col->char_conv->to.charset.max_bytes_per_char, 2, 3);
175 2331 : drec->sql_desc_octet_length = (col->on_server.column_size / 2u) * bytes_per_char;
176 : }
177 2333 : if (is_blob_col(col)) {
178 8 : drec->sql_desc_display_size = SQL_SS_LENGTH_UNLIMITED;
179 8 : drec->sql_desc_octet_length = drec->sql_desc_length =
180 : SQL_SS_LENGTH_UNLIMITED;
181 : }
182 2333 : SET_INFO("nvarchar", "'", "'");
183 :
184 3736 : case XSYBVARCHAR:
185 : case SYBVARCHAR:
186 3736 : drec->sql_desc_concise_type = SQL_VARCHAR;
187 3736 : drec->sql_desc_display_size = col->on_server.column_size;
188 3736 : if (is_blob_col(col)) {
189 36 : drec->sql_desc_display_size = SQL_SS_LENGTH_UNLIMITED;
190 36 : drec->sql_desc_octet_length = drec->sql_desc_length =
191 : SQL_SS_LENGTH_UNLIMITED;
192 : }
193 3736 : SET_INFO("varchar", "'", "'");
194 :
195 574 : case SYBNTEXT:
196 574 : drec->sql_desc_concise_type = SQL_WLONGVARCHAR;
197 574 : drec->sql_desc_display_size = col->on_server.column_size / 2;
198 574 : SET_INFO2("ntext", "'", "'", col->on_server.column_size / 2);
199 :
200 796 : case SYBTEXT:
201 796 : drec->sql_desc_concise_type = SQL_LONGVARCHAR;
202 796 : drec->sql_desc_display_size = col->on_server.column_size;
203 796 : SET_INFO("text", "'", "'");
204 :
205 370 : case SYBBIT:
206 : case SYBBITN:
207 370 : drec->sql_desc_concise_type = SQL_BIT;
208 370 : drec->sql_desc_display_size = 1;
209 370 : drec->sql_desc_unsigned = SQL_TRUE;
210 370 : SET_INFO2("bit", "", "", 1);
211 :
212 : #if (ODBCVER >= 0x0300)
213 214 : case SYB5INT8:
214 : case SYBINT8:
215 : /* TODO return numeric for odbc2 and convert bigint to numeric */
216 214 : drec->sql_desc_concise_type = SQL_BIGINT;
217 214 : drec->sql_desc_display_size = 20;
218 214 : SET_INFO2("bigint", "", "", 19);
219 : #endif
220 :
221 2567 : case SYBINT4:
222 2567 : drec->sql_desc_concise_type = SQL_INTEGER;
223 2567 : drec->sql_desc_display_size = 11; /* -1000000000 */
224 2567 : SET_INFO2("int", "", "", 10);
225 :
226 2623 : case SYBINT2:
227 2623 : drec->sql_desc_concise_type = SQL_SMALLINT;
228 2623 : drec->sql_desc_display_size = 6; /* -10000 */
229 2623 : SET_INFO2("smallint", "", "", 5);
230 :
231 314 : case SYBUINT1:
232 : case SYBINT1:
233 314 : drec->sql_desc_unsigned = SQL_TRUE;
234 314 : case SYBSINT1: /* TODO not another type_name ?? */
235 314 : drec->sql_desc_concise_type = SQL_TINYINT;
236 314 : drec->sql_desc_display_size = 3; /* 255 */
237 314 : SET_INFO2("tinyint", "", "", 3);
238 :
239 : #if (ODBCVER >= 0x0300)
240 36 : case SYBUINT8:
241 36 : drec->sql_desc_unsigned = SQL_TRUE;
242 36 : drec->sql_desc_concise_type = SQL_BIGINT;
243 36 : drec->sql_desc_display_size = 20;
244 : /* TODO return numeric for odbc2 and convert bigint to numeric */
245 36 : SET_INFO2("unsigned bigint", "", "", 20);
246 : #endif
247 :
248 36 : case SYBUINT4:
249 36 : drec->sql_desc_unsigned = SQL_TRUE;
250 36 : drec->sql_desc_concise_type = SQL_INTEGER;
251 36 : drec->sql_desc_display_size = 10;
252 36 : SET_INFO2("unsigned int", "", "", 10);
253 :
254 38 : case SYBUINT2:
255 38 : drec->sql_desc_unsigned = SQL_TRUE;
256 38 : drec->sql_desc_concise_type = SQL_SMALLINT;
257 38 : drec->sql_desc_display_size = 5; /* 65535 */
258 38 : SET_INFO2("unsigned smallint", "", "", 5);
259 :
260 316 : case SYBREAL:
261 316 : drec->sql_desc_concise_type = SQL_REAL;
262 316 : drec->sql_desc_display_size = 14;
263 316 : SET_INFO2("real", "", "", odbc_ver == SQL_OV_ODBC3 ? 24 : 7);
264 :
265 812 : case SYBFLT8:
266 812 : drec->sql_desc_concise_type = SQL_DOUBLE;
267 812 : drec->sql_desc_display_size = 24; /* FIXME -- what should the correct size be? */
268 812 : SET_INFO2("float", "", "", odbc_ver == SQL_OV_ODBC3 ? 53 : 15);
269 :
270 356 : case SYBMONEY:
271 : /* TODO check money format returned by proprietary ODBC, scale == 4 but we use 2 digits */
272 356 : drec->sql_desc_concise_type = SQL_DECIMAL;
273 356 : drec->sql_desc_octet_length = 21;
274 356 : drec->sql_desc_display_size = 21;
275 356 : drec->sql_desc_precision = 19;
276 356 : drec->sql_desc_scale = 4;
277 356 : SET_INFO2("money", "$", "", 19);
278 :
279 100 : case SYBMONEY4:
280 100 : drec->sql_desc_concise_type = SQL_DECIMAL;
281 100 : drec->sql_desc_octet_length = 12;
282 100 : drec->sql_desc_display_size = 12;
283 100 : drec->sql_desc_precision = 10;
284 100 : drec->sql_desc_scale = 4;
285 100 : SET_INFO2("money", "$", "", 10);
286 :
287 1332 : case SYBDATETIME:
288 1332 : drec->sql_desc_concise_type = SQL_TYPE_TIMESTAMP;
289 1332 : drec->sql_desc_display_size = 23;
290 1332 : drec->sql_desc_octet_length = sizeof(TIMESTAMP_STRUCT);
291 1332 : drec->sql_desc_precision = 3;
292 1332 : drec->sql_desc_scale = 3;
293 1332 : drec->sql_desc_datetime_interval_code = SQL_CODE_TIMESTAMP;
294 1332 : SET_INFO2("datetime", "'", "'", 23);
295 :
296 130 : case SYBDATETIME4:
297 130 : drec->sql_desc_concise_type = SQL_TYPE_TIMESTAMP;
298 : /* TODO dependent on precision (decimal second digits) */
299 : /* we always format using yyyy-mm-dd hh:mm:ss[.fff], see convert_tds2sql.c */
300 130 : drec->sql_desc_display_size = 19;
301 130 : drec->sql_desc_octet_length = sizeof(TIMESTAMP_STRUCT);
302 130 : drec->sql_desc_datetime_interval_code = SQL_CODE_TIMESTAMP;
303 130 : SET_INFO2("datetime", "'", "'", 16);
304 :
305 : /* The following two types are just Sybase types but as mainly our ODBC
306 : * driver is much more compatible with Windows use attributes similar
307 : * to MS one. For instance Sybase ODBC returns TIME into a TIME_STRUCT
308 : * however this truncate the precision to 0 as TIME does not have
309 : * fraction of seconds. Also Sybase ODBC have different concepts for
310 : * PRECISION for many types and making these 2 types compatibles with
311 : * Sybase would break this driver compatibility.
312 : */
313 36 : case SYBTIME:
314 36 : drec->sql_desc_concise_type = SQL_SS_TIME2;
315 36 : drec->sql_desc_octet_length = sizeof(SQL_SS_TIME2_STRUCT);
316 : /* we always format using hh:mm:ss[.fff], see convert_tds2sql.c */
317 36 : drec->sql_desc_display_size = 12;
318 36 : drec->sql_desc_precision = 3;
319 36 : drec->sql_desc_scale = 3;
320 36 : SET_INFO2("time", "'", "'", 12);
321 :
322 40 : case SYBDATE:
323 40 : drec->sql_desc_octet_length = sizeof(DATE_STRUCT);
324 40 : drec->sql_desc_concise_type = SQL_TYPE_DATE;
325 : /* we always format using yyyy-mm-dd, see convert_tds2sql.c */
326 40 : drec->sql_desc_display_size = 10;
327 40 : SET_INFO2("date", "'", "'", 10);
328 :
329 58 : case XSYBBINARY:
330 : case SYBBINARY:
331 58 : drec->sql_desc_concise_type = SQL_BINARY;
332 58 : drec->sql_desc_display_size = col->column_size * 2;
333 : /* handle TIMESTAMP using usertype */
334 58 : if (col->column_usertype == 80)
335 8 : SET_INFO("timestamp", "0x", "");
336 50 : SET_INFO("binary", "0x", "");
337 :
338 76 : case SYBLONGBINARY:
339 76 : if (col->column_usertype == USER_UNICHAR_TYPE) {
340 4 : drec->sql_desc_concise_type = SQL_WCHAR;
341 4 : drec->sql_desc_display_size = col->on_server.column_size / 2;
342 4 : SET_INFO2("unichar", "'", "'", col->on_server.column_size / 2);
343 : }
344 72 : if (col->column_usertype == USER_UNIVARCHAR_TYPE) {
345 62 : drec->sql_desc_concise_type = SQL_WVARCHAR;
346 62 : drec->sql_desc_display_size = col->on_server.column_size / 2;
347 62 : SET_INFO2("univarchar", "'", "'", col->on_server.column_size / 2);
348 : }
349 : case SYBIMAGE:
350 374 : drec->sql_desc_concise_type = SQL_LONGVARBINARY;
351 374 : drec->sql_desc_display_size = col->column_size * 2;
352 374 : SET_INFO("image", "0x", "");
353 :
354 436 : case XSYBVARBINARY:
355 : case SYBVARBINARY:
356 436 : drec->sql_desc_concise_type = SQL_VARBINARY;
357 436 : drec->sql_desc_display_size = col->column_size * 2;
358 436 : if (is_blob_col(col)) {
359 40 : drec->sql_desc_display_size = SQL_SS_LENGTH_UNLIMITED;
360 40 : drec->sql_desc_octet_length = drec->sql_desc_length =
361 : SQL_SS_LENGTH_UNLIMITED;
362 : }
363 436 : SET_INFO("varbinary", "0x", "");
364 :
365 : case SYBINTN:
366 : case SYBDATETIMN:
367 : case SYBFLTN:
368 : case SYBMONEYN:
369 : case SYBUINTN:
370 : case SYBTIMEN:
371 : case SYBDATEN:
372 0 : assert(0);
373 :
374 : case SYBVOID:
375 : case SYBINTERVAL:
376 : case SYBUNITEXT:
377 : case SYBXML:
378 : case SYBMSUDT:
379 : break;
380 :
381 : #if (ODBCVER >= 0x0300)
382 74 : case SYBUNIQUE:
383 : #ifdef SQL_GUID
384 74 : drec->sql_desc_concise_type = SQL_GUID;
385 : #else
386 : drec->sql_desc_concise_type = SQL_CHAR;
387 : #endif
388 74 : drec->sql_desc_display_size = 36;
389 : /* FIXME for Sybase ?? */
390 74 : SET_INFO2("uniqueidentifier", "'", "'", 36);
391 : #endif
392 :
393 12 : case SYBMSXML:
394 12 : drec->sql_desc_concise_type = SQL_SS_XML;
395 12 : drec->sql_desc_display_size = SQL_SS_LENGTH_UNLIMITED;
396 12 : drec->sql_desc_octet_length = drec->sql_desc_length =
397 : SQL_SS_LENGTH_UNLIMITED;
398 12 : SET_INFO("xml", "'", "'");
399 : /* types already handled in other types, just to silent warnings */
400 : case SYBNUMERIC:
401 : case SYBDECIMAL:
402 : case SYBVARIANT:
403 : case SYBMSDATE:
404 : case SYBMSTIME:
405 : case SYBMSDATETIME2:
406 : case SYBMSDATETIMEOFFSET:
407 : case SYB5BIGDATETIME:
408 : case SYB5BIGTIME:
409 : case SYBMSTABLE:
410 : break;
411 : }
412 0 : SET_INFO("", "", "");
413 : }
414 :
415 : static void
416 0 : data_invalid_set_type_info(TDSCOLUMN * col TDS_UNUSED, struct _drecord *drec TDS_UNUSED, SQLINTEGER odbc_ver TDS_UNUSED)
417 : {
418 0 : }
419 :
420 : void
421 19693 : odbc_set_sql_type_info(TDSCOLUMN * col, struct _drecord *drec, SQLINTEGER odbc_ver)
422 : {
423 19693 : drec->sql_desc_precision = col->column_prec;
424 19693 : drec->sql_desc_scale = col->column_scale;
425 19693 : drec->sql_desc_unsigned = SQL_FALSE;
426 19693 : drec->sql_desc_octet_length = drec->sql_desc_length = col->on_server.column_size;
427 19693 : drec->sql_desc_num_prec_radix = 0;
428 19693 : drec->sql_desc_datetime_interval_code = 0;
429 :
430 19693 : ((TDS_FUNCS *) col->funcs)->set_type_info(col, drec, odbc_ver);
431 :
432 19693 : drec->sql_desc_type = drec->sql_desc_concise_type;
433 19693 : if (drec->sql_desc_concise_type == SQL_TYPE_TIMESTAMP)
434 1510 : drec->sql_desc_type = SQL_DATETIME;
435 19693 : }
436 :
437 : # define TDS_DEFINE_FUNCS(name) \
438 : const TDS_FUNCS tds_ ## name ## _funcs = { \
439 : TDS_COMMON_FUNCS(name), \
440 : data_ ## name ## _set_type_info, \
441 : }
442 : TDS_DEFINE_FUNCS(invalid);
443 : TDS_DEFINE_FUNCS(generic);
444 : TDS_DEFINE_FUNCS(numeric);
445 : TDS_DEFINE_FUNCS(variant);
446 : TDS_DEFINE_FUNCS(msdatetime);
447 : TDS_DEFINE_FUNCS(clrudt);
448 : TDS_DEFINE_FUNCS(sybbigtime);
449 : TDS_DEFINE_FUNCS(mstabletype);
|