Line data Source code
1 : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2 : * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Brian Bruns
3 : * Copyright (C) 2017 Frediano Ziglio
4 : *
5 : * This library is free software; you can redistribute it and/or
6 : * modify it under the terms of the GNU Library General Public
7 : * License as published by the Free Software Foundation; either
8 : * version 2 of the License, or (at your option) any later version.
9 : *
10 : * This library is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 : * Library General Public License for more details.
14 : *
15 : * You should have received a copy of the GNU Library General Public
16 : * License along with this library; if not, write to the
17 : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 : * Boston, MA 02111-1307, USA.
19 : */
20 :
21 : #define TDS_DONT_DEFINE_DEFAULT_FUNCTIONS
22 : #include "common.h"
23 : #include <assert.h>
24 : #include <freetds/tds/convert.h>
25 : #include <freetds/tds/checks.h>
26 : #include <freetds/tds/all_types.h>
27 :
28 : static bool
29 4230 : is_convert_pointer_type(int type)
30 : {
31 4230 : switch (type) {
32 : case SYBCHAR: case SYBVARCHAR: case SYBTEXT: case XSYBCHAR: case XSYBVARCHAR:
33 : case SYBBINARY: case SYBVARBINARY: case SYBIMAGE: case XSYBBINARY: case XSYBVARBINARY:
34 : case SYBLONGBINARY:
35 : return true;
36 : }
37 3660 : return false;
38 : }
39 :
40 :
41 : static void
42 2160 : free_convert(int type, CONV_RESULT *cr)
43 : {
44 2160 : if (is_convert_pointer_type(type))
45 330 : free(cr->c);
46 2160 : }
47 :
48 : static void create_type(TDSSOCKET *tds, int desttype, int server_type, tds_any_type_t *func);
49 :
50 : enum { TDSVER_MS = 0x704, TDSVER_SYB = 0x500 };
51 :
52 30 : void tds_all_types(TDSSOCKET *tds, tds_any_type_t *func)
53 : {
54 : int desttype;
55 :
56 30 : tds->conn->tds_version = TDSVER_MS;
57 :
58 : /*
59 : * Test every type
60 : */
61 7710 : for (desttype = 0; desttype < 0x100; desttype++) {
62 : int types_buffer[10];
63 7680 : int *types = types_buffer, *types_end;
64 : int server_type;
65 : int varint, other_varint;
66 :
67 7680 : if (!is_tds_type_valid(desttype))
68 12240 : continue;
69 :
70 1740 : tds->conn->tds_version = TDSVER_MS;
71 :
72 : /* if is only Sybase change version to Sybase */
73 1740 : varint = tds_get_varint_size(tds->conn, desttype);
74 1740 : tds->conn->tds_version ^= TDSVER_MS ^ TDSVER_SYB;
75 1740 : other_varint = tds_get_varint_size(tds->conn, desttype);
76 1740 : tds->conn->tds_version ^= TDSVER_MS ^ TDSVER_SYB;
77 1740 : if (varint == 1 && varint != other_varint)
78 360 : tds->conn->tds_version = TDSVER_SYB;
79 :
80 1740 : server_type = desttype;
81 1740 : switch (desttype) {
82 : /* unsupported */
83 60 : case SYBVOID:
84 : case SYBINTERVAL:
85 60 : continue;
86 : /* nullable, use another type */
87 : /* TODO, try all sizes */
88 30 : case SYBINTN:
89 30 : *types++ = SYBINT1;
90 30 : *types++ = SYBINT2;
91 30 : *types++ = SYBINT4;
92 30 : *types++ = SYBINT8;
93 30 : break;
94 30 : case SYBUINTN:
95 30 : *types++ = SYBUINT1;
96 30 : *types++ = SYBUINT2;
97 30 : *types++ = SYBUINT4;
98 30 : *types++ = SYBUINT8;
99 30 : tds->conn->tds_version = TDSVER_SYB;
100 30 : break;
101 30 : case SYBFLTN:
102 30 : *types++ = SYBREAL;
103 30 : *types++ = SYBFLT8;
104 30 : break;
105 30 : case SYBMONEYN:
106 30 : *types++ = SYBMONEY4;
107 30 : *types++ = SYBMONEY;
108 30 : break;
109 30 : case SYBDATETIMN:
110 30 : *types++ = SYBDATETIME4;
111 30 : *types++ = SYBDATETIME;
112 30 : break;
113 30 : case SYBDATEN:
114 30 : *types++ = SYBDATE;
115 30 : tds->conn->tds_version = TDSVER_SYB;
116 30 : break;
117 30 : case SYBTIMEN:
118 30 : *types++ = SYBTIME;
119 30 : tds->conn->tds_version = TDSVER_SYB;
120 30 : break;
121 30 : case SYB5INT8:
122 30 : *types++ = SYBINT8;
123 30 : break;
124 : /* TODO tds_set_column_type */
125 :
126 300 : case SYBXML: /* ?? */
127 : case SYBNTEXT: /* ?? */
128 : case XSYBNVARCHAR:
129 : case XSYBNCHAR:
130 : case SYBNVARCHAR:
131 : case SYBMSUDT:
132 : case SYBMSXML:
133 : case SYBUNITEXT:
134 : case SYBVARIANT: /* TODO */
135 : case SYBSINT1: /* TODO */
136 : case SYBMSTABLE: /* TODO */
137 300 : continue;
138 : }
139 :
140 1380 : if (types == types_buffer)
141 1140 : *types++ = desttype;
142 :
143 1380 : types_end = types;
144 3030 : for (types = types_buffer; types != types_end; ++types) {
145 1650 : create_type(tds, *types, server_type, func);
146 1650 : if (*types != server_type)
147 510 : create_type(tds, *types, *types, func);
148 : }
149 : }
150 30 : }
151 :
152 2160 : static void create_type(TDSSOCKET *tds, int desttype, int server_type, tds_any_type_t *func)
153 : {
154 2160 : const TDSCONTEXT *ctx = tds_get_ctx(tds);
155 : int result;
156 2160 : TDS_CHAR *src = NULL;
157 : TDS_UINT srclen;
158 :
159 : CONV_RESULT cr;
160 2160 : const int srctype = SYBCHAR;
161 :
162 : TDSRESULTINFO *results;
163 : TDSCOLUMN *curcol;
164 :
165 2160 : cr.n.precision = 8;
166 2160 : cr.n.scale = 2;
167 :
168 2160 : switch (desttype) {
169 : case SYBCHAR:
170 : case SYBVARCHAR:
171 : case SYBTEXT:
172 : case XSYBVARCHAR:
173 : case XSYBCHAR:
174 : src = "test of a character field";
175 : break;
176 180 : case SYBDATETIME:
177 : case SYBDATETIME4:
178 180 : src = "Apr 12, 1985 17:49:41";
179 180 : break;
180 120 : case SYBMSDATE:
181 : case SYBDATE:
182 120 : src = "2012-11-27";
183 120 : break;
184 90 : case SYBTIME:
185 90 : src = "15:27:12";
186 90 : break;
187 60 : case SYBMSTIME:
188 : case SYB5BIGTIME:
189 60 : src = "15:27:12.327862";
190 60 : break;
191 90 : case SYBMSDATETIME2:
192 : case SYBMSDATETIMEOFFSET:
193 : case SYB5BIGDATETIME:
194 90 : src = "2015-09-12 21:48:12.638161";
195 90 : break;
196 60 : case SYBBINARY:
197 : case SYBIMAGE:
198 60 : src = "0xbeef";
199 60 : break;
200 540 : case SYBINT1:
201 : case SYBINT2:
202 : case SYBINT4:
203 : case SYBUINT1:
204 : case SYBUINT2:
205 : case SYBUINT4:
206 540 : src = "255";
207 540 : break;
208 240 : case SYBINT8:
209 : case SYBUINT8:
210 240 : src = "374632567765";
211 240 : break;
212 360 : case SYBFLT8:
213 : case SYBREAL:
214 : case SYBMONEY:
215 : case SYBMONEY4:
216 360 : src = "1237.45";
217 : cr.n.precision = 8;
218 : cr.n.scale = 2;
219 360 : break;
220 60 : case SYBNUMERIC:
221 : case SYBDECIMAL:
222 60 : src = "947919.25";
223 : cr.n.precision = 8;
224 : cr.n.scale = 2;
225 60 : break;
226 30 : case SYBUNIQUE:
227 30 : src = "A8C60F70-5BD4-3E02-B769-7CCCCA585DCC";
228 30 : break;
229 180 : case SYBBIT:
230 : default:
231 180 : src = "1";
232 180 : break;
233 : }
234 : assert(src);
235 2160 : srclen = (TDS_UINT) strlen(src);
236 :
237 : /*
238 : * Now at last do the conversion
239 : */
240 :
241 2160 : result = tds_convert(ctx, srctype, src, srclen, desttype, &cr);
242 :
243 2160 : if (result < 0) {
244 0 : if (result == TDS_CONVERT_NOAVAIL) /* tds_willconvert returned true, but it lied. */
245 0 : fprintf(stderr, "Conversion not yet implemented:\n\t");
246 :
247 0 : fprintf(stderr, "failed (%d) to convert %d (%s, %d bytes) : %d (%s).\n",
248 : result,
249 : srctype, tds_prtype(srctype), srclen,
250 : desttype, tds_prtype(desttype));
251 :
252 0 : if (result == TDS_CONVERT_NOAVAIL)
253 0 : exit(1);
254 : }
255 :
256 2160 : printf("converted %d (%s, %d bytes) -> %d (%s, %d bytes).\n",
257 : srctype, tds_prtype(srctype), srclen,
258 : desttype, tds_prtype(desttype), result);
259 :
260 2160 : results = tds_alloc_param_result(NULL);
261 2160 : assert(results);
262 2160 : curcol = results->columns[0];
263 2160 : assert(curcol);
264 :
265 2160 : tds_set_column_type(tds->conn, curcol, server_type);
266 2160 : curcol->on_server.column_size = curcol->column_size = curcol->column_cur_size = result;
267 2160 : if (is_numeric_type(desttype)) {
268 60 : curcol->column_prec = cr.n.precision;
269 60 : curcol->column_scale = cr.n.scale;
270 : }
271 2160 : switch (desttype) {
272 60 : case SYB5BIGDATETIME:
273 : case SYB5BIGTIME:
274 60 : curcol->column_prec = curcol->column_scale = 6;
275 60 : break;
276 : }
277 2160 : CHECK_COLUMN_EXTRA(curcol);
278 :
279 2160 : tds_alloc_param_data(curcol);
280 2160 : if (is_blob_col(curcol)) {
281 90 : ((TDSBLOB *) curcol->column_data)->textvalue = cr.c;
282 90 : cr.c = NULL;
283 2070 : } else if (is_convert_pointer_type(desttype)) {
284 240 : memcpy(curcol->column_data, cr.c, (size_t) result);
285 : } else {
286 1830 : memcpy(curcol->column_data, &cr.i, (size_t) result);
287 : }
288 :
289 2160 : func(tds, curcol);
290 :
291 : /* try to convert to SQL_VARIANT */
292 2160 : if (is_variant_inner_type(desttype)) {
293 : TDSVARIANT *v;
294 : TDSCOLUMN *basecol;
295 :
296 1470 : tds->conn->tds_version = TDSVER_MS;
297 :
298 1470 : results = tds_alloc_param_result(results);
299 1470 : assert(results);
300 :
301 1470 : basecol = results->columns[0];
302 1470 : curcol = results->columns[1];
303 1470 : tds_set_column_type(tds->conn, curcol, SYBVARIANT);
304 1470 : CHECK_COLUMN_EXTRA(curcol);
305 :
306 1470 : tds_alloc_param_data(curcol);
307 1470 : v = (TDSVARIANT *) curcol->column_data;
308 1470 : v->size = basecol->column_size;
309 1470 : v->type = basecol->column_type;
310 1470 : memcpy(v->collation, basecol->column_collation, sizeof(v->collation));
311 :
312 1470 : assert(basecol->column_cur_size > 0);
313 1470 : v->data = tds_new(TDS_CHAR, (size_t) basecol->column_cur_size);
314 1470 : assert(v->data);
315 1470 : v->data_len = basecol->column_cur_size;
316 1470 : curcol->column_cur_size = v->data_len;
317 1470 : curcol->column_size = curcol->on_server.column_size = 8009;
318 1470 : assert(!is_blob_col(basecol));
319 : assert(v->data_len >= 0);
320 1470 : memcpy(v->data, basecol->column_data, (size_t) v->data_len);
321 1470 : CHECK_COLUMN_EXTRA(curcol);
322 :
323 1470 : func(tds, curcol);
324 : }
325 :
326 2160 : tds_free_results(results);
327 :
328 2160 : if (result >= 0)
329 2160 : free_convert(desttype, &cr);
330 2160 : }
|