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/convert.h>
25 : #include <freetds/checks.h>
26 :
27 : static bool
28 3384 : is_convert_pointer_type(int type)
29 : {
30 3384 : switch (type) {
31 : case SYBCHAR: case SYBVARCHAR: case SYBTEXT: case XSYBCHAR: case XSYBVARCHAR:
32 : case SYBBINARY: case SYBVARBINARY: case SYBIMAGE: case XSYBBINARY: case XSYBVARBINARY:
33 : case SYBLONGBINARY:
34 : return true;
35 : }
36 2928 : return false;
37 : }
38 :
39 :
40 : static void
41 1728 : free_convert(int type, CONV_RESULT *cr)
42 : {
43 1728 : if (is_convert_pointer_type(type))
44 264 : free(cr->c);
45 1728 : }
46 :
47 : static void create_type(TDSSOCKET *tds, int desttype, int server_type, tds_any_type_t *func);
48 :
49 : enum { TDSVER_MS = 0x704, TDSVER_SYB = 0x500 };
50 :
51 24 : void tds_all_types(TDSSOCKET *tds, tds_any_type_t *func)
52 : {
53 : int desttype;
54 :
55 24 : tds->conn->tds_version = TDSVER_MS;
56 :
57 : /*
58 : * Test every type
59 : */
60 6168 : for (desttype = 0; desttype < 0x100; desttype++) {
61 : int types_buffer[10];
62 6144 : int *types = types_buffer, *types_end;
63 : int server_type;
64 : int varint, other_varint;
65 :
66 6144 : if (!is_tds_type_valid(desttype))
67 9792 : continue;
68 :
69 1392 : tds->conn->tds_version = TDSVER_MS;
70 :
71 : /* if is only Sybase change version to Sybase */
72 1392 : varint = tds_get_varint_size(tds->conn, desttype);
73 1392 : tds->conn->tds_version ^= TDSVER_MS ^ TDSVER_SYB;
74 1392 : other_varint = tds_get_varint_size(tds->conn, desttype);
75 1392 : tds->conn->tds_version ^= TDSVER_MS ^ TDSVER_SYB;
76 1392 : if (varint == 1 && varint != other_varint)
77 288 : tds->conn->tds_version = TDSVER_SYB;
78 :
79 1392 : server_type = desttype;
80 1392 : switch (desttype) {
81 : /* unsupported */
82 48 : case SYBVOID:
83 : case SYBINTERVAL:
84 48 : continue;
85 : /* nullable, use another type */
86 : /* TODO, try all sizes */
87 24 : case SYBINTN:
88 24 : *types++ = SYBINT1;
89 24 : *types++ = SYBINT2;
90 24 : *types++ = SYBINT4;
91 24 : *types++ = SYBINT8;
92 24 : break;
93 24 : case SYBUINTN:
94 24 : *types++ = SYBUINT1;
95 24 : *types++ = SYBUINT2;
96 24 : *types++ = SYBUINT4;
97 24 : *types++ = SYBUINT8;
98 24 : tds->conn->tds_version = TDSVER_SYB;
99 24 : break;
100 24 : case SYBFLTN:
101 24 : *types++ = SYBREAL;
102 24 : *types++ = SYBFLT8;
103 24 : break;
104 24 : case SYBMONEYN:
105 24 : *types++ = SYBMONEY4;
106 24 : *types++ = SYBMONEY;
107 24 : break;
108 24 : case SYBDATETIMN:
109 24 : *types++ = SYBDATETIME4;
110 24 : *types++ = SYBDATETIME;
111 24 : break;
112 24 : case SYBDATEN:
113 24 : *types++ = SYBDATE;
114 24 : tds->conn->tds_version = TDSVER_SYB;
115 24 : break;
116 24 : case SYBTIMEN:
117 24 : *types++ = SYBTIME;
118 24 : tds->conn->tds_version = TDSVER_SYB;
119 24 : break;
120 24 : case SYB5INT8:
121 24 : *types++ = SYBINT8;
122 24 : break;
123 : /* TODO tds_set_column_type */
124 :
125 240 : case SYBXML: /* ?? */
126 : case SYBNTEXT: /* ?? */
127 : case XSYBNVARCHAR:
128 : case XSYBNCHAR:
129 : case SYBNVARCHAR:
130 : case SYBMSUDT:
131 : case SYBMSXML:
132 : case SYBUNITEXT:
133 : case SYBVARIANT: /* TODO */
134 : case SYBSINT1: /* TODO */
135 : case SYBMSTABLE: /* TODO */
136 240 : continue;
137 : }
138 :
139 1104 : if (types == types_buffer)
140 912 : *types++ = desttype;
141 :
142 1104 : types_end = types;
143 2424 : for (types = types_buffer; types != types_end; ++types) {
144 1320 : create_type(tds, *types, server_type, func);
145 1320 : if (*types != server_type)
146 408 : create_type(tds, *types, *types, func);
147 : }
148 : }
149 24 : }
150 :
151 1728 : static void create_type(TDSSOCKET *tds, int desttype, int server_type, tds_any_type_t *func)
152 : {
153 1728 : const TDSCONTEXT *ctx = tds_get_ctx(tds);
154 : int result;
155 1728 : TDS_CHAR *src = NULL;
156 : TDS_UINT srclen;
157 :
158 : CONV_RESULT cr;
159 1728 : const int srctype = SYBCHAR;
160 :
161 : TDSRESULTINFO *results;
162 : TDSCOLUMN *curcol;
163 :
164 1728 : cr.n.precision = 8;
165 1728 : cr.n.scale = 2;
166 :
167 1728 : switch (desttype) {
168 : case SYBCHAR:
169 : case SYBVARCHAR:
170 : case SYBTEXT:
171 : case XSYBVARCHAR:
172 : case XSYBCHAR:
173 : src = "test of a character field";
174 : break;
175 144 : case SYBDATETIME:
176 : case SYBDATETIME4:
177 144 : src = "Apr 12, 1985 17:49:41";
178 144 : break;
179 96 : case SYBMSDATE:
180 : case SYBDATE:
181 96 : src = "2012-11-27";
182 96 : break;
183 72 : case SYBTIME:
184 72 : src = "15:27:12";
185 72 : break;
186 48 : case SYBMSTIME:
187 : case SYB5BIGTIME:
188 48 : src = "15:27:12.327862";
189 48 : break;
190 72 : case SYBMSDATETIME2:
191 : case SYBMSDATETIMEOFFSET:
192 : case SYB5BIGDATETIME:
193 72 : src = "2015-09-12 21:48:12.638161";
194 72 : break;
195 48 : case SYBBINARY:
196 : case SYBIMAGE:
197 48 : src = "0xbeef";
198 48 : break;
199 432 : case SYBINT1:
200 : case SYBINT2:
201 : case SYBINT4:
202 : case SYBUINT1:
203 : case SYBUINT2:
204 : case SYBUINT4:
205 432 : src = "255";
206 432 : break;
207 192 : case SYBINT8:
208 : case SYBUINT8:
209 192 : src = "374632567765";
210 192 : break;
211 288 : case SYBFLT8:
212 : case SYBREAL:
213 : case SYBMONEY:
214 : case SYBMONEY4:
215 288 : src = "1237.45";
216 : cr.n.precision = 8;
217 : cr.n.scale = 2;
218 288 : break;
219 48 : case SYBNUMERIC:
220 : case SYBDECIMAL:
221 48 : src = "947919.25";
222 : cr.n.precision = 8;
223 : cr.n.scale = 2;
224 48 : break;
225 24 : case SYBUNIQUE:
226 24 : src = "A8C60F70-5BD4-3E02-B769-7CCCCA585DCC";
227 24 : break;
228 144 : case SYBBIT:
229 : default:
230 144 : src = "1";
231 144 : break;
232 : }
233 : assert(src);
234 1728 : srclen = strlen(src);
235 :
236 : /*
237 : * Now at last do the conversion
238 : */
239 :
240 1728 : result = tds_convert(ctx, srctype, src, srclen, desttype, &cr);
241 :
242 1728 : if (result < 0) {
243 0 : if (result == TDS_CONVERT_NOAVAIL) /* tds_willconvert returned true, but it lied. */
244 0 : fprintf(stderr, "Conversion not yet implemented:\n\t");
245 :
246 0 : fprintf(stderr, "failed (%d) to convert %d (%s, %d bytes) : %d (%s).\n",
247 : result,
248 : srctype, tds_prtype(srctype), srclen,
249 : desttype, tds_prtype(desttype));
250 :
251 0 : if (result == TDS_CONVERT_NOAVAIL)
252 0 : exit(1);
253 : }
254 :
255 1728 : printf("converted %d (%s, %d bytes) -> %d (%s, %d bytes).\n",
256 : srctype, tds_prtype(srctype), srclen,
257 : desttype, tds_prtype(desttype), result);
258 :
259 1728 : results = tds_alloc_param_result(NULL);
260 1728 : assert(results);
261 1728 : curcol = results->columns[0];
262 1728 : assert(curcol);
263 :
264 1728 : tds_set_column_type(tds->conn, curcol, server_type);
265 1728 : curcol->on_server.column_size = curcol->column_size = curcol->column_cur_size = result;
266 1728 : if (is_numeric_type(desttype)) {
267 48 : curcol->column_prec = cr.n.precision;
268 48 : curcol->column_scale = cr.n.scale;
269 : }
270 1728 : switch (desttype) {
271 48 : case SYB5BIGDATETIME:
272 : case SYB5BIGTIME:
273 48 : curcol->column_prec = curcol->column_scale = 6;
274 48 : break;
275 : }
276 1728 : CHECK_COLUMN_EXTRA(curcol);
277 :
278 1728 : tds_alloc_param_data(curcol);
279 1728 : if (is_blob_col(curcol)) {
280 72 : ((TDSBLOB *) curcol->column_data)->textvalue = cr.c;
281 72 : cr.c = NULL;
282 1656 : } else if (is_convert_pointer_type(desttype)) {
283 192 : memcpy(curcol->column_data, cr.c, result);
284 : } else {
285 1464 : memcpy(curcol->column_data, &cr.i, result);
286 : }
287 :
288 1728 : func(tds, curcol);
289 :
290 : /* try to convert to SQL_VARIANT */
291 1728 : if (is_variant_inner_type(desttype)) {
292 : TDSVARIANT *v;
293 : TDSCOLUMN *basecol;
294 :
295 1176 : tds->conn->tds_version = TDSVER_MS;
296 :
297 1176 : results = tds_alloc_param_result(results);
298 1176 : assert(results);
299 :
300 1176 : basecol = results->columns[0];
301 1176 : curcol = results->columns[1];
302 1176 : tds_set_column_type(tds->conn, curcol, SYBVARIANT);
303 1176 : CHECK_COLUMN_EXTRA(curcol);
304 :
305 1176 : tds_alloc_param_data(curcol);
306 1176 : v = (TDSVARIANT *) curcol->column_data;
307 1176 : v->size = basecol->column_size;
308 1176 : v->type = basecol->column_type;
309 1176 : memcpy(v->collation, basecol->column_collation, sizeof(v->collation));
310 :
311 1176 : assert(basecol->column_cur_size > 0);
312 1176 : v->data = tds_new(TDS_CHAR, basecol->column_cur_size);
313 1176 : assert(v->data);
314 1176 : v->data_len = basecol->column_cur_size;
315 1176 : curcol->column_cur_size = v->data_len;
316 1176 : curcol->column_size = curcol->on_server.column_size = 8009;
317 1176 : assert(!is_blob_col(basecol));
318 1176 : memcpy(v->data, basecol->column_data, v->data_len);
319 1176 : CHECK_COLUMN_EXTRA(curcol);
320 :
321 1176 : func(tds, curcol);
322 : }
323 :
324 1728 : tds_free_results(results);
325 :
326 1728 : if (result >= 0)
327 1728 : free_convert(desttype, &cr);
328 1728 : }
|