1 : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2 : * Copyright (C) 1998-1999 Brian Bruns
3 : * Copyright (C) 2003-2005 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 : #if HAVE_CONFIG_H
22 : #include <config.h>
23 : #endif /* HAVE_CONFIG_H */
24 :
25 : #include <assert.h>
26 :
27 : #if HAVE_STDLIB_H
28 : #include <stdlib.h>
29 : #endif /* HAVE_STDLIB_H */
30 :
31 : #if HAVE_STRING_H
32 : #include <string.h>
33 : #endif /* HAVE_STRING_H */
34 :
35 : #include "tdsodbc.h"
36 : #include "tdsconvert.h"
37 :
38 : #ifdef DMALLOC
39 : #include <dmalloc.h>
40 : #endif
41 :
42 : TDS_RCSID(var, "$Id: convert_tds2sql.c,v 1.46 2005/08/23 17:25:51 freddy77 Exp $");
43 :
44 : TDS_INT
45 : convert_tds2sql(TDSCONTEXT * context, int srctype, TDS_CHAR * src, TDS_UINT srclen, int desttype, TDS_CHAR * dest, SQLULEN destlen,
46 : const struct _drecord *drec_ixd)
47 1281 : {
48 : TDS_INT nDestSybType;
49 1281 : TDS_INT nRetVal = TDS_FAIL;
50 :
51 : CONV_RESULT ores;
52 :
53 : TDSDATEREC dr;
54 : DATE_STRUCT *dsp;
55 : TIME_STRUCT *tsp;
56 : TIMESTAMP_STRUCT *tssp;
57 : SQL_NUMERIC_STRUCT *num;
58 :
59 1281 : int ret = TDS_FAIL;
60 : int i, cplen;
61 :
62 1281 : tdsdump_log(TDS_DBG_FUNC, "convert_tds2sql: src is %d dest = %d\n", srctype, desttype);
63 :
64 1281 : assert(desttype != SQL_C_DEFAULT);
65 :
66 1281 : nDestSybType = odbc_c_to_server_type(desttype);
67 1281 : if (nDestSybType == TDS_FAIL)
68 0 : return TDS_CONVERT_NOAVAIL;
69 :
70 : /* special case for binary type */
71 1281 : if (desttype == SQL_C_BINARY) {
72 48 : tdsdump_log(TDS_DBG_FUNC, "convert_tds2sql: outputting binary data destlen = %lu \n", (unsigned long) destlen);
73 :
74 48 : if (is_numeric_type(srctype)) {
75 4 : desttype = SQL_C_NUMERIC;
76 4 : nDestSybType = SYBNUMERIC;
77 : /* prevent buffer overflow */
78 4 : if (destlen < sizeof(SQL_NUMERIC_STRUCT))
79 0 : return TDS_CONVERT_FAIL;
80 4 : ores.n.precision = ((TDS_NUMERIC *) src)->precision;
81 4 : ores.n.scale = ((TDS_NUMERIC *) src)->scale;
82 : } else {
83 44 : ret = srclen;
84 44 : if (destlen > 0) {
85 44 : cplen = (destlen > srclen) ? srclen : destlen;
86 44 : assert(cplen >= 0);
87 : /* do not NULL terminate binary buffer */
88 44 : memcpy(dest, src, cplen);
89 : } else {
90 : /* if destlen == 0 we return only length */
91 0 : if (destlen != 0)
92 0 : ret = TDS_FAIL;
93 : }
94 44 : return ret;
95 : }
96 1233 : } else if (is_numeric_type(nDestSybType)) {
97 : /* TODO use descriptor information (APD) ?? However APD can contain SQL_C_DEFAULT... */
98 10 : if (drec_ixd)
99 10 : ores.n.precision = drec_ixd->sql_desc_precision;
100 : else
101 0 : ores.n.precision = 38;
102 10 : ores.n.scale = 0;
103 : }
104 :
105 :
106 1237 : nRetVal = tds_convert(context, srctype, src, srclen, nDestSybType, &ores);
107 1237 : if (nRetVal < 0)
108 0 : return nRetVal;
109 :
110 1237 : switch (desttype) {
111 :
112 : case SQL_C_CHAR:
113 730 : tdsdump_log(TDS_DBG_FUNC, "convert_tds2sql: outputting character data destlen = %lu \n", (unsigned long) destlen);
114 :
115 730 : ret = nRetVal;
116 : /* TODO handle not terminated configuration */
117 730 : if (destlen > 0) {
118 726 : cplen = (destlen - 1) > nRetVal ? nRetVal : (destlen - 1);
119 726 : assert(cplen >= 0);
120 : /*
121 : * odbc always terminate but do not overwrite
122 : * destination buffer more than needed
123 : */
124 726 : memcpy(dest, ores.c, cplen);
125 726 : dest[cplen] = 0;
126 : } else {
127 : /* if destlen == 0 we return only length */
128 4 : if (destlen != 0)
129 0 : ret = TDS_FAIL;
130 : }
131 :
132 730 : free(ores.c);
133 730 : break;
134 :
135 : case SQL_C_TYPE_DATE:
136 : case SQL_C_DATE:
137 :
138 : /* we've already converted the returned value to a SYBDATETIME */
139 : /* now decompose date into constituent parts... */
140 :
141 2 : tds_datecrack(SYBDATETIME, &(ores.dt), &dr);
142 :
143 2 : dsp = (DATE_STRUCT *) dest;
144 :
145 2 : dsp->year = dr.year;
146 2 : dsp->month = dr.month + 1;
147 2 : dsp->day = dr.day;
148 :
149 2 : ret = sizeof(DATE_STRUCT);
150 2 : break;
151 :
152 : case SQL_C_TYPE_TIME:
153 : case SQL_C_TIME:
154 :
155 : /* we've already converted the returned value to a SYBDATETIME */
156 : /* now decompose date into constituent parts... */
157 :
158 2 : tds_datecrack(SYBDATETIME, &(ores.dt), &dr);
159 :
160 2 : tsp = (TIME_STRUCT *) dest;
161 :
162 2 : tsp->hour = dr.hour;
163 2 : tsp->minute = dr.minute;
164 2 : tsp->second = dr.second;
165 :
166 2 : ret = sizeof(TIME_STRUCT);
167 2 : break;
168 :
169 : case SQL_C_TYPE_TIMESTAMP:
170 : case SQL_C_TIMESTAMP:
171 :
172 : /* we've already converted the returned value to a SYBDATETIME */
173 : /* now decompose date into constituent parts... */
174 :
175 4 : tds_datecrack(SYBDATETIME, &(ores.dt), &dr);
176 :
177 4 : tssp = (TIMESTAMP_STRUCT *) dest;
178 :
179 4 : tssp->year = dr.year;
180 4 : tssp->month = dr.month + 1;
181 4 : tssp->day = dr.day;
182 4 : tssp->hour = dr.hour;
183 4 : tssp->minute = dr.minute;
184 4 : tssp->second = dr.second;
185 4 : tssp->fraction = dr.millisecond * 1000000u;
186 :
187 4 : ret = sizeof(TIMESTAMP_STRUCT);
188 4 : break;
189 :
190 : #ifdef SQL_C_SBIGINT
191 : case SQL_C_SBIGINT:
192 : case SQL_C_UBIGINT:
193 0 : *((TDS_INT8 *) dest) = ores.bi;
194 0 : ret = sizeof(TDS_INT8);
195 0 : break;
196 : #endif
197 :
198 : case SQL_C_LONG:
199 : case SQL_C_SLONG:
200 : case SQL_C_ULONG:
201 224 : *((TDS_INT *) dest) = ores.i;
202 224 : ret = sizeof(TDS_INT);
203 224 : break;
204 :
205 : case SQL_C_SHORT:
206 : case SQL_C_SSHORT:
207 : case SQL_C_USHORT:
208 234 : *((TDS_SMALLINT *) dest) = ores.si;
209 234 : ret = sizeof(TDS_SMALLINT);
210 234 : break;
211 :
212 : case SQL_C_TINYINT:
213 : case SQL_C_STINYINT:
214 : case SQL_C_UTINYINT:
215 : case SQL_C_BIT:
216 6 : *((TDS_TINYINT *) dest) = ores.ti;
217 6 : ret = sizeof(TDS_TINYINT);
218 6 : break;
219 :
220 : case SQL_C_DOUBLE:
221 8 : *((TDS_FLOAT *) dest) = ores.f;
222 8 : ret = sizeof(TDS_FLOAT);
223 8 : break;
224 :
225 : case SQL_C_FLOAT:
226 8 : *((TDS_REAL *) dest) = ores.r;
227 8 : ret = sizeof(TDS_REAL);
228 8 : break;
229 :
230 : case SQL_C_NUMERIC:
231 : /* ODBC numeric is quite different from TDS one ... */
232 14 : num = (SQL_NUMERIC_STRUCT *) dest;
233 14 : num->precision = ores.n.precision;
234 14 : num->scale = ores.n.scale;
235 14 : num->sign = ores.n.array[0] ^ 1;
236 : /* FIXME can i be greater than SQL_MAX_NUMERIC_LEN ?? */
237 14 : i = tds_numeric_bytes_per_prec[ores.n.precision] - 1;
238 14 : memcpy(num->val, ores.n.array + 1, i);
239 14 : tds_swap_bytes(num->val, i);
240 14 : if (i < SQL_MAX_NUMERIC_LEN)
241 8 : memset(num->val + i, 0, SQL_MAX_NUMERIC_LEN - i);
242 14 : ret = sizeof(SQL_NUMERIC_STRUCT);
243 14 : break;
244 :
245 : #ifdef SQL_C_GUID
246 : case SQL_C_GUID:
247 5 : memcpy(dest, &(ores.u), sizeof(TDS_UNIQUE));
248 5 : ret = sizeof(TDS_UNIQUE);
249 5 : break;
250 : #endif
251 :
252 : case SQL_C_BINARY:
253 : /* type already handled */
254 0 : assert(desttype != SQL_C_BINARY);
255 :
256 : default:
257 : break;
258 :
259 : }
260 :
261 1237 : return ret;
262 : }
|