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 124 : data_msdatetime_set_type_info(TDSCOLUMN * col, struct _drecord *drec, SQLINTEGER odbc_ver)
53 : {
54 124 : int decimals = col->column_prec ? col->column_prec + 1: 0;
55 :
56 124 : switch (col->on_server.column_type) {
57 42 : case SYBMSTIME:
58 42 : drec->sql_desc_octet_length = sizeof(SQL_SS_TIME2_STRUCT);
59 42 : drec->sql_desc_concise_type = SQL_SS_TIME2;
60 : /* always hh:mm:ss[.fff] */
61 42 : drec->sql_desc_display_size = 8 + decimals;
62 42 : SET_INFO2("time", "'", "'", 8 + decimals);
63 44 : case SYBMSDATE:
64 44 : drec->sql_desc_octet_length = sizeof(DATE_STRUCT);
65 44 : drec->sql_desc_concise_type = SQL_TYPE_DATE;
66 : /* always yyyy-mm-dd ?? */
67 44 : drec->sql_desc_display_size = 10;
68 44 : SET_INFO2("date", "'", "'", 10);
69 16 : case SYBMSDATETIMEOFFSET:
70 16 : drec->sql_desc_octet_length = sizeof(SQL_SS_TIMESTAMPOFFSET_STRUCT);
71 16 : 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 16 : drec->sql_desc_display_size = 26 + decimals;
74 16 : SET_INFO2("datetimeoffset", "'", "'", 26 + decimals);
75 22 : case SYBMSDATETIME2:
76 22 : drec->sql_desc_octet_length = sizeof(TIMESTAMP_STRUCT);
77 22 : drec->sql_desc_concise_type = SQL_TYPE_TIMESTAMP;
78 22 : 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 22 : drec->sql_desc_display_size = 19 + decimals;
81 22 : SET_INFO2("datetime2", "'", "'", 19 + decimals);
82 : default:
83 : break;
84 : }
85 : }
86 :
87 : static void
88 474 : data_variant_set_type_info(TDSCOLUMN * col, struct _drecord *drec, SQLINTEGER odbc_ver)
89 : {
90 474 : drec->sql_desc_concise_type = SQL_SS_VARIANT;
91 474 : drec->sql_desc_display_size = 8000;
92 474 : drec->sql_desc_octet_length = 0;
93 474 : SET_INFO2("sql_variant", "", "", 8000);
94 : }
95 :
96 : static void
97 664 : data_numeric_set_type_info(TDSCOLUMN * col, struct _drecord *drec, SQLINTEGER odbc_ver)
98 : {
99 664 : const char *type_name =
100 664 : col->on_server.column_type == SYBNUMERIC ? "numeric" : "decimal";
101 :
102 664 : drec->sql_desc_concise_type = SQL_NUMERIC;
103 664 : drec->sql_desc_octet_length = col->column_prec + 2;
104 664 : drec->sql_desc_display_size = col->column_prec + 2;
105 664 : drec->sql_desc_num_prec_radix = 10;
106 664 : SET_INFO2(type_name, "", "", col->column_prec);
107 : }
108 :
109 : static void
110 4 : data_clrudt_set_type_info(TDSCOLUMN * col, struct _drecord *drec, SQLINTEGER odbc_ver)
111 : {
112 4 : drec->sql_desc_concise_type = SQL_LONGVARBINARY;
113 : /* TODO ??? */
114 4 : drec->sql_desc_display_size = col->column_size * 2;
115 4 : }
116 :
117 : static void
118 16 : data_sybbigtime_set_type_info(TDSCOLUMN * col, struct _drecord *drec, SQLINTEGER odbc_ver)
119 : {
120 16 : if (col->on_server.column_type == SYB5BIGTIME) {
121 8 : drec->sql_desc_concise_type = SQL_SS_TIME2;
122 : /* we always format using hh:mm:ss[.ffffff], see convert_tds2sql.c */
123 8 : drec->sql_desc_display_size = 15;
124 8 : drec->sql_desc_octet_length = sizeof(SQL_SS_TIME2_STRUCT);
125 8 : drec->sql_desc_precision = 6;
126 8 : drec->sql_desc_scale = 6;
127 8 : drec->sql_desc_datetime_interval_code = SQL_CODE_TIMESTAMP;
128 8 : SET_INFO2("bigtime", "'", "'", 15);
129 : }
130 :
131 8 : assert(col->on_server.column_type == SYB5BIGDATETIME);
132 :
133 8 : drec->sql_desc_concise_type = SQL_TYPE_TIMESTAMP;
134 8 : drec->sql_desc_display_size = 26;
135 8 : drec->sql_desc_octet_length = sizeof(TIMESTAMP_STRUCT);
136 8 : drec->sql_desc_precision = 6;
137 8 : drec->sql_desc_scale = 6;
138 8 : drec->sql_desc_datetime_interval_code = SQL_CODE_TIMESTAMP;
139 8 : SET_INFO2("bigdatetime", "'", "'", 26);
140 : }
141 :
142 : static void
143 0 : data_mstabletype_set_type_info(TDSCOLUMN *col, struct _drecord *drec, SQLINTEGER odbc_ver)
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 13756 : data_generic_set_type_info(TDSCOLUMN * col, struct _drecord *drec, SQLINTEGER odbc_ver)
151 : {
152 13756 : TDS_SERVER_TYPE col_type = col->on_server.column_type;
153 13756 : int col_size = col->on_server.column_size;
154 :
155 13756 : switch (tds_get_conversion_type(col_type, col_size)) {
156 28 : case XSYBNCHAR:
157 28 : drec->sql_desc_concise_type = SQL_WCHAR;
158 28 : drec->sql_desc_display_size = col->on_server.column_size / 2;
159 28 : SET_INFO2("nchar", "'", "'", col->on_server.column_size / 2);
160 :
161 138 : case XSYBCHAR:
162 : case SYBCHAR:
163 138 : drec->sql_desc_concise_type = SQL_CHAR;
164 138 : drec->sql_desc_display_size = col->on_server.column_size;
165 138 : SET_INFO("char", "'", "'");
166 :
167 : /* TODO really sure ?? SYBNVARCHAR sybase only ?? */
168 1739 : case SYBNVARCHAR:
169 : case XSYBNVARCHAR:
170 1739 : drec->sql_desc_concise_type = SQL_WVARCHAR;
171 1739 : drec->sql_desc_display_size = col->on_server.column_size / 2;
172 1739 : drec->sql_desc_length = col->on_server.column_size / 2u;
173 1739 : if (col->char_conv) {
174 1739 : unsigned char bytes_per_char = ODBC_CLAMP(col->char_conv->to.charset.max_bytes_per_char, 2, 3);
175 1739 : drec->sql_desc_octet_length = (col->on_server.column_size / 2u) * bytes_per_char;
176 : }
177 1739 : if (is_blob_col(col)) {
178 4 : drec->sql_desc_display_size = SQL_SS_LENGTH_UNLIMITED;
179 4 : drec->sql_desc_octet_length = drec->sql_desc_length =
180 : SQL_SS_LENGTH_UNLIMITED;
181 : }
182 1739 : SET_INFO("nvarchar", "'", "'");
183 :
184 2769 : case XSYBVARCHAR:
185 : case SYBVARCHAR:
186 2769 : drec->sql_desc_concise_type = SQL_VARCHAR;
187 2769 : drec->sql_desc_display_size = col->on_server.column_size;
188 2769 : if (is_blob_col(col)) {
189 18 : drec->sql_desc_display_size = SQL_SS_LENGTH_UNLIMITED;
190 18 : drec->sql_desc_octet_length = drec->sql_desc_length =
191 : SQL_SS_LENGTH_UNLIMITED;
192 : }
193 2769 : SET_INFO("varchar", "'", "'");
194 :
195 432 : case SYBNTEXT:
196 432 : drec->sql_desc_concise_type = SQL_WLONGVARCHAR;
197 432 : drec->sql_desc_display_size = col->on_server.column_size / 2;
198 432 : SET_INFO2("ntext", "'", "'", col->on_server.column_size / 2);
199 :
200 632 : case SYBTEXT:
201 632 : drec->sql_desc_concise_type = SQL_LONGVARCHAR;
202 632 : drec->sql_desc_display_size = col->on_server.column_size;
203 632 : SET_INFO("text", "'", "'");
204 :
205 288 : case SYBBIT:
206 : case SYBBITN:
207 288 : drec->sql_desc_concise_type = SQL_BIT;
208 288 : drec->sql_desc_display_size = 1;
209 288 : drec->sql_desc_unsigned = SQL_TRUE;
210 288 : SET_INFO2("bit", "", "", 1);
211 :
212 : #if (ODBCVER >= 0x0300)
213 164 : case SYB5INT8:
214 : case SYBINT8:
215 : /* TODO return numeric for odbc2 and convert bigint to numeric */
216 164 : drec->sql_desc_concise_type = SQL_BIGINT;
217 164 : drec->sql_desc_display_size = 20;
218 164 : SET_INFO2("bigint", "", "", 19);
219 : #endif
220 :
221 1985 : case SYBINT4:
222 1985 : drec->sql_desc_concise_type = SQL_INTEGER;
223 1985 : drec->sql_desc_display_size = 11; /* -1000000000 */
224 1985 : SET_INFO2("int", "", "", 10);
225 :
226 2015 : case SYBINT2:
227 2015 : drec->sql_desc_concise_type = SQL_SMALLINT;
228 2015 : drec->sql_desc_display_size = 6; /* -10000 */
229 2015 : SET_INFO2("smallint", "", "", 5);
230 :
231 244 : case SYBUINT1:
232 : case SYBINT1:
233 244 : drec->sql_desc_unsigned = SQL_TRUE;
234 244 : case SYBSINT1: /* TODO not another type_name ?? */
235 244 : drec->sql_desc_concise_type = SQL_TINYINT;
236 244 : drec->sql_desc_display_size = 3; /* 255 */
237 244 : SET_INFO2("tinyint", "", "", 3);
238 :
239 : #if (ODBCVER >= 0x0300)
240 30 : case SYBUINT8:
241 30 : drec->sql_desc_unsigned = SQL_TRUE;
242 30 : drec->sql_desc_concise_type = SQL_BIGINT;
243 30 : drec->sql_desc_display_size = 20;
244 : /* TODO return numeric for odbc2 and convert bigint to numeric */
245 30 : SET_INFO2("unsigned bigint", "", "", 20);
246 : #endif
247 :
248 30 : case SYBUINT4:
249 30 : drec->sql_desc_unsigned = SQL_TRUE;
250 30 : drec->sql_desc_concise_type = SQL_INTEGER;
251 30 : drec->sql_desc_display_size = 10;
252 30 : SET_INFO2("unsigned int", "", "", 10);
253 :
254 32 : case SYBUINT2:
255 32 : drec->sql_desc_unsigned = SQL_TRUE;
256 32 : drec->sql_desc_concise_type = SQL_SMALLINT;
257 32 : drec->sql_desc_display_size = 5; /* 65535 */
258 32 : SET_INFO2("unsigned smallint", "", "", 5);
259 :
260 248 : case SYBREAL:
261 248 : drec->sql_desc_concise_type = SQL_REAL;
262 248 : drec->sql_desc_display_size = 14;
263 248 : SET_INFO2("real", "", "", odbc_ver == SQL_OV_ODBC3 ? 24 : 7);
264 :
265 634 : case SYBFLT8:
266 634 : drec->sql_desc_concise_type = SQL_DOUBLE;
267 634 : drec->sql_desc_display_size = 24; /* FIXME -- what should the correct size be? */
268 634 : SET_INFO2("float", "", "", odbc_ver == SQL_OV_ODBC3 ? 53 : 15);
269 :
270 272 : case SYBMONEY:
271 : /* TODO check money format returned by propretary ODBC, scale == 4 but we use 2 digits */
272 272 : drec->sql_desc_concise_type = SQL_DECIMAL;
273 272 : drec->sql_desc_octet_length = 21;
274 272 : drec->sql_desc_display_size = 21;
275 272 : drec->sql_desc_precision = 19;
276 272 : drec->sql_desc_scale = 4;
277 272 : SET_INFO2("money", "$", "", 19);
278 :
279 80 : case SYBMONEY4:
280 80 : drec->sql_desc_concise_type = SQL_DECIMAL;
281 80 : drec->sql_desc_octet_length = 12;
282 80 : drec->sql_desc_display_size = 12;
283 80 : drec->sql_desc_precision = 10;
284 80 : drec->sql_desc_scale = 4;
285 80 : SET_INFO2("money", "$", "", 10);
286 :
287 1034 : case SYBDATETIME:
288 1034 : drec->sql_desc_concise_type = SQL_TYPE_TIMESTAMP;
289 1034 : drec->sql_desc_display_size = 23;
290 1034 : drec->sql_desc_octet_length = sizeof(TIMESTAMP_STRUCT);
291 1034 : drec->sql_desc_precision = 3;
292 1034 : drec->sql_desc_scale = 3;
293 1034 : drec->sql_desc_datetime_interval_code = SQL_CODE_TIMESTAMP;
294 1034 : SET_INFO2("datetime", "'", "'", 23);
295 :
296 104 : case SYBDATETIME4:
297 104 : 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 104 : drec->sql_desc_display_size = 19;
301 104 : drec->sql_desc_octet_length = sizeof(TIMESTAMP_STRUCT);
302 104 : drec->sql_desc_datetime_interval_code = SQL_CODE_TIMESTAMP;
303 104 : 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 30 : case SYBTIME:
314 30 : drec->sql_desc_concise_type = SQL_SS_TIME2;
315 30 : drec->sql_desc_octet_length = sizeof(SQL_SS_TIME2_STRUCT);
316 : /* we always format using hh:mm:ss[.fff], see convert_tds2sql.c */
317 30 : drec->sql_desc_display_size = 12;
318 30 : drec->sql_desc_precision = 3;
319 30 : drec->sql_desc_scale = 3;
320 30 : SET_INFO2("time", "'", "'", 12);
321 :
322 34 : case SYBDATE:
323 34 : drec->sql_desc_octet_length = sizeof(DATE_STRUCT);
324 34 : drec->sql_desc_concise_type = SQL_TYPE_DATE;
325 : /* we always format using yyyy-mm-dd, see convert_tds2sql.c */
326 34 : drec->sql_desc_display_size = 10;
327 34 : SET_INFO2("date", "'", "'", 10);
328 :
329 46 : case XSYBBINARY:
330 : case SYBBINARY:
331 46 : drec->sql_desc_concise_type = SQL_BINARY;
332 46 : drec->sql_desc_display_size = col->column_size * 2;
333 : /* handle TIMESTAMP using usertype */
334 46 : if (col->column_usertype == 80)
335 6 : SET_INFO("timestamp", "0x", "");
336 40 : SET_INFO("binary", "0x", "");
337 :
338 74 : case SYBLONGBINARY:
339 74 : 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 70 : 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 302 : drec->sql_desc_concise_type = SQL_LONGVARBINARY;
351 302 : drec->sql_desc_display_size = col->column_size * 2;
352 302 : SET_INFO("image", "0x", "");
353 :
354 322 : case XSYBVARBINARY:
355 : case SYBVARBINARY:
356 322 : drec->sql_desc_concise_type = SQL_VARBINARY;
357 322 : drec->sql_desc_display_size = col->column_size * 2;
358 322 : if (is_blob_col(col)) {
359 20 : drec->sql_desc_display_size = SQL_SS_LENGTH_UNLIMITED;
360 20 : drec->sql_desc_octet_length = drec->sql_desc_length =
361 : SQL_SS_LENGTH_UNLIMITED;
362 : }
363 322 : 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 52 : case SYBUNIQUE:
383 : #ifdef SQL_GUID
384 52 : drec->sql_desc_concise_type = SQL_GUID;
385 : #else
386 : drec->sql_desc_concise_type = SQL_CHAR;
387 : #endif
388 52 : drec->sql_desc_display_size = 36;
389 : /* FIXME for Sybase ?? */
390 52 : SET_INFO2("uniqueidentifier", "'", "'", 36);
391 : #endif
392 :
393 6 : case SYBMSXML:
394 6 : drec->sql_desc_concise_type = SQL_SS_XML;
395 6 : drec->sql_desc_display_size = SQL_SS_LENGTH_UNLIMITED;
396 6 : drec->sql_desc_octet_length = drec->sql_desc_length =
397 : SQL_SS_LENGTH_UNLIMITED;
398 6 : 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, struct _drecord *drec, SQLINTEGER odbc_ver)
417 : {
418 0 : }
419 :
420 : void
421 15038 : odbc_set_sql_type_info(TDSCOLUMN * col, struct _drecord *drec, SQLINTEGER odbc_ver)
422 : {
423 15038 : drec->sql_desc_precision = col->column_prec;
424 15038 : drec->sql_desc_scale = col->column_scale;
425 15038 : drec->sql_desc_unsigned = SQL_FALSE;
426 15038 : drec->sql_desc_octet_length = drec->sql_desc_length = col->on_server.column_size;
427 15038 : drec->sql_desc_num_prec_radix = 0;
428 15038 : drec->sql_desc_datetime_interval_code = 0;
429 :
430 15038 : ((TDS_FUNCS *) col->funcs)->set_type_info(col, drec, odbc_ver);
431 :
432 15038 : drec->sql_desc_type = drec->sql_desc_concise_type;
433 15038 : if (drec->sql_desc_concise_type == SQL_TYPE_TIMESTAMP)
434 1168 : drec->sql_desc_type = SQL_DATETIME;
435 15038 : }
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);
|