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 0 : odbc_bcp_control(TDS_DBC *dbc, int field, void *value)
171 : {
172 0 : tdsdump_log(TDS_DBG_FUNC, "bcp_control(%p, %d, %p)\n", dbc, field, value);
173 0 : if (dbc->bcpinfo == NULL)
174 0 : ODBCBCP_ERROR_RETURN("HY010");
175 :
176 :
177 0 : switch (field) {
178 0 : case BCPKEEPIDENTITY:
179 0 : dbc->bcpinfo->identity_insert_on = (value != NULL);
180 0 : break;
181 0 : case BCPHINTS:
182 0 : if (!value)
183 0 : ODBCBCP_ERROR_RETURN("HY009");
184 0 : if (!tds_dstr_copy(&dbc->bcpinfo->hint, (char*)value))
185 0 : ODBCBCP_ERROR_RETURN("HY001");
186 : break;
187 0 : default:
188 0 : ODBCBCP_ERROR_RETURN("HY009");
189 : }
190 : }
191 :
192 : /**
193 : * \ingroup odbc_bcp
194 : * \brief Override bcp_bind() by pointing to a different host variable.
195 : *
196 : * \param dbc ODBC database connection object
197 : * \param colptr The pointer, the address of your variable.
198 : * \param table_column The 1-based column ordinal in the table.
199 : * \remarks Use between calls to bcp_sendrow(). After calling bcp_colptr(),
200 : * subsequent calls to bcp_sendrow() will bind to the new address.
201 : * \sa odbc_bcp_bind(), odbc_bcp_sendrow()
202 : */
203 : void
204 0 : odbc_bcp_colptr(TDS_DBC *dbc, const void * colptr, int table_column)
205 : {
206 : TDSCOLUMN *curcol;
207 :
208 0 : tdsdump_log(TDS_DBG_FUNC, "bcp_colptr(%p, %p, %d)\n", dbc, colptr, table_column);
209 0 : if (dbc->bcpinfo == NULL || dbc->bcpinfo->bindinfo == NULL)
210 0 : ODBCBCP_ERROR_RETURN("HY010");
211 : /* colptr can be NULL */
212 :
213 0 : if (dbc->bcpinfo->direction != BCP_DIRECTION_IN)
214 0 : ODBCBCP_ERROR_RETURN("HY010");
215 0 : if (table_column <= 0 || table_column > dbc->bcpinfo->bindinfo->num_cols)
216 0 : ODBCBCP_ERROR_RETURN("HY009");
217 :
218 0 : curcol = dbc->bcpinfo->bindinfo->columns[table_column - 1];
219 0 : curcol->column_varaddr = (TDS_CHAR *)colptr;
220 : }
221 :
222 :
223 : /**
224 : * \ingroup odbc_bcp
225 : * \brief Write data in host variables to the table.
226 : *
227 : * \param dbc ODBC database connection object
228 : *
229 : * \remarks Call bcp_bind() first to describe the variables to be used.
230 : * Use bcp_batch() to commit sets of rows.
231 : * After sending the last row call bcp_done().
232 : * \sa odbc_bcp_batch(), odbc_bcp_bind(), odbc_bcp_colptr(), odbc_bcp_done(),
233 : * odbc_bcp_init()
234 : */
235 : void
236 162 : odbc_bcp_sendrow(TDS_DBC *dbc)
237 : {
238 : TDSSOCKET *tds;
239 :
240 162 : tdsdump_log(TDS_DBG_FUNC, "bcp_sendrow(%p)\n", dbc);
241 162 : if (dbc->bcpinfo == NULL)
242 0 : ODBCBCP_ERROR_RETURN("HY010");
243 :
244 162 : tds = dbc->tds_socket;
245 :
246 162 : if (dbc->bcpinfo->direction != BCP_DIRECTION_IN)
247 0 : ODBCBCP_ERROR_RETURN("HY010");
248 :
249 : /*
250 : * The first time sendrow is called after bcp_init,
251 : * there is a certain amount of initialisation to be done.
252 : */
253 162 : if (dbc->bcpinfo->xfer_init == 0) {
254 :
255 : /* The start_copy function retrieves details of the table's columns */
256 18 : if (TDS_FAILED(tds_bcp_start_copy_in(tds, dbc->bcpinfo)))
257 0 : ODBCBCP_ERROR_RETURN("HY000");
258 :
259 18 : dbc->bcpinfo->xfer_init = 1;
260 : }
261 :
262 162 : dbc->bcpinfo->parent = dbc;
263 162 : if (TDS_FAILED(tds_bcp_send_record(dbc->tds_socket, dbc->bcpinfo, _bcp_get_col_data, NULL, 0)))
264 0 : ODBCBCP_ERROR_RETURN("HY000");
265 : }
266 :
267 :
268 : /**
269 : * \ingroup odbc_bcp
270 : * \brief Commit a set of rows to the table.
271 : *
272 : * \param dbc ODBC database connection object
273 : * \remarks If not called, bcp_done() will cause the rows to be saved.
274 : * \return Count of rows saved, or -1 on error.
275 : * \sa odbc_bcp_bind(), odbc_bcp_done(), odbc_bcp_sendrow()
276 : */
277 : int
278 18 : odbc_bcp_batch(TDS_DBC *dbc)
279 : {
280 18 : int rows_copied = 0;
281 :
282 18 : tdsdump_log(TDS_DBG_FUNC, "bcp_batch(%p)\n", dbc);
283 18 : if (dbc->bcpinfo == NULL)
284 0 : ODBCBCP_ERROR_DBINT("HY010");
285 :
286 18 : if (TDS_FAILED(tds_bcp_done(dbc->tds_socket, &rows_copied)))
287 0 : ODBCBCP_ERROR_DBINT("HY000");
288 :
289 18 : tds_bcp_start(dbc->tds_socket, dbc->bcpinfo);
290 :
291 18 : return rows_copied;
292 : }
293 :
294 : /**
295 : * \ingroup odbc_bcp
296 : * \brief Conclude the transfer of data from program variables.
297 : *
298 : * \param dbc ODBC database connection object
299 : * \remarks Do not overlook this function. According to Sybase, failure to call bcp_done()
300 : * "will result in unpredictable errors".
301 : * \return As with bcp_batch(), the count of rows saved, or -1 on error.
302 : * \sa bcp_batch(), bcp_bind(), bcp_moretext(), bcp_sendrow()
303 : */
304 : int
305 18 : odbc_bcp_done(TDS_DBC *dbc)
306 : {
307 : int rows_copied;
308 :
309 18 : tdsdump_log(TDS_DBG_FUNC, "bcp_done(%p)\n", dbc);
310 :
311 18 : if (!(dbc->bcpinfo))
312 0 : ODBCBCP_ERROR_DBINT("HY010");
313 :
314 18 : if (TDS_FAILED(tds_bcp_done(dbc->tds_socket, &rows_copied)))
315 0 : ODBCBCP_ERROR_DBINT("HY000");
316 :
317 18 : odbc_bcp_free_storage(dbc);
318 :
319 18 : return rows_copied;
320 : }
321 :
322 : /**
323 : * \ingroup odbc_bcp
324 : * \brief Bind a program host variable to a database column
325 : *
326 : * \param dbc ODBC database connection object
327 : * \param varaddr address of host variable
328 : * \param prefixlen length of any prefix found at the beginning of \a varaddr, in bytes.
329 : * Use zero for fixed-length datatypes.
330 : * \param varlen bytes of data in \a varaddr. Zero for NULL, -1 for fixed-length datatypes.
331 : * \param terminator byte sequence that marks the end of the data in \a varaddr
332 : * \param termlen length of \a terminator
333 : * \param vartype datatype of the host variable
334 : * \param table_column Nth column, starting at 1, in the table.
335 : *
336 : * \remarks The order of operation is:
337 : * - bcp_init() with \a hfile == NULL and \a direction == DB_IN.
338 : * - bcp_bind(), once per column you want to write to
339 : * - bcp_batch(), optionally, to commit a set of rows
340 : * - bcp_done()
341 : *
342 : * \sa odbc_bcp_batch(), odbc_bcp_done(), odbc_bcp_sendrow()
343 : */
344 : void
345 476 : odbc_bcp_bind(TDS_DBC *dbc, const void * varaddr, int prefixlen, int varlen,
346 : const void * terminator, int termlen, int vartype, int table_column)
347 : {
348 : TDSCOLUMN *colinfo;
349 :
350 476 : tdsdump_log(TDS_DBG_FUNC, "bcp_bind(%p, %p, %d, %d -- %p, %d, %d, %d)\n",
351 : dbc, varaddr, prefixlen, varlen,
352 : terminator, termlen, vartype, table_column);
353 476 : if (!dbc->bcpinfo)
354 0 : ODBCBCP_ERROR_RETURN("HY010");
355 :
356 476 : if (dbc->bcpinfo->direction != BCP_DIRECTION_IN)
357 0 : ODBCBCP_ERROR_RETURN("HY010");
358 :
359 476 : if (varlen < -1 && varlen != SQL_VARLEN_DATA)
360 0 : ODBCBCP_ERROR_RETURN("HY009");
361 :
362 476 : if (prefixlen != 0 && prefixlen != 1 && prefixlen != 2 && prefixlen != 4 && prefixlen != 8)
363 0 : ODBCBCP_ERROR_RETURN("HY009");
364 :
365 952 : if (vartype != 0 && !is_tds_type_valid(vartype))
366 0 : ODBCBCP_ERROR_RETURN("HY004");
367 :
368 476 : if (prefixlen == 0 && varlen == SQL_VARLEN_DATA && termlen == -1 && !is_fixed_type(vartype)) {
369 0 : tdsdump_log(TDS_DBG_FUNC, "bcp_bind(): non-fixed type %d requires prefix or terminator\n", vartype);
370 0 : ODBCBCP_ERROR_RETURN("HY009");
371 : }
372 :
373 476 : if (table_column <= 0 || table_column > dbc->bcpinfo->bindinfo->num_cols)
374 0 : ODBCBCP_ERROR_RETURN("HY009");
375 :
376 476 : if (varaddr == NULL && (prefixlen != 0 || termlen != 0))
377 0 : ODBCBCP_ERROR_RETURN("HY009");
378 :
379 476 : colinfo = dbc->bcpinfo->bindinfo->columns[table_column - 1];
380 :
381 : /* If varaddr is NULL and varlen greater than 0, the table column type must be SYBTEXT or SYBIMAGE
382 : and the program variable type must be SYBTEXT, SYBCHAR, SYBIMAGE or SYBBINARY */
383 476 : if (varaddr == NULL && varlen >= 0) {
384 0 : int fOK = (colinfo->column_type == SYBTEXT || colinfo->column_type == SYBIMAGE) &&
385 0 : (vartype == SYBTEXT || vartype == SYBCHAR || vartype == SYBIMAGE || vartype == SYBBINARY );
386 : if( !fOK ) {
387 0 : tdsdump_log(TDS_DBG_FUNC, "bcp_bind: SYBEBCBNTYP: column=%d and vartype=%d (should fail?)\n",
388 : colinfo->column_type, vartype);
389 0 : ODBCBCP_ERROR_RETURN("HY009");
390 : }
391 : }
392 :
393 476 : colinfo->column_varaddr = (char *)varaddr;
394 476 : colinfo->column_bindtype = vartype;
395 476 : colinfo->column_bindlen = varlen;
396 476 : colinfo->bcp_prefix_len = prefixlen;
397 :
398 476 : TDS_ZERO_FREE(colinfo->bcp_terminator);
399 476 : colinfo->bcp_term_len = 0;
400 476 : if (termlen > 0) {
401 0 : if ((colinfo->bcp_terminator = tds_new(TDS_CHAR, termlen)) == NULL)
402 0 : ODBCBCP_ERROR_RETURN("HY001");
403 0 : memcpy(colinfo->bcp_terminator, terminator, termlen);
404 0 : colinfo->bcp_term_len = termlen;
405 : }
406 : }
407 :
408 : static SQLLEN
409 484 : _bcp_iconv_helper(const TDS_DBC *dbc, const TDSCOLUMN *bindcol, const TDS_CHAR * src, size_t srclen, char * dest, size_t destlen)
410 : {
411 484 : if (bindcol->char_conv) {
412 484 : char *orig_dest = dest;
413 :
414 484 : if (tds_iconv(dbc->tds_socket, bindcol->char_conv, to_server, &src, &srclen, &dest, &destlen) == (size_t)-1)
415 : return -1;
416 484 : return dest - orig_dest;
417 : }
418 :
419 0 : if (destlen > srclen)
420 0 : destlen = srclen;
421 0 : memcpy(dest, src, destlen);
422 0 : return destlen;
423 : }
424 :
425 : static SQLLEN
426 2410 : _tdsodbc_dbconvert(TDS_DBC *dbc, int srctype, const TDS_CHAR * src, SQLLEN src_len,
427 : int desttype, unsigned char * dest, TDSCOLUMN *bindcol)
428 : {
429 : CONV_RESULT dres;
430 : SQLLEN ret;
431 : SQLLEN len;
432 2410 : SQLLEN destlen = bindcol->column_size;
433 : TDS_DATETIMEALL dta;
434 : TDS_NUMERIC num;
435 : SQL_NUMERIC_STRUCT * sql_num;
436 2410 : bool always_convert = false;
437 :
438 2410 : assert(src_len >= 0);
439 2410 : assert(src != NULL);
440 2410 : assert(dest != NULL);
441 2410 : assert(destlen > 0);
442 :
443 2410 : tdsdump_log(TDS_DBG_FUNC, "tdsodbc_dbconvert(%p, %d, %p, %d, %d, %p, %d)\n",
444 : dbc, srctype, src, (int)src_len, desttype, dest, (int)destlen);
445 :
446 2410 : switch (srctype) {
447 2 : case SYBMSDATETIME2:
448 2 : convert_datetime2server(SQL_C_TYPE_TIMESTAMP, src, &dta);
449 2 : dta.time_prec = (destlen - 40) / 2;
450 2 : src = (char *) &dta;
451 2 : break;
452 4 : case SYBDECIMAL:
453 : case SYBNUMERIC:
454 4 : sql_num = (SQL_NUMERIC_STRUCT *) src;
455 4 : num.precision = sql_num->precision;
456 4 : num.scale = sql_num->scale;
457 4 : num.array[0] = sql_num->sign ^ 1;
458 : /* test precision so client do not crash our library */
459 4 : if (num.precision <= 0 || num.precision > 38 || num.scale > num.precision)
460 : /* TODO add proper error */
461 : return -1;
462 4 : len = tds_numeric_bytes_per_prec[num.precision];
463 4 : memcpy(num.array + 1, sql_num->val, len - 1);
464 4 : tds_swap_bytes(num.array + 1, len - 1);
465 4 : if (len < sizeof(num.array))
466 4 : memset(num.array + len, 0, sizeof(num.array) - len);
467 4 : src = (char *) #
468 4 : always_convert = num.scale != bindcol->column_scale;
469 4 : break;
470 : /* TODO intervals */
471 : }
472 :
473 : /* oft times we are asked to convert a data type to itself */
474 2410 : if ((srctype == desttype || is_similar_type(srctype, desttype)) && !always_convert) {
475 646 : if (is_char_type(desttype)) {
476 482 : ret = _bcp_iconv_helper(dbc, bindcol, src, src_len, (char *)dest, destlen);
477 : }
478 : else {
479 164 : ret = destlen < src_len ? destlen : src_len;
480 164 : memcpy(dest, src, ret);
481 : }
482 : return ret;
483 : }
484 :
485 1764 : tdsdump_log(TDS_DBG_INFO1, "dbconvert() calling tds_convert\n");
486 :
487 1764 : if (is_numeric_type(desttype)) {
488 322 : dres.n.precision = bindcol->column_prec;
489 322 : dres.n.scale = bindcol->column_scale;
490 : }
491 1764 : len = tds_convert(dbc->env->tds_ctx, srctype, src, src_len, desttype, &dres);
492 1764 : tdsdump_log(TDS_DBG_INFO1, "dbconvert() called tds_convert returned %d\n", (int)len);
493 :
494 1764 : if (len < 0) {
495 0 : odbc_convert_err_set(&dbc->errs, len);
496 0 : return -1;
497 : }
498 :
499 1764 : switch (desttype) {
500 0 : case SYBBINARY:
501 : case SYBVARBINARY:
502 : case SYBIMAGE:
503 0 : ret = destlen < len ? destlen : len;
504 0 : memcpy(dest, dres.ib, ret);
505 0 : free(dres.ib);
506 0 : break;
507 1762 : case SYBINT1:
508 : case SYBINT2:
509 : case SYBINT4:
510 : case SYBINT8:
511 : case SYBFLT8:
512 : case SYBREAL:
513 : case SYBBIT:
514 : case SYBBITN:
515 : case SYBMONEY:
516 : case SYBMONEY4:
517 : case SYBDATETIME:
518 : case SYBDATETIME4:
519 : case SYBNUMERIC:
520 : case SYBDECIMAL:
521 : case SYBUNIQUE:
522 : case SYBMSDATE:
523 : case SYBMSTIME:
524 : case SYBMSDATETIME2:
525 : case SYBMSDATETIMEOFFSET:
526 1762 : memcpy(dest, &dres, len);
527 1762 : ret = len;
528 1762 : break;
529 2 : case SYBCHAR:
530 : case SYBVARCHAR:
531 : case SYBTEXT:
532 2 : ret = _bcp_iconv_helper(dbc, bindcol, dres.c, len, (char *)dest, destlen);
533 2 : free(dres.c);
534 2 : break;
535 0 : default:
536 0 : tdsdump_log(TDS_DBG_INFO1, "error: dbconvert(): unrecognized desttype %d \n", desttype);
537 : ret = -1;
538 : break;
539 :
540 : }
541 : return (ret);
542 : }
543 :
544 : static TDSRET
545 4652 : _bcp_get_col_data(TDSBCPINFO *bcpinfo, TDSCOLUMN *bindcol, int offset)
546 : {
547 : TDS_TINYINT ti;
548 : TDS_SMALLINT si;
549 : TDS_INT li;
550 : TDS_INT8 lli;
551 : TDS_SERVER_TYPE desttype, coltype;
552 : SQLLEN col_len;
553 : int data_is_null;
554 : SQLLEN bytes_read;
555 : int converted_data_size;
556 : TDS_CHAR *dataptr;
557 4652 : TDS_DBC *dbc = (TDS_DBC *) bcpinfo->parent;
558 :
559 4652 : tdsdump_log(TDS_DBG_FUNC, "_bcp_get_col_data(%p, %p)\n", bcpinfo, bindcol);
560 :
561 4652 : dataptr = bindcol->column_varaddr;
562 :
563 4652 : data_is_null = 0;
564 4652 : col_len = SQL_NULL_DATA;
565 :
566 : /* If a prefix length specified, read the correct amount of data. */
567 :
568 4652 : if (bindcol->bcp_prefix_len > 0) {
569 :
570 2320 : switch (bindcol->bcp_prefix_len) {
571 0 : case 1:
572 0 : memcpy(&ti, dataptr, 1);
573 0 : dataptr += 1;
574 0 : col_len = ti;
575 0 : break;
576 0 : case 2:
577 0 : memcpy(&si, dataptr, 2);
578 0 : dataptr += 2;
579 0 : col_len = si;
580 0 : break;
581 0 : case 4:
582 0 : memcpy(&li, dataptr, 4);
583 0 : dataptr += 4;
584 0 : col_len = li;
585 0 : break;
586 2320 : case 8:
587 2320 : memcpy(&lli, dataptr, 8);
588 2320 : dataptr += 8;
589 2320 : col_len = lli;
590 : if (lli != col_len)
591 : return TDS_FAIL;
592 : break;
593 : }
594 2320 : if (col_len == SQL_NULL_DATA)
595 : data_is_null = 1;
596 : }
597 :
598 : /* if (Max) column length specified take that into consideration. */
599 :
600 4652 : if (bindcol->column_bindlen == SQL_NULL_DATA)
601 : data_is_null = 1;
602 3530 : else if (!data_is_null && bindcol->column_bindlen != SQL_VARLEN_DATA) {
603 1770 : if (col_len != SQL_NULL_DATA)
604 880 : col_len = ((TDS_INT8)bindcol->column_bindlen < col_len) ? bindcol->column_bindlen : col_len;
605 : else
606 890 : col_len = bindcol->column_bindlen;
607 : }
608 :
609 4652 : desttype = tds_get_conversion_type(bindcol->column_type, bindcol->column_size);
610 :
611 : /* Fixed Length data - this overrides anything else specified */
612 4652 : coltype = bindcol->column_bindtype == 0 ? desttype : (TDS_SERVER_TYPE) bindcol->column_bindtype;
613 4652 : if (is_fixed_type(coltype)) {
614 1124 : col_len = tds_get_size_by_type(coltype);
615 : }
616 :
617 : /* read the data, finally */
618 :
619 4652 : if (!data_is_null && bindcol->bcp_term_len > 0) { /* terminated field */
620 0 : bytes_read = _bcp_get_term_var(dataptr, bindcol->bcp_terminator, bindcol->bcp_term_len);
621 :
622 0 : if (col_len != SQL_NULL_DATA)
623 0 : col_len = (bytes_read < col_len) ? bytes_read : col_len;
624 : else
625 : col_len = bytes_read;
626 : }
627 :
628 4652 : if (data_is_null) {
629 2242 : bindcol->bcp_column_data->datalen = 0;
630 2242 : bindcol->bcp_column_data->is_null = true;
631 : } else {
632 2410 : if ((converted_data_size =
633 2410 : _tdsodbc_dbconvert(dbc, coltype,
634 : dataptr, col_len,
635 2410 : desttype, bindcol->bcp_column_data->data, bindcol)) == -1) {
636 : return TDS_FAIL;
637 : }
638 :
639 2410 : bindcol->bcp_column_data->datalen = converted_data_size;
640 2410 : bindcol->bcp_column_data->is_null = false;
641 : }
642 :
643 : return TDS_SUCCESS;
644 : }
645 :
646 : /**
647 : * Get the data for bcp-in from program variables, where the program data
648 : * have been identified as character terminated,
649 : * This is a low-level, internal function. Call it correctly.
650 : */
651 : static SQLLEN
652 0 : _bcp_get_term_var(const TDS_CHAR * pdata, const TDS_CHAR * term, int term_len)
653 : {
654 : SQLLEN bufpos;
655 :
656 0 : assert(term_len > 0);
657 :
658 0 : if (term_len == 1 && *term == '\0') /* significant optimization for very common case */
659 0 : return strlen(pdata);
660 :
661 : /* if bufpos becomes negative, we probably failed to find the terminator */
662 0 : for (bufpos = 0; bufpos >= 0 && memcmp(pdata, term, term_len) != 0; pdata++) {
663 0 : bufpos++;
664 : }
665 :
666 : assert(bufpos >= 0);
667 : return bufpos;
668 : }
669 :
670 : void
671 936 : odbc_bcp_free_storage(TDS_DBC *dbc)
672 : {
673 936 : tdsdump_log(TDS_DBG_FUNC, "_bcp_free_storage(%p)\n", dbc);
674 936 : assert(dbc);
675 :
676 936 : tds_free_bcpinfo(dbc->bcpinfo);
677 936 : dbc->bcpinfo = NULL;
678 936 : }
679 :
|