Line data Source code
1 : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2 : * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Brian Bruns
3 : * Copyright (C) 2010, 2011 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 : #include <config.h>
22 :
23 : #include <stdarg.h>
24 : #include <stdio.h>
25 : #include <assert.h>
26 :
27 : #if HAVE_STRING_H
28 : #include <string.h>
29 : #endif /* HAVE_STRING_H */
30 :
31 : #if HAVE_STDLIB_H
32 : #include <stdlib.h>
33 : #endif /* HAVE_STDLIB_H */
34 :
35 : #if HAVE_UNISTD_H
36 : #include <unistd.h>
37 : #endif /* HAVE_UNISTD_H */
38 :
39 : #ifdef _WIN32
40 : #include <io.h>
41 : #endif
42 :
43 : #include <freetds/tds.h>
44 : #include <freetds/iconv.h>
45 : #include <freetds/convert.h>
46 : #include <freetds/odbc.h>
47 : #include <freetds/utils/string.h>
48 : #define TDSODBC_BCP
49 : #include <odbcss.h>
50 :
51 : static TDSRET
52 : _bcp_get_col_data(TDSBCPINFO *bcpinfo, TDSCOLUMN *bindcol, int offset);
53 : static SQLLEN
54 : _bcp_get_term_var(const TDS_CHAR * pdata, const TDS_CHAR * term, int term_len);
55 :
56 : #define ODBCBCP_ERROR_RETURN(code) \
57 : do {odbc_errs_add(&dbc->errs, code, NULL); return;} while(0)
58 :
59 : #define ODBCBCP_ERROR_DBINT(code) \
60 : do {odbc_errs_add(&dbc->errs, code, NULL); return -1;} while(0)
61 :
62 : /**
63 : * \ingroup odbc_bcp
64 : * \brief Prepare for bulk copy operation on a table
65 : *
66 : * \param dbc ODBC database connection object
67 : * \param tblname the name of the table receiving or providing the data.
68 : * \param hfile the data file opposite the table, if any. NB: The current
69 : * implementation does not support file I/O so this must be NULL
70 : * \param errfile the "error file" captures messages and, if errors are
71 : * encountered. NB: The current implementation does not support
72 : * file I/O so this must be NULL
73 : * \param direction one of
74 : * - \b DB_IN writing to the table
75 : * - \b DB_OUT writing to the host file (Not currently supported)
76 : * .
77 : * \remarks bcp_init() sets the host file data format and acquires the table metadata.
78 : * It is called before the other bulk copy functions.
79 : *
80 : * The ODBC BCP functionality should be accessed via the inline functions in
81 : * odbcss.h.
82 : *
83 : * After calling this function, call bcp_bind() to associate your data with
84 : * the appropriate table column.
85 : *
86 : * \sa SQL_COPT_SS_BCP, odbc_bcp_bind(), odbc_bcp_done(), odbc_bcp_exec()
87 : */
88 : void
89 18 : odbc_bcp_init(TDS_DBC *dbc, const ODBC_CHAR *tblname, const ODBC_CHAR *hfile,
90 : const ODBC_CHAR *errfile, int direction _WIDE)
91 : {
92 18 : if (TDS_UNLIKELY(tds_write_dump)) {
93 : #ifdef ENABLE_ODBC_WIDE
94 0 : if (wide) {
95 0 : SQLWSTR_BUFS(3);
96 0 : tdsdump_log(TDS_DBG_FUNC, "bcp_initW(%p, %ls, %ls, %ls, %d)\n",
97 0 : dbc, SQLWSTR(tblname->wide), SQLWSTR(hfile->wide), SQLWSTR(errfile->wide), direction);
98 0 : SQLWSTR_FREE();
99 : } else {
100 : #else
101 : {
102 : #endif
103 0 : tdsdump_log(TDS_DBG_FUNC, "bcp_init(%p, %s, %s, %s, %d)\n",
104 : dbc, (const char*) tblname, (const char*) hfile, (const char*) errfile, direction);
105 : }
106 : }
107 18 : if (!tblname)
108 0 : ODBCBCP_ERROR_RETURN("HY009");
109 :
110 : /* Free previously allocated storage in dbproc & initialise flags, etc. */
111 :
112 18 : odbc_bcp_free_storage(dbc);
113 :
114 : /*
115 : * Validate other parameters
116 : */
117 18 : if (dbc->tds_socket->conn->tds_version < 0x500)
118 0 : ODBCBCP_ERROR_RETURN("HYC00");
119 :
120 18 : if (direction != BCP_DIRECTION_IN || hfile || errfile)
121 0 : ODBCBCP_ERROR_RETURN("HYC00");
122 :
123 : /* Allocate storage */
124 :
125 18 : dbc->bcpinfo = tds_alloc_bcpinfo();
126 18 : if (dbc->bcpinfo == NULL)
127 0 : ODBCBCP_ERROR_RETURN("HY001");
128 :
129 18 : if (!odbc_dstr_copy(dbc, &dbc->bcpinfo->tablename, SQL_NTS, tblname)) {
130 0 : odbc_bcp_free_storage(dbc);
131 0 : ODBCBCP_ERROR_RETURN("HY001");
132 : }
133 :
134 36 : if (tds_dstr_len(&dbc->bcpinfo->tablename) > 92 && !IS_TDS7_PLUS(dbc->tds_socket->conn)) { /* 30.30.30 */
135 0 : odbc_bcp_free_storage(dbc);
136 0 : ODBCBCP_ERROR_RETURN("HYC00");
137 : }
138 :
139 18 : dbc->bcpinfo->direction = direction;
140 :
141 18 : dbc->bcpinfo->xfer_init = 0;
142 18 : dbc->bcpinfo->bind_count = 0;
143 :
144 18 : if (TDS_FAILED(tds_bcp_init(dbc->tds_socket, dbc->bcpinfo))) {
145 : /* TODO return proper error */
146 : /* Attempt to use Bulk Copy with a non-existent Server table (might be why ...) */
147 0 : ODBCBCP_ERROR_RETURN("HY000");
148 : }
149 : }
150 :
151 :
152 : /**
153 : * \ingroup odbc_bcp
154 : * \brief Set BCP options for data transfer
155 : *
156 : * \param dbc ODBC database connection object
157 : * \param field symbolic constant indicating the option to be set, one of:
158 : * - \b BCPKEEPIDENTITY Enable identity insert, as if by executing
159 : * 'SET IDENTITY_INSERT \a table ON'. The default is off
160 : * - \b BCPHINTS Arbitrary extra text to pass to the server. See the
161 : * documentation for the bcp command-line tool which came with your
162 : * database server for the correct syntax.
163 : * \param value The value for \a field.
164 : *
165 : * \remarks These options control the behavior of bcp_sendrow().
166 : *
167 : * \sa odbc_bcp_batch(), odbc_bcp_init(), odbc_bcp_done()
168 : */
169 : void
170 2 : odbc_bcp_control(TDS_DBC *dbc, int field, void *value)
171 : {
172 : #ifdef ENABLE_ODBC_WIDE
173 2 : int wide = 0;
174 : #endif
175 :
176 2 : tdsdump_log(TDS_DBG_FUNC, "bcp_control(%p, %d, %p)\n", dbc, field, value);
177 2 : if (dbc->bcpinfo == NULL)
178 0 : ODBCBCP_ERROR_RETURN("HY010");
179 :
180 :
181 2 : switch (field) {
182 0 : case BCPKEEPIDENTITY:
183 0 : dbc->bcpinfo->identity_insert_on = (value != NULL);
184 0 : break;
185 2 : case BCPHINTSA:
186 2 : if (!value)
187 0 : ODBCBCP_ERROR_RETURN("HY009");
188 2 : if (!odbc_dstr_copy(dbc, &dbc->bcpinfo->hint, SQL_NTS, (ODBC_CHAR *) value))
189 0 : ODBCBCP_ERROR_RETURN("HY001");
190 : break;
191 : #ifdef ENABLE_ODBC_WIDE
192 0 : case BCPHINTSW:
193 0 : if (!value)
194 0 : ODBCBCP_ERROR_RETURN("HY009");
195 0 : wide = 1;
196 0 : if (!odbc_dstr_copy(dbc, &dbc->bcpinfo->hint, SQL_NTS, (ODBC_CHAR *) value))
197 0 : ODBCBCP_ERROR_RETURN("HY001");
198 : break;
199 : #endif
200 0 : default:
201 0 : ODBCBCP_ERROR_RETURN("HY009");
202 : }
203 : }
204 :
205 : /**
206 : * \ingroup odbc_bcp
207 : * \brief Override bcp_bind() by pointing to a different host variable.
208 : *
209 : * \param dbc ODBC database connection object
210 : * \param colptr The pointer, the address of your variable.
211 : * \param table_column The 1-based column ordinal in the table.
212 : * \remarks Use between calls to bcp_sendrow(). After calling bcp_colptr(),
213 : * subsequent calls to bcp_sendrow() will bind to the new address.
214 : * \sa odbc_bcp_bind(), odbc_bcp_sendrow()
215 : */
216 : void
217 0 : odbc_bcp_colptr(TDS_DBC *dbc, const void * colptr, int table_column)
218 : {
219 : TDSCOLUMN *curcol;
220 :
221 0 : tdsdump_log(TDS_DBG_FUNC, "bcp_colptr(%p, %p, %d)\n", dbc, colptr, table_column);
222 0 : if (dbc->bcpinfo == NULL || dbc->bcpinfo->bindinfo == NULL)
223 0 : ODBCBCP_ERROR_RETURN("HY010");
224 : /* colptr can be NULL */
225 :
226 0 : if (dbc->bcpinfo->direction != BCP_DIRECTION_IN)
227 0 : ODBCBCP_ERROR_RETURN("HY010");
228 0 : if (table_column <= 0 || table_column > dbc->bcpinfo->bindinfo->num_cols)
229 0 : ODBCBCP_ERROR_RETURN("HY009");
230 :
231 0 : curcol = dbc->bcpinfo->bindinfo->columns[table_column - 1];
232 0 : curcol->column_varaddr = (TDS_CHAR *)colptr;
233 : }
234 :
235 :
236 : /**
237 : * \ingroup odbc_bcp
238 : * \brief Write data in host variables to the table.
239 : *
240 : * \param dbc ODBC database connection object
241 : *
242 : * \remarks Call bcp_bind() first to describe the variables to be used.
243 : * Use bcp_batch() to commit sets of rows.
244 : * After sending the last row call bcp_done().
245 : * \sa odbc_bcp_batch(), odbc_bcp_bind(), odbc_bcp_colptr(), odbc_bcp_done(),
246 : * odbc_bcp_init()
247 : */
248 : void
249 162 : odbc_bcp_sendrow(TDS_DBC *dbc)
250 : {
251 : TDSSOCKET *tds;
252 :
253 162 : tdsdump_log(TDS_DBG_FUNC, "bcp_sendrow(%p)\n", dbc);
254 162 : if (dbc->bcpinfo == NULL)
255 0 : ODBCBCP_ERROR_RETURN("HY010");
256 :
257 162 : tds = dbc->tds_socket;
258 :
259 162 : if (dbc->bcpinfo->direction != BCP_DIRECTION_IN)
260 0 : ODBCBCP_ERROR_RETURN("HY010");
261 :
262 : /*
263 : * The first time sendrow is called after bcp_init,
264 : * there is a certain amount of initialisation to be done.
265 : */
266 162 : if (dbc->bcpinfo->xfer_init == 0) {
267 :
268 : /* The start_copy function retrieves details of the table's columns */
269 18 : if (TDS_FAILED(tds_bcp_start_copy_in(tds, dbc->bcpinfo)))
270 0 : ODBCBCP_ERROR_RETURN("HY000");
271 :
272 18 : dbc->bcpinfo->xfer_init = 1;
273 : }
274 :
275 162 : dbc->bcpinfo->parent = dbc;
276 162 : if (TDS_FAILED(tds_bcp_send_record(dbc->tds_socket, dbc->bcpinfo, _bcp_get_col_data, NULL, 0)))
277 0 : ODBCBCP_ERROR_RETURN("HY000");
278 : }
279 :
280 :
281 : /**
282 : * \ingroup odbc_bcp
283 : * \brief Commit a set of rows to the table.
284 : *
285 : * \param dbc ODBC database connection object
286 : * \remarks If not called, bcp_done() will cause the rows to be saved.
287 : * \return Count of rows saved, or -1 on error.
288 : * \sa odbc_bcp_bind(), odbc_bcp_done(), odbc_bcp_sendrow()
289 : */
290 : int
291 18 : odbc_bcp_batch(TDS_DBC *dbc)
292 : {
293 18 : int rows_copied = 0;
294 :
295 18 : tdsdump_log(TDS_DBG_FUNC, "bcp_batch(%p)\n", dbc);
296 18 : if (dbc->bcpinfo == NULL)
297 0 : ODBCBCP_ERROR_DBINT("HY010");
298 :
299 18 : if (TDS_FAILED(tds_bcp_done(dbc->tds_socket, &rows_copied)))
300 0 : ODBCBCP_ERROR_DBINT("HY000");
301 :
302 18 : tds_bcp_start(dbc->tds_socket, dbc->bcpinfo);
303 :
304 18 : return rows_copied;
305 : }
306 :
307 : /**
308 : * \ingroup odbc_bcp
309 : * \brief Conclude the transfer of data from program variables.
310 : *
311 : * \param dbc ODBC database connection object
312 : * \remarks Do not overlook this function. According to Sybase, failure to call bcp_done()
313 : * "will result in unpredictable errors".
314 : * \return As with bcp_batch(), the count of rows saved, or -1 on error.
315 : * \sa bcp_batch(), bcp_bind(), bcp_moretext(), bcp_sendrow()
316 : */
317 : int
318 18 : odbc_bcp_done(TDS_DBC *dbc)
319 : {
320 : int rows_copied;
321 :
322 18 : tdsdump_log(TDS_DBG_FUNC, "bcp_done(%p)\n", dbc);
323 :
324 18 : if (!(dbc->bcpinfo))
325 0 : ODBCBCP_ERROR_DBINT("HY010");
326 :
327 18 : if (TDS_FAILED(tds_bcp_done(dbc->tds_socket, &rows_copied)))
328 0 : ODBCBCP_ERROR_DBINT("HY000");
329 :
330 18 : odbc_bcp_free_storage(dbc);
331 :
332 18 : return rows_copied;
333 : }
334 :
335 : /**
336 : * \ingroup odbc_bcp
337 : * \brief Bind a program host variable to a database column
338 : *
339 : * \param dbc ODBC database connection object
340 : * \param varaddr address of host variable
341 : * \param prefixlen length of any prefix found at the beginning of \a varaddr, in bytes.
342 : * Use zero for fixed-length datatypes.
343 : * \param varlen bytes of data in \a varaddr. Zero for NULL, -1 for fixed-length datatypes.
344 : * \param terminator byte sequence that marks the end of the data in \a varaddr
345 : * \param termlen length of \a terminator
346 : * \param vartype datatype of the host variable
347 : * \param table_column Nth column, starting at 1, in the table.
348 : *
349 : * \remarks The order of operation is:
350 : * - bcp_init() with \a hfile == NULL and \a direction == DB_IN.
351 : * - bcp_bind(), once per column you want to write to
352 : * - bcp_batch(), optionally, to commit a set of rows
353 : * - bcp_done()
354 : *
355 : * \sa odbc_bcp_batch(), odbc_bcp_done(), odbc_bcp_sendrow()
356 : */
357 : void
358 476 : odbc_bcp_bind(TDS_DBC *dbc, const void * varaddr, int prefixlen, int varlen,
359 : const void * terminator, int termlen, int vartype, int table_column)
360 : {
361 : TDSCOLUMN *colinfo;
362 :
363 476 : tdsdump_log(TDS_DBG_FUNC, "bcp_bind(%p, %p, %d, %d -- %p, %d, %d, %d)\n",
364 : dbc, varaddr, prefixlen, varlen,
365 : terminator, termlen, vartype, table_column);
366 476 : if (!dbc->bcpinfo)
367 0 : ODBCBCP_ERROR_RETURN("HY010");
368 :
369 476 : if (dbc->bcpinfo->direction != BCP_DIRECTION_IN)
370 0 : ODBCBCP_ERROR_RETURN("HY010");
371 :
372 476 : if (varlen < -1 && varlen != SQL_VARLEN_DATA)
373 0 : ODBCBCP_ERROR_RETURN("HY009");
374 :
375 476 : if (prefixlen != 0 && prefixlen != 1 && prefixlen != 2 && prefixlen != 4 && prefixlen != 8)
376 0 : ODBCBCP_ERROR_RETURN("HY009");
377 :
378 952 : if (vartype != 0 && !is_tds_type_valid(vartype))
379 0 : ODBCBCP_ERROR_RETURN("HY004");
380 :
381 476 : if (prefixlen == 0 && varlen == SQL_VARLEN_DATA && termlen == -1 && !is_fixed_type(vartype)) {
382 0 : tdsdump_log(TDS_DBG_FUNC, "bcp_bind(): non-fixed type %d requires prefix or terminator\n", vartype);
383 0 : ODBCBCP_ERROR_RETURN("HY009");
384 : }
385 :
386 476 : if (table_column <= 0 || table_column > dbc->bcpinfo->bindinfo->num_cols)
387 0 : ODBCBCP_ERROR_RETURN("HY009");
388 :
389 476 : if (varaddr == NULL && (prefixlen != 0 || termlen != 0))
390 0 : ODBCBCP_ERROR_RETURN("HY009");
391 :
392 476 : colinfo = dbc->bcpinfo->bindinfo->columns[table_column - 1];
393 :
394 : /* If varaddr is NULL and varlen greater than 0, the table column type must be SYBTEXT or SYBIMAGE
395 : and the program variable type must be SYBTEXT, SYBCHAR, SYBIMAGE or SYBBINARY */
396 476 : if (varaddr == NULL && varlen >= 0) {
397 0 : int fOK = (colinfo->column_type == SYBTEXT || colinfo->column_type == SYBIMAGE) &&
398 0 : (vartype == SYBTEXT || vartype == SYBCHAR || vartype == SYBIMAGE || vartype == SYBBINARY );
399 : if( !fOK ) {
400 0 : tdsdump_log(TDS_DBG_FUNC, "bcp_bind: SYBEBCBNTYP: column=%d and vartype=%d (should fail?)\n",
401 : colinfo->column_type, vartype);
402 0 : ODBCBCP_ERROR_RETURN("HY009");
403 : }
404 : }
405 :
406 476 : colinfo->column_varaddr = (char *)varaddr;
407 476 : colinfo->column_bindtype = vartype;
408 476 : colinfo->column_bindlen = varlen;
409 476 : colinfo->bcp_prefix_len = prefixlen;
410 :
411 476 : TDS_ZERO_FREE(colinfo->bcp_terminator);
412 476 : colinfo->bcp_term_len = 0;
413 476 : if (termlen > 0) {
414 0 : if ((colinfo->bcp_terminator = tds_new(TDS_CHAR, termlen)) == NULL)
415 0 : ODBCBCP_ERROR_RETURN("HY001");
416 0 : memcpy(colinfo->bcp_terminator, terminator, termlen);
417 0 : colinfo->bcp_term_len = termlen;
418 : }
419 : }
420 :
421 : static SQLLEN
422 484 : _bcp_iconv_helper(const TDS_DBC *dbc, const TDSCOLUMN *bindcol, const TDS_CHAR * src, size_t srclen, char * dest, size_t destlen)
423 : {
424 484 : if (bindcol->char_conv) {
425 484 : char *orig_dest = dest;
426 :
427 484 : if (tds_iconv(dbc->tds_socket, bindcol->char_conv, to_server, &src, &srclen, &dest, &destlen) == (size_t)-1)
428 : return -1;
429 484 : return dest - orig_dest;
430 : }
431 :
432 0 : if (destlen > srclen)
433 0 : destlen = srclen;
434 0 : memcpy(dest, src, destlen);
435 0 : return destlen;
436 : }
437 :
438 : static SQLLEN
439 2410 : _tdsodbc_dbconvert(TDS_DBC *dbc, int srctype, const TDS_CHAR * src, SQLLEN src_len,
440 : int desttype, unsigned char * dest, TDSCOLUMN *bindcol)
441 : {
442 : CONV_RESULT dres;
443 : SQLLEN ret;
444 : SQLLEN len;
445 2410 : SQLLEN destlen = bindcol->column_size;
446 : TDS_DATETIMEALL dta;
447 : TDS_NUMERIC num;
448 : SQL_NUMERIC_STRUCT * sql_num;
449 2410 : bool always_convert = false;
450 :
451 2410 : assert(src_len >= 0);
452 2410 : assert(src != NULL);
453 2410 : assert(dest != NULL);
454 2410 : assert(destlen > 0);
455 :
456 2410 : tdsdump_log(TDS_DBG_FUNC, "tdsodbc_dbconvert(%p, %d, %p, %d, %d, %p, %d)\n",
457 : dbc, srctype, src, (int)src_len, desttype, dest, (int)destlen);
458 :
459 2410 : switch (srctype) {
460 2 : case SYBMSDATETIME2:
461 2 : convert_datetime2server(SQL_C_TYPE_TIMESTAMP, src, &dta);
462 2 : dta.time_prec = (destlen - 40) / 2;
463 2 : src = (char *) &dta;
464 2 : break;
465 4 : case SYBDECIMAL:
466 : case SYBNUMERIC:
467 4 : sql_num = (SQL_NUMERIC_STRUCT *) src;
468 4 : num.precision = sql_num->precision;
469 4 : num.scale = sql_num->scale;
470 4 : num.array[0] = sql_num->sign ^ 1;
471 : /* test precision so client do not crash our library */
472 4 : if (num.precision <= 0 || num.precision > 38 || num.scale > num.precision)
473 : /* TODO add proper error */
474 : return -1;
475 4 : len = tds_numeric_bytes_per_prec[num.precision];
476 4 : memcpy(num.array + 1, sql_num->val, len - 1);
477 4 : tds_swap_bytes(num.array + 1, len - 1);
478 4 : if (len < sizeof(num.array))
479 4 : memset(num.array + len, 0, sizeof(num.array) - len);
480 4 : src = (char *) #
481 4 : always_convert = num.scale != bindcol->column_scale;
482 4 : break;
483 : /* TODO intervals */
484 : }
485 :
486 : /* oft times we are asked to convert a data type to itself */
487 2410 : if ((srctype == desttype || is_similar_type(srctype, desttype)) && !always_convert) {
488 646 : if (is_char_type(desttype)) {
489 482 : ret = _bcp_iconv_helper(dbc, bindcol, src, src_len, (char *)dest, destlen);
490 : }
491 : else {
492 164 : ret = destlen < src_len ? destlen : src_len;
493 164 : memcpy(dest, src, ret);
494 : }
495 : return ret;
496 : }
497 :
498 1764 : tdsdump_log(TDS_DBG_INFO1, "dbconvert() calling tds_convert\n");
499 :
500 1764 : if (is_numeric_type(desttype)) {
501 322 : dres.n.precision = bindcol->column_prec;
502 322 : dres.n.scale = bindcol->column_scale;
503 : }
504 1764 : len = tds_convert(dbc->env->tds_ctx, srctype, src, src_len, desttype, &dres);
505 1764 : tdsdump_log(TDS_DBG_INFO1, "dbconvert() called tds_convert returned %d\n", (int)len);
506 :
507 1764 : if (len < 0) {
508 0 : odbc_convert_err_set(&dbc->errs, len);
509 0 : return -1;
510 : }
511 :
512 1764 : switch (desttype) {
513 0 : case SYBBINARY:
514 : case SYBVARBINARY:
515 : case SYBIMAGE:
516 0 : ret = destlen < len ? destlen : len;
517 0 : memcpy(dest, dres.ib, ret);
518 0 : free(dres.ib);
519 0 : break;
520 1762 : case SYBINT1:
521 : case SYBINT2:
522 : case SYBINT4:
523 : case SYBINT8:
524 : case SYBFLT8:
525 : case SYBREAL:
526 : case SYBBIT:
527 : case SYBBITN:
528 : case SYBMONEY:
529 : case SYBMONEY4:
530 : case SYBDATETIME:
531 : case SYBDATETIME4:
532 : case SYBNUMERIC:
533 : case SYBDECIMAL:
534 : case SYBUNIQUE:
535 : case SYBMSDATE:
536 : case SYBMSTIME:
537 : case SYBMSDATETIME2:
538 : case SYBMSDATETIMEOFFSET:
539 1762 : memcpy(dest, &dres, len);
540 1762 : ret = len;
541 1762 : break;
542 2 : case SYBCHAR:
543 : case SYBVARCHAR:
544 : case SYBTEXT:
545 2 : ret = _bcp_iconv_helper(dbc, bindcol, dres.c, len, (char *)dest, destlen);
546 2 : free(dres.c);
547 2 : break;
548 0 : default:
549 0 : tdsdump_log(TDS_DBG_INFO1, "error: dbconvert(): unrecognized desttype %d \n", desttype);
550 : ret = -1;
551 : break;
552 :
553 : }
554 : return (ret);
555 : }
556 :
557 : static TDSRET
558 4652 : _bcp_get_col_data(TDSBCPINFO *bcpinfo, TDSCOLUMN *bindcol, int offset TDS_UNUSED)
559 : {
560 : TDS_TINYINT ti;
561 : TDS_SMALLINT si;
562 : TDS_INT li;
563 : TDS_INT8 lli;
564 : TDS_SERVER_TYPE desttype, coltype;
565 : SQLLEN col_len;
566 : int data_is_null;
567 : SQLLEN bytes_read;
568 : int converted_data_size;
569 : TDS_CHAR *dataptr;
570 4652 : TDS_DBC *dbc = (TDS_DBC *) bcpinfo->parent;
571 :
572 4652 : tdsdump_log(TDS_DBG_FUNC, "_bcp_get_col_data(%p, %p)\n", bcpinfo, bindcol);
573 :
574 4652 : dataptr = bindcol->column_varaddr;
575 :
576 4652 : data_is_null = 0;
577 4652 : col_len = SQL_NULL_DATA;
578 :
579 : /* If a prefix length specified, read the correct amount of data. */
580 :
581 4652 : if (bindcol->bcp_prefix_len > 0) {
582 :
583 2320 : switch (bindcol->bcp_prefix_len) {
584 0 : case 1:
585 0 : memcpy(&ti, dataptr, 1);
586 0 : dataptr += 1;
587 0 : col_len = ti;
588 0 : break;
589 0 : case 2:
590 0 : memcpy(&si, dataptr, 2);
591 0 : dataptr += 2;
592 0 : col_len = si;
593 0 : break;
594 0 : case 4:
595 0 : memcpy(&li, dataptr, 4);
596 0 : dataptr += 4;
597 0 : col_len = li;
598 0 : break;
599 2320 : case 8:
600 2320 : memcpy(&lli, dataptr, 8);
601 2320 : dataptr += 8;
602 2320 : col_len = lli;
603 : if (lli != col_len)
604 : return TDS_FAIL;
605 : break;
606 : }
607 2320 : if (col_len == SQL_NULL_DATA)
608 : data_is_null = 1;
609 : }
610 :
611 : /* if (Max) column length specified take that into consideration. */
612 :
613 4652 : if (bindcol->column_bindlen == SQL_NULL_DATA)
614 : data_is_null = 1;
615 3530 : else if (!data_is_null && bindcol->column_bindlen != SQL_VARLEN_DATA) {
616 1770 : if (col_len != SQL_NULL_DATA)
617 880 : col_len = ((TDS_INT8)bindcol->column_bindlen < col_len) ? bindcol->column_bindlen : col_len;
618 : else
619 890 : col_len = bindcol->column_bindlen;
620 : }
621 :
622 4652 : desttype = tds_get_conversion_type(bindcol->column_type, bindcol->column_size);
623 :
624 : /* Fixed Length data - this overrides anything else specified */
625 4652 : coltype = bindcol->column_bindtype == 0 ? desttype : (TDS_SERVER_TYPE) bindcol->column_bindtype;
626 4652 : if (is_fixed_type(coltype)) {
627 1124 : col_len = tds_get_size_by_type(coltype);
628 : }
629 :
630 : /* read the data, finally */
631 :
632 4652 : if (!data_is_null && bindcol->bcp_term_len > 0) { /* terminated field */
633 0 : bytes_read = _bcp_get_term_var(dataptr, bindcol->bcp_terminator, bindcol->bcp_term_len);
634 :
635 0 : if (col_len != SQL_NULL_DATA)
636 0 : col_len = (bytes_read < col_len) ? bytes_read : col_len;
637 : else
638 : col_len = bytes_read;
639 : }
640 :
641 4652 : if (data_is_null) {
642 2242 : bindcol->bcp_column_data->datalen = 0;
643 2242 : bindcol->bcp_column_data->is_null = true;
644 : } else {
645 2410 : if ((converted_data_size =
646 2410 : _tdsodbc_dbconvert(dbc, coltype,
647 : dataptr, col_len,
648 2410 : desttype, bindcol->bcp_column_data->data, bindcol)) == -1) {
649 : return TDS_FAIL;
650 : }
651 :
652 2410 : bindcol->bcp_column_data->datalen = converted_data_size;
653 2410 : bindcol->bcp_column_data->is_null = false;
654 : }
655 :
656 : return TDS_SUCCESS;
657 : }
658 :
659 : /**
660 : * Get the data for bcp-in from program variables, where the program data
661 : * have been identified as character terminated,
662 : * This is a low-level, internal function. Call it correctly.
663 : */
664 : static SQLLEN
665 0 : _bcp_get_term_var(const TDS_CHAR * pdata, const TDS_CHAR * term, int term_len)
666 : {
667 : SQLLEN bufpos;
668 :
669 0 : assert(term_len > 0);
670 :
671 0 : if (term_len == 1 && *term == '\0') /* significant optimization for very common case */
672 0 : return strlen(pdata);
673 :
674 : /* if bufpos becomes negative, we probably failed to find the terminator */
675 0 : for (bufpos = 0; bufpos >= 0 && memcmp(pdata, term, term_len) != 0; pdata++) {
676 0 : bufpos++;
677 : }
678 :
679 : assert(bufpos >= 0);
680 : return bufpos;
681 : }
682 :
683 : void
684 952 : odbc_bcp_free_storage(TDS_DBC *dbc)
685 : {
686 952 : tdsdump_log(TDS_DBG_FUNC, "_bcp_free_storage(%p)\n", dbc);
687 952 : assert(dbc);
688 :
689 952 : tds_free_bcpinfo(dbc->bcpinfo);
690 952 : dbc->bcpinfo = NULL;
691 952 : }
692 :
|