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/bytes.h>
47 #include <freetds/utils/string.h>
48 #include <freetds/encodings.h>
49 #include <freetds/replacements.h>
50 #include <sybfront.h>
51 #include <sybdb.h>
52 #include <syberror.h>
53 #include <dblib.h>
54
55 #define HOST_COL_CONV_ERROR 1
56 #define HOST_COL_NULL_ERROR 2
57
58 #ifndef MAX
59 #define MAX(a,b) ( (a) > (b) ? (a) : (b) )
60 #endif
61
62 #ifdef HAVE_FSEEKO
63 typedef off_t offset_type;
64 #elif defined(_WIN32) || defined(_WIN64)
65 /* win32 version */
66 typedef __int64 offset_type;
67 # if defined(HAVE__FSEEKI64) && defined(HAVE__FTELLI64)
68 # define fseeko(f,o,w) _fseeki64((f),o,w)
69 # define ftello(f) _ftelli64((f))
70 # else
71 # define fseeko(f,o,w) (_lseeki64(fileno(f),o,w) == -1 ? -1 : 0)
72 # define ftello(f) _telli64(fileno(f))
73 # endif
74 #else
75 /* use old version */
76 #define fseeko(f,o,w) fseek(f,o,w)
77 #define ftello(f) ftell(f)
78 typedef long offset_type;
79 #endif
80
81 static void _bcp_free_storage(DBPROCESS * dbproc);
82 static void _bcp_free_columns(DBPROCESS * dbproc);
83 static void _bcp_null_error(TDSBCPINFO *bcpinfo, int index, int offset);
84 static TDSRET _bcp_get_col_data(TDSBCPINFO *bcpinfo, TDSCOLUMN *bindcol, int offset);
85 static TDSRET _bcp_no_get_col_data(TDSBCPINFO *bcpinfo, TDSCOLUMN *bindcol, int offset);
86
87 static int rtrim(char *, int);
88 static int rtrim_u16(uint16_t *str, int len, uint16_t space);
89 static STATUS _bcp_read_hostfile(DBPROCESS * dbproc, FILE * hostfile, int *row_error, bool skip);
90 static int _bcp_readfmt_colinfo(DBPROCESS * dbproc, char *buf, BCP_HOSTCOLINFO * ci);
91 static int _bcp_get_term_var(const BYTE * pdata, const BYTE * term, int term_len);
92
93 /*
94 * "If a host file is being used ... the default data formats are as follows:
95 *
96 * > The order, type, length and number of the columns in the host file are
97 * assumed to be identical to the order, type and number of the columns in the database table.
98 * > If a given database column's data is fixed-length,
99 * then the host file's data column will also be fixed-length.
100 * > If a given database column's data is variable-length or may contain null values,
101 * the host file's data column will be prefixed by
102 * a 4-byte length value for SYBTEXT and SYBIMAGE data types, and
103 * a 1-byte length value for all other types.
104 * > There are no terminators of any kind between host file columns."
105 */
106
107 static void
init_hostfile_columns(DBPROCESS * dbproc)108 init_hostfile_columns(DBPROCESS *dbproc)
109 {
110 const int ncols = dbproc->bcpinfo->bindinfo->num_cols;
111 RETCODE erc;
112 int icol;
113
114 if (ncols == 0)
115 return;
116
117 if ((erc = bcp_columns(dbproc, ncols)) != SUCCEED) {
118 assert(erc == SUCCEED);
119 return;
120 }
121
122 for (icol = 0; icol < ncols; icol++) {
123 const TDSCOLUMN *pcol = dbproc->bcpinfo->bindinfo->columns[icol];
124 int prefixlen = 0, termlen = 0;
125
126 switch (pcol->column_type) {
127 case SYBTEXT:
128 case SYBIMAGE:
129 prefixlen = 4;
130 break;
131 default:
132 prefixlen = dbvarylen(dbproc, icol+1)? 1 : 0;
133 }
134
135 erc = bcp_colfmt(dbproc, icol+1, pcol->column_type, prefixlen, pcol->column_size, NULL, termlen, icol+1);
136
137 assert(erc == SUCCEED);
138 if (erc != SUCCEED)
139 return;
140 }
141 }
142
143
144 /**
145 * \ingroup dblib_bcp
146 * \brief Prepare for bulk copy operation on a table
147 *
148 * \param dbproc contains all information needed by db-lib to manage communications with the server.
149 * \param tblname the name of the table receiving or providing the data.
150 * \param hfile the data file opposite the table, if any.
151 * \param errfile the "error file" captures messages and, if errors are encountered,
152 * copies of any rows that could not be written to the table.
153 * \param direction one of
154 * - \b DB_IN writing to the table
155 * - \b DB_OUT writing to the host file
156 * .
157 * \remarks bcp_init() sets the host file data format and acquires the table metadata.
158 * It is called before the other bulk copy functions.
159 *
160 * When writing to a table, bcp can use as its data source a data file (\a hfile),
161 * or program data in an application's variables. In the latter case, call bcp_bind()
162 * to associate your data with the appropriate table column.
163 * \return SUCCEED or FAIL.
164 * \sa BCP_SETL(), bcp_bind(), bcp_done(), bcp_exec()
165 */
166 RETCODE
bcp_init(DBPROCESS * dbproc,const char * tblname,const char * hfile,const char * errfile,int direction)167 bcp_init(DBPROCESS * dbproc, const char *tblname, const char *hfile, const char *errfile, int direction)
168 {
169 tdsdump_log(TDS_DBG_FUNC, "bcp_init(%p, %s, %s, %s, %d)\n",
170 dbproc, tblname? tblname:"NULL", hfile? hfile:"NULL", errfile? errfile:"NULL", direction);
171 CHECK_CONN(FAIL);
172
173 /*
174 * Validate other parameters
175 */
176 if (dbproc->tds_socket->conn->tds_version < 0x500) {
177 dbperror(dbproc, SYBETDSVER, 0);
178 return FAIL;
179 }
180
181 if (tblname == NULL) {
182 dbperror(dbproc, SYBEBCITBNM, 0);
183 return FAIL;
184 }
185
186 if (direction != DB_QUERYOUT && !IS_TDS7_PLUS(dbproc->tds_socket->conn) &&
187 strlen(tblname) > 92) { /* 30.30.30 for Sybase */
188 dbperror(dbproc, SYBEBCITBLEN, 0);
189 return FAIL;
190 }
191
192 if (direction != DB_IN && direction != DB_OUT && direction != DB_QUERYOUT) {
193 dbperror(dbproc, SYBEBDIO, 0);
194 return FAIL;
195 }
196
197 /* Free previously allocated storage in dbproc & initialise flags, etc. */
198 _bcp_free_storage(dbproc);
199
200 /* Allocate storage */
201 dbproc->bcpinfo = tds_alloc_bcpinfo();
202 if (dbproc->bcpinfo == NULL)
203 goto memory_error;
204
205 if (!tds_dstr_copy(&dbproc->bcpinfo->tablename, tblname))
206 goto memory_error;
207
208 dbproc->bcpinfo->direction = direction;
209
210 dbproc->bcpinfo->xfer_init = 0;
211 dbproc->bcpinfo->bind_count = 0;
212
213 if (TDS_FAILED(tds_bcp_init(dbproc->tds_socket, dbproc->bcpinfo))) {
214 /* TODO return proper error */
215 /* Attempt to use Bulk Copy with a non-existent Server table (might be why ...) */
216 dbperror(dbproc, SYBEBCNT, 0);
217 return FAIL;
218 }
219
220 /* Prepare default hostfile columns */
221
222 if (hfile == NULL) {
223 dbproc->hostfileinfo = NULL;
224 return SUCCEED;
225 }
226
227 dbproc->hostfileinfo = tds_new0(BCP_HOSTFILEINFO, 1);
228
229 if (dbproc->hostfileinfo == NULL)
230 goto memory_error;
231 dbproc->hostfileinfo->maxerrs = 10;
232 dbproc->hostfileinfo->firstrow = 1;
233 if ((dbproc->hostfileinfo->hostfile = strdup(hfile)) == NULL)
234 goto memory_error;
235
236 if (errfile != NULL)
237 if ((dbproc->hostfileinfo->errorfile = strdup(errfile)) == NULL)
238 goto memory_error;
239
240 init_hostfile_columns(dbproc);
241
242 return SUCCEED;
243
244 memory_error:
245 _bcp_free_storage(dbproc);
246 dbperror(dbproc, SYBEMEM, ENOMEM);
247 return FAIL;
248 }
249
250
251 /**
252 * \ingroup dblib_bcp
253 * \brief Set the length of a host variable to be written to a table.
254 *
255 * \param dbproc contains all information needed by db-lib to manage communications with the server.
256 * \param varlen size of the variable, in bytes, or
257 * - \b 0 indicating NULL
258 * - \b -1 indicating size is determined by the prefix or terminator.
259 * (If both a prefix and a terminator are present, bcp is supposed to use the smaller of the
260 * two. This feature might or might not actually work.)
261 * \param table_column the number of the column in the table (starting with 1, not zero).
262 *
263 * \return SUCCEED or FAIL.
264 * \sa bcp_bind(), bcp_colptr(), bcp_sendrow()
265 */
266 RETCODE
bcp_collen(DBPROCESS * dbproc,DBINT varlen,int table_column)267 bcp_collen(DBPROCESS * dbproc, DBINT varlen, int table_column)
268 {
269 TDSCOLUMN *bcpcol;
270
271 tdsdump_log(TDS_DBG_FUNC, "bcp_collen(%p, %d, %d)\n", dbproc, varlen, table_column);
272
273 CHECK_CONN(FAIL);
274 CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL); /* not initialized */
275 DBPERROR_RETURN(dbproc->bcpinfo->direction != DB_IN, SYBEBCPN) /* not inbound */
276 DBPERROR_RETURN(dbproc->hostfileinfo != NULL, SYBEBCPI) /* cannot have data file */
277 CHECK_PARAMETER(0 < table_column &&
278 table_column <= dbproc->bcpinfo->bindinfo->num_cols, SYBECNOR, FAIL);
279
280 bcpcol = dbproc->bcpinfo->bindinfo->columns[table_column - 1];
281
282 /* Sybase library does not check for NULL here, only sending, so don't
283 * check and send SYBEBCNN */
284 bcpcol->column_bindlen = varlen;
285
286 return SUCCEED;
287 }
288
289 /**
290 * \ingroup dblib_bcp
291 * \brief Indicate how many columns are to be found in the datafile.
292 *
293 * \param dbproc contains all information needed by db-lib to manage communications with the server.
294 * \param host_colcount count of columns in the datafile, irrespective of how many you intend to use.
295 * \remarks This function describes the file as it is, not how it will be used.
296 *
297 * \return SUCCEED or FAIL. It's hard to see how it could fail.
298 * \sa bcp_colfmt()
299 */
300 RETCODE
bcp_columns(DBPROCESS * dbproc,int host_colcount)301 bcp_columns(DBPROCESS * dbproc, int host_colcount)
302 {
303 int i;
304
305 tdsdump_log(TDS_DBG_FUNC, "bcp_columns(%p, %d)\n", dbproc, host_colcount);
306 CHECK_CONN(FAIL);
307 CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);
308 CHECK_PARAMETER(dbproc->hostfileinfo, SYBEBIVI, FAIL);
309
310 if (host_colcount < 1) {
311 dbperror(dbproc, SYBEBCFO, 0);
312 return FAIL;
313 }
314
315 _bcp_free_columns(dbproc);
316
317 dbproc->hostfileinfo->host_columns = tds_new0(BCP_HOSTCOLINFO *, host_colcount);
318 if (dbproc->hostfileinfo->host_columns == NULL) {
319 dbperror(dbproc, SYBEMEM, ENOMEM);
320 return FAIL;
321 }
322
323 dbproc->hostfileinfo->host_colcount = host_colcount;
324
325 for (i = 0; i < host_colcount; i++) {
326 dbproc->hostfileinfo->host_columns[i] = tds_new0(BCP_HOSTCOLINFO, 1);
327 if (dbproc->hostfileinfo->host_columns[i] == NULL) {
328 dbproc->hostfileinfo->host_colcount = i;
329 _bcp_free_columns(dbproc);
330 dbperror(dbproc, SYBEMEM, ENOMEM);
331 return FAIL;
332 }
333 }
334
335 return SUCCEED;
336 }
337
338 /**
339 * \ingroup dblib_bcp
340 * \brief Specify the format of a datafile prior to writing to a table.
341 *
342 * \param dbproc contains all information needed by db-lib to manage communications with the server.
343 * \param host_colnum datafile column number (starting with 1, not zero).
344 * \param host_type dataype token describing the data type in \a host_colnum. E.g. SYBCHAR for character data.
345 * \param host_prefixlen size of the prefix in the datafile column, if any. For delimited files: zero.
346 * May be 0, 1, 2, or 4 bytes. The prefix will be read as an integer (not a character string) from the
347 * data file, and will be interpreted the data size of that column, in bytes.
348 * \param host_collen maximum size of datafile column, exclusive of any prefix/terminator. Just the data, ma'am.
349 * Special values:
350 * - \b 0 indicates NULL.
351 * - \b -1 for fixed-length non-null datatypes
352 * - \b -1 for variable-length datatypes (e.g. SYBCHAR) where the length is established
353 * by a prefix/terminator.
354 * \param host_term the sequence of characters that will serve as a column terminator (delimiter) in the datafile.
355 * Often a tab character, but can be any string of any length. Zero indicates no terminator.
356 * Special characters:
357 * - \b '\\0' terminator is an ASCII NUL.
358 * - \b '\\t' terminator is an ASCII TAB.
359 * - \b '\\n' terminator is an ASCII NL.
360 * \param host_termlen the length of \a host_term, in bytes.
361 * \param table_colnum Nth column, starting at 1, in the table that maps to \a host_colnum.
362 * If there is a column in the datafile that does not map to a table column, set \a table_colnum to zero.
363 *
364 *\remarks bcp_colfmt() is called once for each column in the datafile, as specified with bcp_columns().
365 * In so doing, you describe to FreeTDS how to parse each line of your datafile, and where to send each field.
366 *
367 * When a prefix or terminator is used with variable-length data, \a host_collen may have one of three values:
368 * - \b positive indicating the maximum number of bytes to be used
369 * - \b 0 indicating NULL
370 * - \b -1 indicating no maximum; all data, as described by the prefix/terminator will be used.
371 * .
372 * \return SUCCEED or FAIL.
373 * \sa bcp_batch(), bcp_bind(), bcp_colfmt_ps(), bcp_collen(), bcp_colptr(), bcp_columns(),
374 * bcp_control(), bcp_done(), bcp_exec(), bcp_init(), bcp_sendrow
375 */
376 RETCODE
bcp_colfmt(DBPROCESS * dbproc,int host_colnum,int host_type,int host_prefixlen,DBINT host_collen,const BYTE * host_term,int host_termlen,int table_colnum)377 bcp_colfmt(DBPROCESS * dbproc, int host_colnum, int host_type, int host_prefixlen, DBINT host_collen, const BYTE * host_term,
378 int host_termlen, int table_colnum)
379 {
380 BCP_HOSTCOLINFO *hostcol;
381 BYTE *terminator = NULL;
382
383 tdsdump_log(TDS_DBG_FUNC, "bcp_colfmt(%p, %d, %d, %d, %d, %p, %d, %d)\n",
384 dbproc, host_colnum, host_type, host_prefixlen, (int) host_collen, host_term, host_termlen, table_colnum);
385 CHECK_CONN(FAIL);
386 CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);
387 CHECK_PARAMETER(dbproc->hostfileinfo, SYBEBIVI, FAIL);
388
389 /* Microsoft specifies a "file_termlen" of zero if there's no terminator */
390 if (dbproc->msdblib && host_termlen == 0)
391 host_termlen = -1;
392
393 if (host_termlen < 0)
394 host_termlen = -1;
395
396 if (dbproc->hostfileinfo->host_colcount == 0) {
397 dbperror(dbproc, SYBEBCBC, 0);
398 return FAIL;
399 }
400
401 if (host_colnum < 1) {
402 dbperror(dbproc, SYBEBCFO, 0);
403 return FAIL;
404 }
405
406 if (host_colnum > dbproc->hostfileinfo->host_colcount) {
407 dbperror(dbproc, SYBECNOR, 0);
408 return FAIL;
409 }
410
411 if (host_prefixlen != 0 && host_prefixlen != 1 && host_prefixlen != 2 && host_prefixlen != 4 && host_prefixlen != -1) {
412 dbperror(dbproc, SYBEBCPREF, 0);
413 return FAIL;
414 }
415
416 /* if column is not copied you cannot specify destination type */
417 if (table_colnum <= 0 && host_type == 0) {
418 dbperror(dbproc, SYBEBCPCTYP, 0);
419 return FAIL;
420 }
421
422 if (table_colnum > 0 && !is_tds_type_valid(host_type)) {
423 dbperror(dbproc, SYBEUDTY, 0);
424 return FAIL;
425 }
426
427 if (host_type && host_prefixlen == 0 && host_collen == -1 && host_termlen == -1 && !is_fixed_type(host_type)) {
428 dbperror(dbproc, SYBEVDPT, 0);
429 return FAIL;
430 }
431
432 if (host_collen < -1) {
433 dbperror(dbproc, SYBEBCHLEN, 0);
434 return FAIL;
435 }
436
437 /* No official error message. Fix and warn. */
438 if (is_fixed_type(host_type) && (host_collen != -1 && host_collen != 0)) {
439 tdsdump_log(TDS_DBG_FUNC,
440 "bcp_colfmt: changing host_collen to -1 from %d for fixed type %d.\n",
441 host_collen, host_type);
442 host_collen = -1;
443 }
444
445 /*
446 * If there's a positive terminator length, we need a valid terminator pointer.
447 * If the terminator length is 0 or -1, then there's no terminator.
448 */
449 if (host_term == NULL && host_termlen > 0) {
450 dbperror(dbproc, SYBEVDPT, 0); /* "all variable-length data must have either a length-prefix ..." */
451 return FAIL;
452 }
453
454 hostcol = dbproc->hostfileinfo->host_columns[host_colnum - 1];
455
456 /* TODO add precision scale and join with bcp_colfmt_ps */
457 if (host_term && host_termlen > 0) {
458 if ((terminator = tds_new(BYTE, host_termlen)) == NULL) {
459 dbperror(dbproc, SYBEMEM, errno);
460 return FAIL;
461 }
462 memcpy(terminator, host_term, host_termlen);
463 }
464 hostcol->host_column = host_colnum;
465 hostcol->datatype = host_type ? (TDS_SERVER_TYPE) host_type : TDS_INVALID_TYPE;
466 hostcol->prefix_len = host_prefixlen;
467 hostcol->column_len = host_collen;
468 free(hostcol->terminator);
469 hostcol->terminator = terminator;
470 hostcol->term_len = host_termlen;
471 hostcol->tab_colnum = table_colnum;
472
473 return SUCCEED;
474 }
475
476 /**
477 * \ingroup dblib_bcp
478 * \brief Specify the format of a host file for bulk copy purposes,
479 * with precision and scale support for numeric and decimal columns.
480 *
481 * \param dbproc contains all information needed by db-lib to manage communications with the server.
482 * \param host_colnum datafile column number (starting with 1, not zero).
483 * \param host_type dataype token describing the data type in \a host_colnum. E.g. SYBCHAR for character data.
484 * \param host_prefixlen size of the prefix in the datafile column, if any. For delimited files: zero.
485 * May be 0, 1, 2, or 4 bytes. The prefix will be read as an integer (not a character string) from the
486 * data file, and will be interpreted the data size of that column, in bytes.
487 * \param host_collen maximum size of datafile column, exclusive of any prefix/terminator. Just the data, ma'am.
488 * Special values:
489 * - \b 0 indicates NULL.
490 * - \b -1 for fixed-length non-null datatypes
491 * - \b -1 for variable-length datatypes (e.g. SYBCHAR) where the length is established
492 * by a prefix/terminator.
493 * \param host_term the sequence of characters that will serve as a column terminator (delimiter) in the datafile.
494 * Often a tab character, but can be any string of any length. Zero indicates no terminator.
495 * Special characters:
496 * - \b '\\0' terminator is an ASCII NUL.
497 * - \b '\\t' terminator is an ASCII TAB.
498 * - \b '\\n' terminator is an ASCII NL.
499 * \param host_termlen the length of \a host_term, in bytes.
500 * \param table_colnum Nth column, starting at 1, in the table that maps to \a host_colnum.
501 * If there is a column in the datafile that does not map to a table column, set \a table_colnum to zero.
502 * \param typeinfo something
503 * \todo Not implemented.
504 * \return SUCCEED or FAIL.
505 * \sa bcp_batch(), bcp_bind(), bcp_colfmt(), bcp_collen(), bcp_colptr(), bcp_columns(),
506 * bcp_control(), bcp_done(), bcp_exec(), bcp_init(), bcp_sendrow
507 */
508 RETCODE
bcp_colfmt_ps(DBPROCESS * dbproc,int host_colnum,int host_type,int host_prefixlen,DBINT host_collen,BYTE * host_term,int host_termlen,int table_colnum,DBTYPEINFO * typeinfo)509 bcp_colfmt_ps(DBPROCESS * dbproc, int host_colnum, int host_type,
510 int host_prefixlen, DBINT host_collen, BYTE * host_term, int host_termlen, int table_colnum, DBTYPEINFO * typeinfo)
511 {
512 tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED: bcp_colfmt_ps(%p, %d, %d)\n", dbproc, host_colnum, host_type);
513 CHECK_CONN(FAIL);
514 CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);
515
516 /* dbperror(dbproc, , 0); Illegal precision specified */
517
518 /* TODO see bcp_colfmt */
519 return FAIL;
520 }
521
522
523 /**
524 * \ingroup dblib_bcp
525 * \brief Set BCP options for uploading a datafile
526 *
527 * \param dbproc contains all information needed by db-lib to manage communications with the server.
528 * \param field symbolic constant indicating the option to be set, one of:
529 * - \b BCPMAXERRS Maximum errors tolerated before quitting. The default is 10.
530 * - \b BCPFIRST The first row to read in the datafile. The default is 1.
531 * - \b BCPLAST The last row to read in the datafile. The default is to copy all rows. A value of
532 * -1 resets this field to its default?
533 * - \b BCPBATCH The number of rows per batch. Default is 0, meaning a single batch.
534 * \param value The value for \a field.
535 *
536 * \remarks These options control the behavior of bcp_exec().
537 * When writing to a table from application host memory variables,
538 * program logic controls error tolerance and batch size.
539 *
540 * \return SUCCEED or FAIL.
541 * \sa bcp_batch(), bcp_bind(), bcp_colfmt(), bcp_collen(), bcp_colptr(), bcp_columns(), bcp_done(), bcp_exec(), bcp_options()
542 */
543 RETCODE
bcp_control(DBPROCESS * dbproc,int field,DBINT value)544 bcp_control(DBPROCESS * dbproc, int field, DBINT value)
545 {
546 tdsdump_log(TDS_DBG_FUNC, "bcp_control(%p, %d, %d)\n", dbproc, field, value);
547 CHECK_CONN(FAIL);
548 CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);
549
550 if (field == BCPKEEPIDENTITY) {
551 dbproc->bcpinfo->identity_insert_on = (value != 0);
552 return SUCCEED;
553 }
554
555 CHECK_PARAMETER(dbproc->hostfileinfo, SYBEBIVI, FAIL);
556
557 switch (field) {
558
559 case BCPMAXERRS:
560 if (value < 1)
561 value = 10;
562 dbproc->hostfileinfo->maxerrs = value;
563 break;
564 case BCPFIRST:
565 if (value < 1)
566 value = 1;
567 dbproc->hostfileinfo->firstrow = value;
568 break;
569 case BCPLAST:
570 dbproc->hostfileinfo->lastrow = value;
571 break;
572 case BCPBATCH:
573 dbproc->hostfileinfo->batch = value;
574 break;
575
576 default:
577 dbperror(dbproc, SYBEIFNB, 0);
578 return FAIL;
579 }
580 return SUCCEED;
581 }
582
583 /*
584 * \ingroup dblib_bcp
585 * \brief Get BCP batch option
586 *
587 * \param dbproc contains all information needed by db-lib to manage communications with the server.
588 * \remarks This function is specific to FreeTDS.
589 *
590 * \return the value that was set by bcp_control.
591 * \sa bcp_batch(), bcp_control()
592 */
593 int
bcp_getbatchsize(DBPROCESS * dbproc)594 bcp_getbatchsize(DBPROCESS * dbproc)
595 {
596 return dbproc->hostfileinfo->batch;
597 }
598
599 /**
600 * \ingroup dblib_bcp
601 * \brief Set "hints" for uploading a file. A FreeTDS-only function.
602 *
603 * \param dbproc contains all information needed by db-lib to manage communications with the server.
604 * \param option symbolic constant indicating the option to be set, one of:
605 * - \b BCPLABELED Not implemented.
606 * - \b BCPHINTS The hint to be passed when the bulk-copy begins.
607 * \param value The string constant for \a option a/k/a the hint. One of:
608 * - \b ORDER The data are ordered in accordance with the table's clustered index.
609 * - \b ROWS_PER_BATCH The batch size
610 * - \b KILOBYTES_PER_BATCH The approximate number of kilobytes to use for a batch size
611 * - \b TABLOCK Lock the table
612 * - \b CHECK_CONSTRAINTS Apply constraints
613 * - \b FIRE_TRIGGERS Fire any INSERT triggers on the target table
614 * \param valuelen The strlen of \a value.
615 *
616 * \return SUCCEED or FAIL.
617 * \sa bcp_control(),
618 * bcp_exec(),
619 * \todo Simplify. Remove \a valuelen, and dbproc->bcpinfo->hint = strdup(hints[i])
620 */
621 RETCODE
bcp_options(DBPROCESS * dbproc,int option,BYTE * value,int valuelen)622 bcp_options(DBPROCESS * dbproc, int option, BYTE * value, int valuelen)
623 {
624 int i;
625 static const char *const hints[] = {
626 "ORDER", "ROWS_PER_BATCH", "KILOBYTES_PER_BATCH", "TABLOCK", "CHECK_CONSTRAINTS",
627 "FIRE_TRIGGERS", "KEEP_NULLS", NULL
628 };
629
630 tdsdump_log(TDS_DBG_FUNC, "bcp_options(%p, %d, %p, %d)\n", dbproc, option, value, valuelen);
631 CHECK_CONN(FAIL);
632 CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);
633 CHECK_NULP(value, "bcp_options", 3, FAIL);
634
635 switch (option) {
636 case BCPLABELED:
637 tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED bcp option: BCPLABELED\n");
638 break;
639 case BCPHINTS:
640 if (!value || valuelen <= 0)
641 break;
642
643 for (i = 0; hints[i]; i++) { /* look up hint */
644 if (strncasecmp((char *) value, hints[i], strlen(hints[i])) == 0) {
645 dbproc->bcpinfo->hint = hints[i]; /* safe: hints[i] is static constant, above */
646 return SUCCEED;
647 }
648 }
649 tdsdump_log(TDS_DBG_FUNC, "failed, no such hint\n");
650 break;
651 default:
652 tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED bcp option: %u\n", option);
653 break;
654 }
655 return FAIL;
656 }
657
658 /**
659 * \ingroup dblib_bcp
660 * \brief Override bcp_bind() by pointing to a different host variable.
661 *
662 * \param dbproc contains all information needed by db-lib to manage communications with the server.
663 * \param colptr The pointer, the address of your variable.
664 * \param table_column The 1-based column ordinal in the table.
665 * \remarks Use between calls to bcp_sendrow(). After calling bcp_colptr(),
666 * subsequent calls to bcp_sendrow() will bind to the new address.
667 * \return SUCCEED or FAIL.
668 * \sa bcp_bind(), bcp_collen(), bcp_sendrow()
669 */
670 RETCODE
bcp_colptr(DBPROCESS * dbproc,BYTE * colptr,int table_column)671 bcp_colptr(DBPROCESS * dbproc, BYTE * colptr, int table_column)
672 {
673 TDSCOLUMN *curcol;
674
675 tdsdump_log(TDS_DBG_FUNC, "bcp_colptr(%p, %p, %d)\n", dbproc, colptr, table_column);
676 CHECK_CONN(FAIL);
677 CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);
678 CHECK_PARAMETER(dbproc->bcpinfo->bindinfo, SYBEBCPI, FAIL);
679 /* colptr can be NULL */
680
681 if (dbproc->bcpinfo->direction != DB_IN) {
682 dbperror(dbproc, SYBEBCPN, 0);
683 return FAIL;
684 }
685 if (table_column <= 0 || table_column > dbproc->bcpinfo->bindinfo->num_cols) {
686 dbperror(dbproc, SYBEBCPN, 0);
687 return FAIL;
688 }
689
690 curcol = dbproc->bcpinfo->bindinfo->columns[table_column - 1];
691 curcol->column_varaddr = (TDS_CHAR *)colptr;
692
693 return SUCCEED;
694 }
695
696
697 /**
698 * \ingroup dblib_bcp
699 * \brief See if BCP_SETL() was used to set the LOGINREC for BCP work.
700 *
701 * \param login Address of the LOGINREC variable to be passed to dbopen().
702 *
703 * \return TRUE or FALSE.
704 * \sa BCP_SETL(), bcp_init(), dblogin(), dbopen()
705 */
706 DBBOOL
bcp_getl(LOGINREC * login)707 bcp_getl(LOGINREC * login)
708 {
709 TDSLOGIN *tdsl = login->tds_login;
710
711 tdsdump_log(TDS_DBG_FUNC, "bcp_getl(%p)\n", login);
712
713 return (tdsl->bulk_copy);
714 }
715
716 /**
717 * Convert column for output (usually to a file)
718 * Conversion is slightly different from input as:
719 * - date is formatted differently;
720 * - you have to set properly numeric while on input the column metadata are
721 * used;
722 * - we need to make sure buffer is always at least a minimum bytes.
723 */
724 static int
_bcp_convert_out(DBPROCESS * dbproc,TDSCOLUMN * curcol,BCP_HOSTCOLINFO * hostcol,TDS_UCHAR ** p_data,const char * bcpdatefmt)725 _bcp_convert_out(DBPROCESS * dbproc, TDSCOLUMN *curcol, BCP_HOSTCOLINFO *hostcol, TDS_UCHAR **p_data, const char *bcpdatefmt)
726 {
727 BYTE *src;
728 int srclen;
729 int buflen;
730 int srctype = tds_get_conversion_type(curcol->column_type, curcol->column_size);
731
732 src = curcol->column_data;
733 if (is_blob_col(curcol))
734 src = (BYTE *) ((TDSBLOB *) src)->textvalue;
735
736 srclen = curcol->column_cur_size;
737
738 /*
739 * if we are converting datetime to string, need to override any
740 * date time formats already established
741 */
742 if (is_datetime_type(srctype) && is_ascii_type(hostcol->datatype)) {
743 TDSDATEREC when;
744
745 tds_datecrack(srctype, src, &when);
746 buflen = (int)tds_strftime((TDS_CHAR *)(*p_data), 256,
747 bcpdatefmt, &when, 3);
748 } else if (srclen == 0 && is_variable_type(curcol->column_type)
749 && is_ascii_type(hostcol->datatype)) {
750 /*
751 * An empty string is denoted in the output file by a single ASCII NUL
752 * byte that we request by specifying a destination length of -1. (Not
753 * to be confused with a database NULL, which is denoted in the output
754 * file with an empty string!)
755 */
756 (*p_data)[0] = 0;
757 buflen = 1;
758 } else if (is_numeric_type(hostcol->datatype)) {
759 TDS_NUMERIC *num = (TDS_NUMERIC *) (*p_data);
760 if (is_numeric_type(srctype)) {
761 TDS_NUMERIC *nsrc = (TDS_NUMERIC *) src;
762 num->precision = nsrc->precision;
763 num->scale = nsrc->scale;
764 } else {
765 num->precision = 18;
766 num->scale = 0;
767 }
768 buflen = tds_convert(dbproc->tds_socket->conn->tds_ctx, srctype, src, srclen, hostcol->datatype, (CONV_RESULT *) num);
769 if (buflen > 0)
770 buflen = tds_numeric_bytes_per_prec[num->precision] + 2;
771 } else if (!is_variable_type(hostcol->datatype)) {
772 buflen = tds_convert(dbproc->tds_socket->conn->tds_ctx, srctype, src, srclen, hostcol->datatype, (CONV_RESULT *) (*p_data));
773 } else {
774 CONV_RESULT cr;
775
776 /*
777 * For null columns, the above work to determine the output buffer size is moot,
778 * because bcpcol->data_size is zero, so dbconvert() won't write anything,
779 * and returns zero.
780 */
781 buflen = tds_convert(dbproc->tds_socket->conn->tds_ctx, srctype, src, srclen, hostcol->datatype, (CONV_RESULT *) &cr);
782 if (buflen < 0)
783 return buflen;
784
785 if (buflen >= 256) {
786 free(*p_data);
787 *p_data = (TDS_UCHAR *) cr.c;
788 } else {
789 memcpy(*p_data, cr.c, buflen);
790 free(cr.c);
791 }
792
793 /*
794 * Special case: When outputting database varchar data
795 * (either varchar or nullable char) conversion may have
796 * trimmed trailing blanks such that nothing is left.
797 * In this case we need to put a single blank to the output file.
798 */
799 if (is_char_type(curcol->column_type) && srclen > 0 && buflen == 0) {
800 strcpy ((char *) (*p_data), " ");
801 buflen = 1;
802 }
803 }
804 return buflen;
805 }
806
807 static int
bcp_cache_prefix_len(BCP_HOSTCOLINFO * hostcol,const TDSCOLUMN * curcol)808 bcp_cache_prefix_len(BCP_HOSTCOLINFO *hostcol, const TDSCOLUMN *curcol)
809 {
810 int plen;
811
812 if (is_blob_type(hostcol->datatype))
813 plen = 4;
814 else if (is_numeric_type(hostcol->datatype))
815 plen = 1;
816 else if (!is_fixed_type(hostcol->datatype))
817 plen = 2;
818 else if (curcol->column_nullable)
819 plen = 1;
820 else
821 plen = 0;
822 /* cache */
823 return hostcol->prefix_len = plen;
824 }
825
826 static RETCODE
bcp_write_prefix(FILE * hostfile,BCP_HOSTCOLINFO * hostcol,TDSCOLUMN * curcol,int buflen)827 bcp_write_prefix(FILE *hostfile, BCP_HOSTCOLINFO *hostcol, TDSCOLUMN *curcol, int buflen)
828 {
829 union {
830 TDS_TINYINT ti;
831 TDS_SMALLINT si;
832 TDS_INT li;
833 } u;
834 int plen;
835
836 /* compute prefix len if needed */
837 if ((plen = hostcol->prefix_len) == -1)
838 plen = bcp_cache_prefix_len(hostcol, curcol);
839
840 /* output prefix to file */
841 switch (plen) {
842 default:
843 return SUCCEED;
844 case 1:
845 u.ti = buflen;
846 break;
847 case 2:
848 u.si = buflen;
849 break;
850 case 4:
851 u.li = buflen;
852 break;
853 }
854 if (fwrite(&u, plen, 1, hostfile) == 1)
855 return SUCCEED;
856
857 return FAIL;
858 }
859
860 /**
861 * \ingroup dblib_bcp_internal
862 * \brief
863 *
864 *
865 * \param dbproc contains all information needed by db-lib to manage communications with the server.
866 * \param rows_copied
867 *
868 * \return SUCCEED or FAIL.
869 * \sa BCP_SETL(), bcp_batch(), bcp_bind(), bcp_colfmt(), bcp_colfmt_ps(), bcp_collen(), bcp_colptr(), bcp_columns(), bcp_control(), bcp_done(), bcp_exec(), bcp_getl(), bcp_init(), bcp_moretext(), bcp_options(), bcp_readfmt(), bcp_sendrow()
870 */
871 static RETCODE
_bcp_exec_out(DBPROCESS * dbproc,DBINT * rows_copied)872 _bcp_exec_out(DBPROCESS * dbproc, DBINT * rows_copied)
873 {
874 FILE *hostfile = NULL;
875 TDS_UCHAR *data = NULL;
876 int i;
877
878 TDSSOCKET *tds;
879 TDSRESULTINFO *resinfo;
880 TDSCOLUMN *curcol = NULL;
881 BCP_HOSTCOLINFO *hostcol;
882 int buflen;
883
884 TDS_INT result_type;
885
886 int row_of_query;
887 int rows_written;
888 const char *bcpdatefmt;
889 TDSRET tdsret;
890
891 tdsdump_log(TDS_DBG_FUNC, "_bcp_exec_out(%p, %p)\n", dbproc, rows_copied);
892 assert(dbproc);
893 assert(rows_copied);
894
895 tds = dbproc->tds_socket;
896 assert(tds);
897
898 bcpdatefmt = getenv("FREEBCP_DATEFMT");
899 if (!bcpdatefmt)
900 bcpdatefmt = "%Y-%m-%d %H:%M:%S.%z";
901
902 if (dbproc->bcpinfo->direction == DB_QUERYOUT ) {
903 if (TDS_FAILED(tds_submit_query(tds, tds_dstr_cstr(&dbproc->bcpinfo->tablename))))
904 return FAIL;
905 } else {
906 /* TODO quote if needed */
907 if (TDS_FAILED(tds_submit_queryf(tds, "select * from %s", tds_dstr_cstr(&dbproc->bcpinfo->tablename))))
908 return FAIL;
909 }
910
911 tdsret = tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS);
912 if (TDS_FAILED(tdsret))
913 return FAIL;
914
915 if (!tds->res_info) {
916 /* TODO flush/cancel to keep consistent state */
917 return FAIL;
918 }
919
920 resinfo = tds->res_info;
921
922 row_of_query = 0;
923 rows_written = 0;
924
925 /* allocate at least 256 bytes */
926 /* allocate data for buffer conversion */
927 data = tds_new(TDS_UCHAR, 256);
928 if (!data) {
929 dbperror(dbproc, SYBEMEM, errno);
930 goto Cleanup;
931 }
932
933 /*
934 * TODO above we allocate many buffer just to convert and store
935 * to file.. avoid all that passages...
936 */
937
938 if (!(hostfile = fopen(dbproc->hostfileinfo->hostfile, "w"))) {
939 dbperror(dbproc, SYBEBCUO, errno);
940 goto Cleanup;
941 }
942
943 /* fetch a row of data from the server */
944
945 while (tds_process_tokens(tds, &result_type, NULL, TDS_STOPAT_ROWFMT|TDS_RETURN_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE)
946 == TDS_SUCCESS) {
947
948 if (result_type != TDS_ROW_RESULT && result_type != TDS_COMPUTE_RESULT)
949 break;
950
951 row_of_query++;
952
953 /* skip rows outside of the firstrow/lastrow range, if specified */
954 if (dbproc->hostfileinfo->firstrow > row_of_query ||
955 row_of_query > MAX(dbproc->hostfileinfo->lastrow, 0x7FFFFFFF))
956 continue;
957
958 /* Go through the hostfile columns, finding those that relate to database columns. */
959 for (i = 0; i < dbproc->hostfileinfo->host_colcount; i++) {
960 hostcol = dbproc->hostfileinfo->host_columns[i];
961 if (hostcol->tab_colnum < 1 || hostcol->tab_colnum > resinfo->num_cols)
962 continue;
963
964 curcol = resinfo->columns[hostcol->tab_colnum - 1];
965
966 if (curcol->column_cur_size < 0) {
967 buflen = 0;
968 } else {
969 buflen = _bcp_convert_out(dbproc, curcol, hostcol, &data, bcpdatefmt);
970 }
971 if (buflen < 0) {
972 _dblib_convert_err(dbproc, buflen);
973 goto Cleanup;
974 }
975
976 /* The prefix */
977 if (bcp_write_prefix(hostfile, hostcol, curcol, buflen) != SUCCEED)
978 goto write_error;
979
980 /* The data */
981 if (hostcol->column_len != -1) {
982 buflen = buflen > hostcol->column_len ? hostcol->column_len : buflen;
983 }
984
985 if (buflen > 0) {
986 if (fwrite(data, buflen, 1, hostfile) != 1)
987 goto write_error;
988 }
989
990 /* The terminator */
991 if (hostcol->terminator && hostcol->term_len > 0) {
992 if (fwrite(hostcol->terminator, hostcol->term_len, 1, hostfile) != 1)
993 goto write_error;
994 }
995 }
996 rows_written++;
997 }
998 if (fclose(hostfile) != 0) {
999 dbperror(dbproc, SYBEBCUC, errno);
1000 goto Cleanup;
1001 }
1002 hostfile = NULL;
1003
1004 if (row_of_query + 1 < dbproc->hostfileinfo->firstrow) {
1005 /*
1006 * The table which bulk-copy is attempting to
1007 * copy to a host-file is shorter than the
1008 * number of rows which bulk-copy was instructed to skip.
1009 */
1010 /* TODO reset TDSSOCKET state */
1011 dbperror(dbproc, SYBETTS, 0);
1012 goto Cleanup;
1013 }
1014
1015 *rows_copied = rows_written;
1016 free(data);
1017 return SUCCEED;
1018
1019 write_error:
1020 dbperror(dbproc, SYBEBCWE, errno);
1021
1022 Cleanup:
1023 if (hostfile)
1024 fclose(hostfile);
1025 free(data);
1026 return FAIL;
1027 }
1028
1029 static STATUS
_bcp_check_eof(DBPROCESS * dbproc,FILE * file,int icol)1030 _bcp_check_eof(DBPROCESS * dbproc, FILE *file, int icol)
1031 {
1032 int errnum = errno;
1033
1034 tdsdump_log(TDS_DBG_FUNC, "_bcp_check_eof(%p, %p, %d)\n", dbproc, file, icol);
1035 assert(dbproc);
1036 assert(file);
1037
1038 if (feof(file)) {
1039 if (icol == 0) {
1040 tdsdump_log(TDS_DBG_FUNC, "Normal end-of-file reached while loading bcp data file.\n");
1041 return NO_MORE_ROWS;
1042 }
1043 dbperror(dbproc, SYBEBEOF, errnum);
1044 return FAIL;
1045 }
1046 dbperror(dbproc, SYBEBCRE, errnum);
1047 return FAIL;
1048 }
1049
1050 /**
1051 * Convert column for input to a table
1052 */
1053 static TDSRET
_bcp_convert_in(DBPROCESS * dbproc,TDS_SERVER_TYPE srctype,const TDS_CHAR * src,TDS_UINT srclen,TDS_SERVER_TYPE desttype,BCPCOLDATA * coldata)1054 _bcp_convert_in(DBPROCESS *dbproc, TDS_SERVER_TYPE srctype, const TDS_CHAR *src, TDS_UINT srclen,
1055 TDS_SERVER_TYPE desttype, BCPCOLDATA *coldata)
1056 {
1057 int variable = 1;
1058 CONV_RESULT cr, *p_cr;
1059 TDS_INT len;
1060
1061 coldata->is_null = false;
1062
1063 if (!is_variable_type(desttype)) {
1064 variable = 0;
1065 p_cr = (CONV_RESULT *) coldata->data;
1066 } else {
1067 p_cr = &cr;
1068 }
1069
1070 len = tds_convert(dbproc->tds_socket->conn->tds_ctx, srctype, src, srclen, desttype, p_cr);
1071 if (len < 0) {
1072 _dblib_convert_err(dbproc, len);
1073 return TDS_FAIL;
1074 }
1075
1076 coldata->datalen = len;
1077 if (variable) {
1078 free(coldata->data);
1079 coldata->data = (TDS_UCHAR *) cr.c;
1080 }
1081 return TDS_SUCCESS;
1082 }
1083
1084 static void
rtrim_bcpcol(TDSCOLUMN * bcpcol)1085 rtrim_bcpcol(TDSCOLUMN *bcpcol)
1086 {
1087 /* trim trailing blanks from character data */
1088 if (is_ascii_type(bcpcol->on_server.column_type)) {
1089 /* A single NUL byte indicates an empty string. */
1090 if (bcpcol->bcp_column_data->datalen == 1
1091 && bcpcol->bcp_column_data->data[0] == '\0') {
1092 bcpcol->bcp_column_data->datalen = 0;
1093 return;
1094 }
1095 bcpcol->bcp_column_data->datalen = rtrim((char *) bcpcol->bcp_column_data->data,
1096 bcpcol->bcp_column_data->datalen);
1097 return;
1098 }
1099
1100 /* unicode part */
1101 if (is_unicode_type(bcpcol->on_server.column_type)) {
1102 uint16_t *data, space;
1103
1104 if (!bcpcol->char_conv || bcpcol->char_conv->to.charset.min_bytes_per_char != 2)
1105 return;
1106
1107 data = (uint16_t *) bcpcol->bcp_column_data->data;
1108 /* A single NUL byte indicates an empty string. */
1109 if (bcpcol->bcp_column_data->datalen == 2 && data[0] == 0) {
1110 bcpcol->bcp_column_data->datalen = 0;
1111 return;
1112 }
1113 switch (bcpcol->char_conv->to.charset.canonic) {
1114 case TDS_CHARSET_UTF_16BE:
1115 case TDS_CHARSET_UCS_2BE:
1116 TDS_PUT_A2BE(&space, 0x20);
1117 break;
1118 case TDS_CHARSET_UTF_16LE:
1119 case TDS_CHARSET_UCS_2LE:
1120 TDS_PUT_A2LE(&space, 0x20);
1121 break;
1122 default:
1123 return;
1124 }
1125 bcpcol->bcp_column_data->datalen = rtrim_u16(data, bcpcol->bcp_column_data->datalen, space);
1126 }
1127 }
1128
1129 /**
1130 * \ingroup dblib_bcp_internal
1131 * \brief
1132 *
1133 * \param dbproc contains all information needed by db-lib to manage communications with the server.
1134 * \param hostfile
1135 * \param row_error
1136 *
1137 * \return MORE_ROWS, NO_MORE_ROWS, or FAIL.
1138 * \sa BCP_SETL(), bcp_batch(), bcp_bind(), bcp_colfmt(), bcp_colfmt_ps(), bcp_collen(), bcp_colptr(), bcp_columns(), bcp_control(), bcp_done(), bcp_exec(), bcp_getl(), bcp_init(), bcp_moretext(), bcp_options(), bcp_readfmt(), bcp_sendrow()
1139 */
1140 static STATUS
_bcp_read_hostfile(DBPROCESS * dbproc,FILE * hostfile,int * row_error,bool skip)1141 _bcp_read_hostfile(DBPROCESS * dbproc, FILE * hostfile, int *row_error, bool skip)
1142 {
1143 int i;
1144
1145 tdsdump_log(TDS_DBG_FUNC, "_bcp_read_hostfile(%p, %p, %p, %d)\n", dbproc, hostfile, row_error, skip);
1146 assert(dbproc);
1147 assert(hostfile);
1148 assert(row_error);
1149
1150 /* for each host file column defined by calls to bcp_colfmt */
1151
1152 for (i = 0; i < dbproc->hostfileinfo->host_colcount; i++) {
1153 TDSCOLUMN *bcpcol = NULL;
1154 BCP_HOSTCOLINFO *hostcol;
1155 TDS_CHAR *coldata;
1156 int collen = 0;
1157 bool data_is_null = false;
1158 offset_type col_start;
1159
1160 tdsdump_log(TDS_DBG_FUNC, "parsing host column %d\n", i + 1);
1161 hostcol = dbproc->hostfileinfo->host_columns[i];
1162
1163 hostcol->column_error = 0;
1164
1165 /*
1166 * If this host file column contains table data,
1167 * find the right element in the table/column list.
1168 */
1169 if (hostcol->tab_colnum > 0) {
1170 if (hostcol->tab_colnum > dbproc->bcpinfo->bindinfo->num_cols) {
1171 tdsdump_log(TDS_DBG_FUNC, "error: file wider than table: %d/%d\n",
1172 i+1, dbproc->bcpinfo->bindinfo->num_cols);
1173 dbperror(dbproc, SYBEBEOF, 0);
1174 return FAIL;
1175 }
1176 tdsdump_log(TDS_DBG_FUNC, "host column %d uses bcpcol %d (%p)\n",
1177 i+1, hostcol->tab_colnum, bcpcol);
1178 bcpcol = dbproc->bcpinfo->bindinfo->columns[hostcol->tab_colnum - 1];
1179 assert(bcpcol != NULL);
1180 }
1181
1182 /* detect prefix len */
1183 if (bcpcol && hostcol->prefix_len == -1)
1184 bcp_cache_prefix_len(hostcol, bcpcol);
1185
1186 /* a prefix length, if extant, specifies how many bytes to read */
1187 if (hostcol->prefix_len > 0) {
1188 union {
1189 TDS_TINYINT ti;
1190 TDS_SMALLINT si;
1191 TDS_INT li;
1192 } u;
1193
1194 switch (hostcol->prefix_len) {
1195 case 1:
1196 if (fread(&u.ti, 1, 1, hostfile) != 1)
1197 return _bcp_check_eof(dbproc, hostfile, i);
1198 collen = u.ti ? u.ti : -1;
1199 break;
1200 case 2:
1201 if (fread(&u.si, 2, 1, hostfile) != 1)
1202 return _bcp_check_eof(dbproc, hostfile, i);
1203 collen = u.si;
1204 break;
1205 case 4:
1206 if (fread(&u.li, 4, 1, hostfile) != 1)
1207 return _bcp_check_eof(dbproc, hostfile, i);
1208 collen = u.li;
1209 break;
1210 default:
1211 /* FIXME return error, remember that prefix_len can be 3 */
1212 assert(hostcol->prefix_len <= 4);
1213 break;
1214 }
1215
1216 /* TODO test all NULL types */
1217 /* TODO for < -1 error */
1218 if (collen <= -1) {
1219 data_is_null = true;
1220 collen = 0;
1221 }
1222 }
1223
1224 /* if (Max) column length specified take that into consideration. (Meaning what, exactly?) */
1225
1226 if (!data_is_null && hostcol->column_len >= 0) {
1227 if (hostcol->column_len == 0)
1228 data_is_null = true;
1229 else if (collen)
1230 collen = (hostcol->column_len < collen) ? hostcol->column_len : collen;
1231 else
1232 collen = hostcol->column_len;
1233 }
1234
1235 tdsdump_log(TDS_DBG_FUNC, "prefix_len = %d collen = %d \n", hostcol->prefix_len, collen);
1236
1237 /* Fixed Length data - this overrides anything else specified */
1238
1239 if (is_fixed_type(hostcol->datatype))
1240 collen = tds_get_size_by_type(hostcol->datatype);
1241
1242 col_start = ftello(hostfile);
1243
1244 /*
1245 * The data file either contains prefixes stating the length, or is delimited.
1246 * If delimited, we "measure" the field by looking for the terminator, then read it,
1247 * and set collen to the field's post-iconv size.
1248 */
1249 if (hostcol->term_len > 0) { /* delimited data file */
1250 size_t col_bytes;
1251 TDSRET conv_res;
1252
1253 /*
1254 * Read and convert the data
1255 */
1256 coldata = NULL;
1257 conv_res = tds_bcp_fread(dbproc->tds_socket, bcpcol ? bcpcol->char_conv : NULL, hostfile,
1258 (const char *) hostcol->terminator, hostcol->term_len, &coldata, &col_bytes);
1259
1260 if (TDS_FAILED(conv_res)) {
1261 tdsdump_log(TDS_DBG_FUNC, "col %d: error converting %ld bytes!\n",
1262 (i+1), (long) collen);
1263 *row_error = TRUE;
1264 free(coldata);
1265 dbperror(dbproc, SYBEBCOR, 0);
1266 return FAIL;
1267 }
1268
1269 if (conv_res == TDS_NO_MORE_RESULTS) {
1270 free(coldata);
1271 return _bcp_check_eof(dbproc, hostfile, i);
1272 }
1273
1274 if (col_bytes > 0x7fffffffl) {
1275 free(coldata);
1276 *row_error = TRUE;
1277 tdsdump_log(TDS_DBG_FUNC, "data from file is too large!\n");
1278 dbperror(dbproc, SYBEBCOR, 0);
1279 return FAIL;
1280 }
1281
1282 collen = (int)col_bytes;
1283 if (collen == 0)
1284 data_is_null = true;
1285
1286 /*
1287 * TODO:
1288 * Dates are a problem. In theory, we should be able to read non-English dates, which
1289 * would contain non-ASCII characters. One might suppose we should convert date
1290 * strings to ISO-8859-1 (or another canonical form) here, because tds_convert() can't be
1291 * expected to deal with encodings. But instead date strings are read verbatim and
1292 * passed to tds_convert() without even waving to iconv(). For English dates, this works,
1293 * because English dates expressed as UTF-8 strings are indistinguishable from the ASCII.
1294 */
1295 } else { /* unterminated field */
1296
1297 coldata = tds_new(TDS_CHAR, 1 + collen);
1298 if (coldata == NULL) {
1299 *row_error = TRUE;
1300 dbperror(dbproc, SYBEMEM, errno);
1301 return FAIL;
1302 }
1303
1304 coldata[collen] = 0;
1305 if (collen) {
1306 /*
1307 * Read and convert the data
1308 * TODO: Call tds_bcp_fread() instead of fread(3).
1309 * The columns should each have their iconv cd set, and noncharacter data
1310 * should have -1 as the iconv cd, causing tds_bcp_fread() to not attempt
1311 * any conversion. We do not need a datatype switch here to decide what to do.
1312 * As of 0.62, this *should* actually work. All that remains is to change the
1313 * call and test it.
1314 */
1315 tdsdump_log(TDS_DBG_FUNC, "Reading %d bytes from hostfile.\n", collen);
1316 if (fread(coldata, collen, 1, hostfile) != 1) {
1317 free(coldata);
1318 return _bcp_check_eof(dbproc, hostfile, i);
1319 }
1320 }
1321 }
1322
1323 /*
1324 * At this point, however the field was read, however big it was, its address is coldata and its size is collen.
1325 */
1326 tdsdump_log(TDS_DBG_FUNC, "Data read from hostfile: collen is now %d, data_is_null is %d\n", collen, data_is_null);
1327 if (!skip && bcpcol) {
1328 if (data_is_null) {
1329 bcpcol->bcp_column_data->is_null = true;
1330 bcpcol->bcp_column_data->datalen = 0;
1331 } else {
1332 TDSRET rc;
1333 TDS_SERVER_TYPE desttype;
1334
1335 desttype = tds_get_conversion_type(bcpcol->column_type, bcpcol->column_size);
1336
1337 rc = _bcp_convert_in(dbproc, hostcol->datatype, (const TDS_CHAR*) coldata, collen,
1338 desttype, bcpcol->bcp_column_data);
1339 if (TDS_FAILED(rc)) {
1340 hostcol->column_error = HOST_COL_CONV_ERROR;
1341 *row_error = 1;
1342 tdsdump_log(TDS_DBG_FUNC,
1343 "_bcp_read_hostfile failed to convert %d bytes at offset 0x%" PRIx64 " in the data file.\n",
1344 collen, (TDS_INT8) col_start);
1345 }
1346
1347 rtrim_bcpcol(bcpcol);
1348 }
1349 #if USING_SYBEBCNN
1350 if (!hostcol->column_error) {
1351 if (bcpcol->bcp_column_data->datalen <= 0) { /* Are we trying to insert a NULL ? */
1352 if (!bcpcol->column_nullable) {
1353 /* too bad if the column is not nullable */
1354 hostcol->column_error = HOST_COL_NULL_ERROR;
1355 *row_error = 1;
1356 dbperror(dbproc, SYBEBCNN, 0);
1357 }
1358 }
1359 }
1360 #endif
1361 }
1362 free(coldata);
1363 }
1364 return MORE_ROWS;
1365 }
1366
1367 /**
1368 * \ingroup dblib_bcp
1369 * \brief Write data in host variables to the table.
1370 *
1371 * \param dbproc contains all information needed by db-lib to manage communications with the server.
1372 *
1373 * \remarks Call bcp_bind() first to describe the variables to be used.
1374 * Use bcp_batch() to commit sets of rows.
1375 * After sending the last row call bcp_done().
1376 * \return SUCCEED or FAIL.
1377 * \sa bcp_batch(), bcp_bind(), bcp_colfmt(), bcp_collen(), bcp_colptr(), bcp_columns(),
1378 * bcp_control(), bcp_done(), bcp_exec(), bcp_init(), bcp_moretext(), bcp_options()
1379 */
1380 RETCODE
bcp_sendrow(DBPROCESS * dbproc)1381 bcp_sendrow(DBPROCESS * dbproc)
1382 {
1383 TDSSOCKET *tds;
1384
1385 tdsdump_log(TDS_DBG_FUNC, "bcp_sendrow(%p)\n", dbproc);
1386 CHECK_CONN(FAIL);
1387 CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);
1388
1389 tds = dbproc->tds_socket;
1390
1391 if (dbproc->bcpinfo->direction != DB_IN) {
1392 dbperror(dbproc, SYBEBCPN, 0);
1393 return FAIL;
1394 }
1395
1396 if (dbproc->hostfileinfo != NULL) {
1397 dbperror(dbproc, SYBEBCPB, 0);
1398 return FAIL;
1399 }
1400
1401 /*
1402 * The first time sendrow is called after bcp_init,
1403 * there is a certain amount of initialisation to be done.
1404 */
1405 if (dbproc->bcpinfo->xfer_init == 0) {
1406
1407 /* The start_copy function retrieves details of the table's columns */
1408 if (TDS_FAILED(tds_bcp_start_copy_in(tds, dbproc->bcpinfo))) {
1409 dbperror(dbproc, SYBEBULKINSERT, 0);
1410 return FAIL;
1411 }
1412
1413 dbproc->bcpinfo->xfer_init = 1;
1414
1415 }
1416
1417 dbproc->bcpinfo->parent = dbproc;
1418 return TDS_FAILED(tds_bcp_send_record(dbproc->tds_socket, dbproc->bcpinfo,
1419 _bcp_get_col_data, _bcp_null_error, 0)) ? FAIL : SUCCEED;
1420 }
1421
1422
1423 /**
1424 * \ingroup dblib_bcp_internal
1425 * \brief
1426 *
1427 * \param dbproc contains all information needed by db-lib to manage communications with the server.
1428 * \param rows_copied
1429 *
1430 * \return SUCCEED or FAIL.
1431 * \sa BCP_SETL(), bcp_batch(), bcp_bind(), bcp_colfmt(), bcp_colfmt_ps(), bcp_collen(), bcp_colptr(), bcp_columns(), bcp_control(), bcp_done(), bcp_exec(), bcp_getl(), bcp_init(), bcp_moretext(), bcp_options(), bcp_readfmt(), bcp_sendrow()
1432 */
1433 static RETCODE
_bcp_exec_in(DBPROCESS * dbproc,DBINT * rows_copied)1434 _bcp_exec_in(DBPROCESS * dbproc, DBINT * rows_copied)
1435 {
1436 FILE *hostfile, *errfile = NULL;
1437 TDSSOCKET *tds = dbproc->tds_socket;
1438 BCP_HOSTCOLINFO *hostcol;
1439 STATUS ret;
1440
1441 int i, row_of_hostfile, rows_written_so_far;
1442 int row_error, row_error_count;
1443 offset_type row_start, row_end;
1444 offset_type error_row_size;
1445 const size_t chunk_size = 0x20000u;
1446
1447 tdsdump_log(TDS_DBG_FUNC, "_bcp_exec_in(%p, %p)\n", dbproc, rows_copied);
1448 assert(dbproc);
1449 assert(rows_copied);
1450
1451 *rows_copied = 0;
1452
1453 if (!(hostfile = fopen(dbproc->hostfileinfo->hostfile, "r"))) {
1454 dbperror(dbproc, SYBEBCUO, 0);
1455 return FAIL;
1456 }
1457
1458 if (TDS_FAILED(tds_bcp_start_copy_in(tds, dbproc->bcpinfo))) {
1459 fclose(hostfile);
1460 return FAIL;
1461 }
1462
1463 row_of_hostfile = 0;
1464 rows_written_so_far = 0;
1465
1466 row_error_count = 0;
1467 dbproc->bcpinfo->parent = dbproc;
1468
1469 for (;;) {
1470 bool skip;
1471
1472 row_start = ftello(hostfile);
1473 row_error = 0;
1474
1475 row_of_hostfile++;
1476
1477 if (row_of_hostfile > MAX(dbproc->hostfileinfo->lastrow, 0x7FFFFFFF))
1478 break;
1479
1480 skip = dbproc->hostfileinfo->firstrow > row_of_hostfile;
1481 ret = _bcp_read_hostfile(dbproc, hostfile, &row_error, skip);
1482 if (ret != MORE_ROWS)
1483 break;
1484
1485 if (row_error) {
1486 int count;
1487
1488 if (errfile == NULL && dbproc->hostfileinfo->errorfile) {
1489 if (!(errfile = fopen(dbproc->hostfileinfo->errorfile, "w"))) {
1490 fclose(hostfile);
1491 dbperror(dbproc, SYBEBUOE, 0);
1492 return FAIL;
1493 }
1494 }
1495
1496 if (errfile != NULL) {
1497 char *row_in_error = NULL;
1498
1499 for (i = 0; i < dbproc->hostfileinfo->host_colcount; i++) {
1500 hostcol = dbproc->hostfileinfo->host_columns[i];
1501 if (hostcol->column_error == HOST_COL_CONV_ERROR) {
1502 count = fprintf(errfile,
1503 "#@ data conversion error on host data file Row %d Column %d\n",
1504 row_of_hostfile, i + 1);
1505 if( count < 0 ) {
1506 dbperror(dbproc, SYBEBWEF, errno);
1507 }
1508 } else if (hostcol->column_error == HOST_COL_NULL_ERROR) {
1509 count = fprintf(errfile, "#@ Attempt to bulk-copy a NULL value into Server column"
1510 " which does not accept NULL values. Row %d, Column %d\n",
1511 row_of_hostfile, i + 1);
1512 if( count < 0 ) {
1513 dbperror(dbproc, SYBEBWEF, errno);
1514 }
1515
1516 }
1517 }
1518
1519 row_end = ftello(hostfile);
1520
1521 /* error data can be very long so split in chunks */
1522 error_row_size = row_end - row_start;
1523 fseeko(hostfile, row_start, SEEK_SET);
1524
1525 while (error_row_size > 0) {
1526 size_t chunk = error_row_size > chunk_size ? chunk_size : (size_t) error_row_size;
1527
1528 if (!row_in_error) {
1529 if ((row_in_error = tds_new(char, chunk)) == NULL) {
1530 dbperror(dbproc, SYBEMEM, errno);
1531 }
1532 }
1533
1534 if (fread(row_in_error, chunk, 1, hostfile) != 1) {
1535 printf("BILL fread failed after fseek\n");
1536 }
1537 count = (int)fwrite(row_in_error, chunk, 1, errfile);
1538 if( (size_t)count < chunk ) {
1539 dbperror(dbproc, SYBEBWEF, errno);
1540 }
1541 error_row_size -= chunk;
1542 }
1543 free(row_in_error);
1544
1545 fseeko(hostfile, row_end, SEEK_SET);
1546 count = fprintf(errfile, "\n");
1547 if( count < 0 ) {
1548 dbperror(dbproc, SYBEBWEF, errno);
1549 }
1550 }
1551 row_error_count++;
1552 if (row_error_count >= dbproc->hostfileinfo->maxerrs)
1553 break;
1554 continue;
1555 }
1556
1557 if (skip)
1558 continue;
1559
1560 if (TDS_SUCCEED(tds_bcp_send_record(dbproc->tds_socket, dbproc->bcpinfo,
1561 _bcp_no_get_col_data, _bcp_null_error, 0))) {
1562
1563 rows_written_so_far++;
1564
1565 if (dbproc->hostfileinfo->batch > 0 && rows_written_so_far == dbproc->hostfileinfo->batch) {
1566 if (TDS_FAILED(tds_bcp_done(tds, &rows_written_so_far))) {
1567 if (errfile)
1568 fclose(errfile);
1569 fclose(hostfile);
1570 return FAIL;
1571 }
1572
1573 *rows_copied += rows_written_so_far;
1574 rows_written_so_far = 0;
1575
1576 dbperror(dbproc, SYBEBBCI, 0); /* batch copied to server */
1577
1578 tds_bcp_start(tds, dbproc->bcpinfo);
1579 }
1580 }
1581 }
1582
1583 if (row_error_count == 0 && row_of_hostfile < dbproc->hostfileinfo->firstrow) {
1584 /* "The BCP hostfile '%1!' contains only %2! rows. */
1585 dbperror(dbproc, SYBEBCSA, 0, dbproc->hostfileinfo->hostfile, row_of_hostfile);
1586 }
1587
1588 if (errfile && 0 != fclose(errfile) ) {
1589 dbperror(dbproc, SYBEBUCE, 0);
1590 }
1591
1592 if (fclose(hostfile) != 0) {
1593 dbperror(dbproc, SYBEBCUC, 0);
1594 ret = FAIL;
1595 }
1596
1597 tds_bcp_done(tds, &rows_written_so_far);
1598 *rows_copied += rows_written_so_far;
1599
1600 return ret == NO_MORE_ROWS? SUCCEED : FAIL; /* (ret is returned from _bcp_read_hostfile) */
1601 }
1602
1603 /**
1604 * \ingroup dblib_bcp
1605 * \brief Write a datafile to a table.
1606 *
1607 *
1608 * \param dbproc contains all information needed by db-lib to manage communications with the server.
1609 * \param rows_copied bcp_exec will write the count of rows successfully written to this address.
1610 * If \a rows_copied is NULL, it will be ignored by db-lib.
1611 *
1612 * \return SUCCEED or FAIL.
1613 * \sa bcp_batch(), bcp_bind(), bcp_colfmt(), bcp_collen(), bcp_colptr(), bcp_columns(),
1614 * bcp_control(), bcp_done(), bcp_init(), bcp_sendrow()
1615 */
1616 RETCODE
bcp_exec(DBPROCESS * dbproc,DBINT * rows_copied)1617 bcp_exec(DBPROCESS * dbproc, DBINT *rows_copied)
1618 {
1619 DBINT dummy_copied;
1620 RETCODE ret = FAIL;
1621
1622 tdsdump_log(TDS_DBG_FUNC, "bcp_exec(%p, %p)\n", dbproc, rows_copied);
1623 CHECK_CONN(FAIL);
1624 CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);
1625 CHECK_PARAMETER(dbproc->hostfileinfo, SYBEBCVH, FAIL);
1626
1627 if (rows_copied == NULL) /* NULL means we should ignore it */
1628 rows_copied = &dummy_copied;
1629
1630 if (dbproc->bcpinfo->direction == DB_OUT || dbproc->bcpinfo->direction == DB_QUERYOUT) {
1631 ret = _bcp_exec_out(dbproc, rows_copied);
1632 } else if (dbproc->bcpinfo->direction == DB_IN) {
1633 ret = _bcp_exec_in(dbproc, rows_copied);
1634 }
1635 _bcp_free_storage(dbproc);
1636
1637 return ret;
1638 }
1639
1640 /**
1641 * \ingroup dblib_bcp_internal
1642 * \brief
1643 *
1644 * \param buffer
1645 * \param size
1646 * \param f
1647 *
1648 * \return SUCCEED or FAIL.
1649 * \sa BCP_SETL(), bcp_batch(), bcp_bind(), bcp_colfmt(), bcp_colfmt_ps(), bcp_collen(), bcp_colptr(), bcp_columns(), bcp_control(), bcp_done(), bcp_exec(), bcp_getl(), bcp_init(), bcp_moretext(), bcp_options(), bcp_readfmt(), bcp_sendrow()
1650 */
1651 static char *
_bcp_fgets(char * buffer,int size,FILE * f)1652 _bcp_fgets(char *buffer, int size, FILE *f)
1653 {
1654 char *p = fgets(buffer, size, f);
1655 if (p == NULL)
1656 return p;
1657
1658 /* discard newline */
1659 p = strchr(buffer, 0) - 1;
1660 if (p >= buffer && *p == '\n')
1661 *p = 0;
1662 return buffer;
1663 }
1664
1665 /**
1666 * \ingroup dblib_bcp
1667 * \brief Read a format definition file.
1668 *
1669 * \param dbproc contains all information needed by db-lib to manage communications with the server.
1670 * \param filename Name that will be passed to fopen(3).
1671 *
1672 * \remarks Reads a format file and calls bcp_columns() and bcp_colfmt() as needed.
1673 *
1674 * \return SUCCEED or FAIL.
1675 * \sa bcp_colfmt(), bcp_colfmt_ps(), bcp_columns(), bcp_writefmt()
1676 */
1677 RETCODE
bcp_readfmt(DBPROCESS * dbproc,const char filename[])1678 bcp_readfmt(DBPROCESS * dbproc, const char filename[])
1679 {
1680 BCP_HOSTCOLINFO hostcol[1];
1681 FILE *ffile;
1682 char buffer[1024];
1683 float lf_version = 0.0;
1684 int li_numcols = 0;
1685 int colinfo_count = 0;
1686
1687 tdsdump_log(TDS_DBG_FUNC, "bcp_readfmt(%p, %s)\n", dbproc, filename? filename:"NULL");
1688 CHECK_CONN(FAIL);
1689 CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);
1690 CHECK_NULP(filename, "bcp_readfmt", 2, FAIL);
1691
1692 memset(hostcol, 0, sizeof(hostcol));
1693
1694 if ((ffile = fopen(filename, "r")) == NULL) {
1695 dbperror(dbproc, SYBEBUOF, 0);
1696 goto Cleanup;
1697 }
1698
1699 if ((_bcp_fgets(buffer, sizeof(buffer), ffile)) != NULL) {
1700 lf_version = (float)atof(buffer);
1701 } else if (ferror(ffile)) {
1702 dbperror(dbproc, SYBEBRFF, errno);
1703 goto Cleanup;
1704 }
1705
1706 if ((_bcp_fgets(buffer, sizeof(buffer), ffile)) != NULL) {
1707 li_numcols = atoi(buffer);
1708 } else if (ferror(ffile)) {
1709 dbperror(dbproc, SYBEBRFF, errno);
1710 goto Cleanup;
1711 }
1712
1713 if (li_numcols <= 0)
1714 goto Cleanup;
1715
1716 if (bcp_columns(dbproc, li_numcols) == FAIL)
1717 goto Cleanup;
1718
1719 do {
1720 memset(hostcol, 0, sizeof(hostcol));
1721
1722 if (_bcp_fgets(buffer, sizeof(buffer), ffile) == NULL)
1723 goto Cleanup;
1724
1725 if (!_bcp_readfmt_colinfo(dbproc, buffer, hostcol))
1726 goto Cleanup;
1727
1728 if (bcp_colfmt(dbproc, hostcol->host_column, hostcol->datatype,
1729 hostcol->prefix_len, hostcol->column_len,
1730 hostcol->terminator, hostcol->term_len, hostcol->tab_colnum) == FAIL) {
1731 goto Cleanup;
1732 }
1733
1734 TDS_ZERO_FREE(hostcol->terminator);
1735 } while (++colinfo_count < li_numcols);
1736
1737 if (ferror(ffile)) {
1738 dbperror(dbproc, SYBEBRFF, errno);
1739 goto Cleanup;
1740 }
1741
1742 if (fclose(ffile) != 0) {
1743 dbperror(dbproc, SYBEBUCF, 0);
1744 /* even if failure is returned ffile is no more valid */
1745 ffile = NULL;
1746 goto Cleanup;
1747 }
1748 ffile = NULL;
1749
1750 if (colinfo_count != li_numcols)
1751 goto Cleanup;
1752
1753 return SUCCEED;
1754
1755 Cleanup:
1756 TDS_ZERO_FREE(hostcol->terminator);
1757 _bcp_free_columns(dbproc);
1758 if (ffile)
1759 fclose(ffile);
1760 return FAIL;
1761 }
1762
1763 /**
1764 * \ingroup dblib_bcp_internal
1765 * \brief
1766 *
1767 * \param dbproc contains all information needed by db-lib to manage communications with the server.
1768 * \param buf
1769 * \param ci
1770 *
1771 * \return SUCCEED or FAIL.
1772 * \sa BCP_SETL(), bcp_batch(), bcp_bind(), bcp_colfmt(), bcp_colfmt_ps(), bcp_collen(), bcp_colptr(), bcp_columns(), bcp_control(), bcp_done(), bcp_exec(), bcp_getl(), bcp_init(), bcp_moretext(), bcp_options(), bcp_readfmt(), bcp_sendrow()
1773 */
1774 static int
_bcp_readfmt_colinfo(DBPROCESS * dbproc,char * buf,BCP_HOSTCOLINFO * ci)1775 _bcp_readfmt_colinfo(DBPROCESS * dbproc, char *buf, BCP_HOSTCOLINFO * ci)
1776 {
1777 char *tok;
1778 int whichcol;
1779 char term[30];
1780 int i;
1781 char *lasts;
1782
1783 enum nextcol
1784 {
1785 HOST_COLUMN,
1786 DATATYPE,
1787 PREFIX_LEN,
1788 COLUMN_LEN,
1789 TERMINATOR,
1790 TAB_COLNUM,
1791 NO_MORE_COLS
1792 };
1793
1794 assert(dbproc);
1795 assert(buf);
1796 assert(ci);
1797 tdsdump_log(TDS_DBG_FUNC, "_bcp_readfmt_colinfo(%p, %s, %p)\n", dbproc, buf, ci);
1798
1799 tok = strtok_r(buf, " \t", &lasts);
1800 whichcol = HOST_COLUMN;
1801
1802 /* TODO use a better way to get an int atoi is very error prone */
1803 while (tok != NULL && whichcol != NO_MORE_COLS) {
1804 switch (whichcol) {
1805
1806 case HOST_COLUMN:
1807 ci->host_column = atoi(tok);
1808
1809 if (ci->host_column < 1) {
1810 dbperror(dbproc, SYBEBIHC, 0);
1811 return (FALSE);
1812 }
1813
1814 whichcol = DATATYPE;
1815 break;
1816
1817 case DATATYPE:
1818 if (strcmp(tok, "SYBCHAR") == 0)
1819 ci->datatype = SYBCHAR;
1820 else if (strcmp(tok, "SYBTEXT") == 0)
1821 ci->datatype = SYBTEXT;
1822 else if (strcmp(tok, "SYBBINARY") == 0)
1823 ci->datatype = SYBBINARY;
1824 else if (strcmp(tok, "SYBIMAGE") == 0)
1825 ci->datatype = SYBIMAGE;
1826 else if (strcmp(tok, "SYBINT1") == 0)
1827 ci->datatype = SYBINT1;
1828 else if (strcmp(tok, "SYBINT2") == 0)
1829 ci->datatype = SYBINT2;
1830 else if (strcmp(tok, "SYBINT4") == 0)
1831 ci->datatype = SYBINT4;
1832 else if (strcmp(tok, "SYBINT8") == 0)
1833 ci->datatype = SYBINT8;
1834 else if (strcmp(tok, "SYBFLT8") == 0)
1835 ci->datatype = SYBFLT8;
1836 else if (strcmp(tok, "SYBREAL") == 0)
1837 ci->datatype = SYBREAL;
1838 else if (strcmp(tok, "SYBBIT") == 0)
1839 ci->datatype = SYBBIT;
1840 else if (strcmp(tok, "SYBNUMERIC") == 0)
1841 ci->datatype = SYBNUMERIC;
1842 else if (strcmp(tok, "SYBDECIMAL") == 0)
1843 ci->datatype = SYBDECIMAL;
1844 else if (strcmp(tok, "SYBMONEY") == 0)
1845 ci->datatype = SYBMONEY;
1846 else if (strcmp(tok, "SYBMONEY4") == 0)
1847 ci->datatype = SYBMONEY4;
1848 else if (strcmp(tok, "SYBDATETIME") == 0)
1849 ci->datatype = SYBDATETIME;
1850 else if (strcmp(tok, "SYBDATETIME4") == 0)
1851 ci->datatype = SYBDATETIME4;
1852 /* TODO SQL* for MS
1853 SQLNCHAR SQLBIGINT SQLTINYINT SQLSMALLINT
1854 SQLUNIQUEID SQLVARIANT SQLUDT */
1855 else {
1856 dbperror(dbproc, SYBEBUDF, 0);
1857 return (FALSE);
1858 }
1859
1860 whichcol = PREFIX_LEN;
1861 break;
1862
1863 case PREFIX_LEN:
1864 ci->prefix_len = atoi(tok);
1865 whichcol = COLUMN_LEN;
1866 break;
1867 case COLUMN_LEN:
1868 ci->column_len = atoi(tok);
1869 whichcol = TERMINATOR;
1870 break;
1871 case TERMINATOR:
1872
1873 if (*tok++ != '\"')
1874 return (FALSE);
1875
1876 for (i = 0; *tok != '\"' && i < sizeof(term); i++) {
1877 if (*tok == '\\') {
1878 tok++;
1879 switch (*tok) {
1880 case 't':
1881 term[i] = '\t';
1882 break;
1883 case 'n':
1884 term[i] = '\n';
1885 break;
1886 case 'r':
1887 term[i] = '\r';
1888 break;
1889 case '\\':
1890 term[i] = '\\';
1891 break;
1892 case '0':
1893 term[i] = '\0';
1894 break;
1895 default:
1896 return (FALSE);
1897 }
1898 tok++;
1899 } else
1900 term[i] = *tok++;
1901 }
1902
1903 if (*tok != '\"')
1904 return (FALSE);
1905
1906 ci->term_len = i;
1907 TDS_ZERO_FREE(ci->terminator);
1908 if (i > 0) {
1909 if ((ci->terminator = tds_new(BYTE, i)) == NULL) {
1910 dbperror(dbproc, SYBEMEM, errno);
1911 return FALSE;
1912 }
1913 memcpy(ci->terminator, term, i);
1914 }
1915
1916 whichcol = TAB_COLNUM;
1917 break;
1918
1919 case TAB_COLNUM:
1920 ci->tab_colnum = atoi(tok);
1921 whichcol = NO_MORE_COLS;
1922 break;
1923
1924 }
1925 tok = strtok_r(NULL, " \t", &lasts);
1926 }
1927 if (whichcol == NO_MORE_COLS)
1928 return (TRUE);
1929 else
1930 return (FALSE);
1931 }
1932
1933 #if defined(DBLIB_UNIMPLEMENTED)
1934 /**
1935 * \ingroup dblib_bcp
1936 * \brief Write a format definition file. Not Implemented.
1937 *
1938 * \param dbproc contains all information needed by db-lib to manage communications with the server.
1939 * \param filename Name that would be passed to fopen(3).
1940 *
1941 * \remarks Reads a format file and calls bcp_columns() and bcp_colfmt() as needed.
1942 * \a FreeTDS includes freebcp, a utility to copy data to or from a host file.
1943 *
1944 * \todo For completeness, \a freebcp ought to be able to create format files, but that functionality
1945 * is currently lacking, as is bcp_writefmt().
1946 * \todo See the vendors' documentation for the format of these files.
1947 *
1948 * \return SUCCEED or FAIL.
1949 * \sa bcp_colfmt(), bcp_colfmt_ps(), bcp_columns(), bcp_readfmt()
1950 */
1951 RETCODE
bcp_writefmt(DBPROCESS * dbproc,const char filename[])1952 bcp_writefmt(DBPROCESS * dbproc, const char filename[])
1953 {
1954 tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED: bcp_writefmt(%p, %s)\n", dbproc, filename? filename:"NULL");
1955 CHECK_CONN(FAIL);
1956 CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);
1957 CHECK_NULP(filename, "bcp_writefmt", 2, FAIL);
1958
1959 #if 0
1960 dbperror(dbproc, SYBEBUFF, errno); /* bcp: Unable to create format file */
1961 dbperror(dbproc, SYBEBWFF, errno); /* I/O error while writing bcp format file */
1962 #endif
1963
1964 return FAIL;
1965 }
1966
1967 /**
1968 * \ingroup dblib_bcp
1969 * \brief Write some text or image data to the server. Not implemented, sadly.
1970 *
1971 * \param dbproc contains all information needed by db-lib to manage communications with the server.
1972 * \param size How much to write, in bytes.
1973 * \param text Address of the data to be written.
1974 * \remarks For a SYBTEXT or SYBIMAGE column, bcp_bind() can be called with
1975 * a NULL varaddr parameter. If it is, bcp_sendrow() will return control
1976 * to the application after the non-text data have been sent. The application then calls
1977 * bcp_moretext() -- usually in a loop -- to send the text data in manageable chunks.
1978 * \todo implement bcp_moretext().
1979 * \return SUCCEED or FAIL.
1980 * \sa bcp_bind(), bcp_sendrow(), dbmoretext(), dbwritetext()
1981 */
1982 RETCODE
bcp_moretext(DBPROCESS * dbproc,DBINT size,BYTE * text)1983 bcp_moretext(DBPROCESS * dbproc, DBINT size, BYTE * text)
1984 {
1985 tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED: bcp_moretext(%p, %d, %p)\n", dbproc, size, text);
1986 CHECK_CONN(FAIL);
1987 CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);
1988 CHECK_NULP(text, "bcp_moretext", 3, FAIL);
1989
1990 #if 0
1991 dbperror(dbproc, SYBEBCMTXT, 0);
1992 /* bcp_moretext may be used only when there is at least one text or image column in the server table */
1993 dbperror(dbproc, SYBEBTMT, 0);
1994 /* Attempt to send too much text data via the bcp_moretext call */
1995 #endif
1996 return FAIL;
1997 }
1998 #endif
1999
2000 /**
2001 * \ingroup dblib_bcp
2002 * \brief Commit a set of rows to the table.
2003 *
2004 * \param dbproc contains all information needed by db-lib to manage communications with the server.
2005 * \remarks If not called, bcp_done() will cause the rows to be saved.
2006 * \return Count of rows saved, or -1 on error.
2007 * \sa bcp_bind(), bcp_done(), bcp_sendrow()
2008 */
2009 DBINT
bcp_batch(DBPROCESS * dbproc)2010 bcp_batch(DBPROCESS * dbproc)
2011 {
2012 int rows_copied = 0;
2013
2014 tdsdump_log(TDS_DBG_FUNC, "bcp_batch(%p)\n", dbproc);
2015 CHECK_CONN(-1);
2016 CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, -1);
2017
2018 if (TDS_FAILED(tds_bcp_done(dbproc->tds_socket, &rows_copied)))
2019 return -1;
2020
2021 tds_bcp_start(dbproc->tds_socket, dbproc->bcpinfo);
2022
2023 return rows_copied;
2024 }
2025
2026 /**
2027 * \ingroup dblib_bcp
2028 * \brief Conclude the transfer of data from program variables.
2029 *
2030 * \param dbproc contains all information needed by db-lib to manage communications with the server.
2031 * \remarks Do not overlook this function. According to Sybase, failure to call bcp_done()
2032 * "will result in unpredictable errors".
2033 * \return As with bcp_batch(), the count of rows saved, or -1 on error.
2034 * \sa bcp_batch(), bcp_bind(), bcp_moretext(), bcp_sendrow()
2035 */
2036 DBINT
bcp_done(DBPROCESS * dbproc)2037 bcp_done(DBPROCESS * dbproc)
2038 {
2039 int rows_copied;
2040
2041 tdsdump_log(TDS_DBG_FUNC, "bcp_done(%p)\n", dbproc);
2042 CHECK_CONN(-1);
2043
2044 if (!(dbproc->bcpinfo))
2045 return -1;
2046
2047 if (TDS_FAILED(tds_bcp_done(dbproc->tds_socket, &rows_copied)))
2048 return -1;
2049
2050 _bcp_free_storage(dbproc);
2051
2052 return rows_copied;
2053 }
2054
2055 /**
2056 * \ingroup dblib_bcp
2057 * \brief Bind a program host variable to a database column
2058 *
2059 * \param dbproc contains all information needed by db-lib to manage communications with the server.
2060 * \param varaddr address of host variable
2061 * \param prefixlen length of any prefix found at the beginning of \a varaddr, in bytes.
2062 Use zero for fixed-length datatypes.
2063 * \param varlen bytes of data in \a varaddr. Zero for NULL, -1 for fixed-length datatypes.
2064 * \param terminator byte sequence that marks the end of the data in \a varaddr
2065 * \param termlen length of \a terminator
2066 * \param vartype datatype of the host variable
2067 * \param table_column Nth column, starting at 1, in the table.
2068 *
2069 * \remarks The order of operation is:
2070 * - bcp_init() with \a hfile == NULL and \a direction == DB_IN.
2071 * - bcp_bind(), once per column you want to write to
2072 * - bcp_batch(), optionally, to commit a set of rows
2073 * - bcp_done()
2074 * \return SUCCEED or FAIL.
2075 * \sa bcp_batch(), bcp_colfmt(), bcp_collen(), bcp_colptr(), bcp_columns(), bcp_control(),
2076 * bcp_done(), bcp_exec(), bcp_moretext(), bcp_sendrow()
2077 */
2078 RETCODE
bcp_bind(DBPROCESS * dbproc,BYTE * varaddr,int prefixlen,DBINT varlen,BYTE * terminator,int termlen,int db_vartype,int table_column)2079 bcp_bind(DBPROCESS * dbproc, BYTE * varaddr, int prefixlen, DBINT varlen,
2080 BYTE * terminator, int termlen, int db_vartype, int table_column)
2081 {
2082 TDS_SERVER_TYPE vartype;
2083 TDSCOLUMN *colinfo;
2084
2085 tdsdump_log(TDS_DBG_FUNC, "bcp_bind(%p, %p, %d, %d -- %p, %d, %s, %d)\n",
2086 dbproc, varaddr, prefixlen, varlen,
2087 terminator, termlen, dbprtype(db_vartype), table_column);
2088 CHECK_CONN(FAIL);
2089 CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);
2090 DBPERROR_RETURN(db_vartype != 0 && !is_tds_type_valid(db_vartype), SYBEUDTY);
2091 vartype = (TDS_SERVER_TYPE) db_vartype;
2092
2093 if (dbproc->hostfileinfo != NULL) {
2094 dbperror(dbproc, SYBEBCPB, 0);
2095 return FAIL;
2096 }
2097
2098 if (dbproc->bcpinfo->direction != DB_IN) {
2099 dbperror(dbproc, SYBEBCPN, 0);
2100 return FAIL;
2101 }
2102
2103 if (varlen < -1) {
2104 dbperror(dbproc, SYBEBCVLEN, 0);
2105 return FAIL;
2106 }
2107
2108 if (prefixlen != 0 && prefixlen != 1 && prefixlen != 2 && prefixlen != 4) {
2109 dbperror(dbproc, SYBEBCBPREF, 0);
2110 return FAIL;
2111 }
2112
2113 if (prefixlen == 0 && varlen == -1 && termlen == -1 && !is_fixed_type(vartype)) {
2114 tdsdump_log(TDS_DBG_FUNC, "bcp_bind(): non-fixed type %d requires prefix or terminator\n", vartype);
2115 return FAIL;
2116 }
2117
2118 if (is_fixed_type(vartype) && (varlen != -1 && varlen != 0)) {
2119 dbperror(dbproc, SYBEBCIT, 0);
2120 return FAIL;
2121 }
2122
2123 if (table_column <= 0 || table_column > dbproc->bcpinfo->bindinfo->num_cols) {
2124 dbperror(dbproc, SYBECNOR, 0);
2125 return FAIL;
2126 }
2127
2128 if (varaddr == NULL && (prefixlen != 0 || termlen != 0)) {
2129 dbperror(dbproc, SYBEBCBNPR, 0);
2130 return FAIL;
2131 }
2132
2133 colinfo = dbproc->bcpinfo->bindinfo->columns[table_column - 1];
2134
2135 /* If varaddr is NULL and varlen greater than 0, the table column type must be SYBTEXT or SYBIMAGE
2136 and the program variable type must be SYBTEXT, SYBCHAR, SYBIMAGE or SYBBINARY */
2137 if (varaddr == NULL && varlen > 0) {
2138 int fOK = (colinfo->column_type == SYBTEXT || colinfo->column_type == SYBIMAGE) &&
2139 (vartype == SYBTEXT || vartype == SYBCHAR || vartype == SYBIMAGE || vartype == SYBBINARY );
2140 if( !fOK ) {
2141 dbperror(dbproc, SYBEBCBNTYP, 0);
2142 tdsdump_log(TDS_DBG_FUNC, "bcp_bind: SYBEBCBNTYP: column=%d and vartype=%d (should fail?)\n",
2143 colinfo->column_type, vartype);
2144 /* return FAIL; */
2145 }
2146 }
2147
2148 colinfo->column_varaddr = (char *)varaddr;
2149 colinfo->column_bindtype = vartype;
2150 colinfo->column_bindlen = varlen;
2151 colinfo->bcp_prefix_len = prefixlen;
2152
2153 TDS_ZERO_FREE(colinfo->bcp_terminator);
2154 colinfo->bcp_term_len = 0;
2155 if (termlen > 0) {
2156 if ((colinfo->bcp_terminator = tds_new(TDS_CHAR, termlen)) == NULL) {
2157 dbperror(dbproc, SYBEMEM, errno);
2158 return FAIL;
2159 }
2160 memcpy(colinfo->bcp_terminator, terminator, termlen);
2161 colinfo->bcp_term_len = termlen;
2162 }
2163
2164 return SUCCEED;
2165 }
2166
2167 static void
_bcp_null_error(TDSBCPINFO * bcpinfo,int index,int offset)2168 _bcp_null_error(TDSBCPINFO *bcpinfo, int index, int offset)
2169 {
2170 DBPROCESS *dbproc = (DBPROCESS *) bcpinfo->parent;
2171 dbperror(dbproc, SYBEBCNN, 0);
2172 }
2173
2174 /**
2175 * \ingroup dblib_bcp_internal
2176 * \brief For a bcp in from program variables, get the data from the host variable
2177 *
2178 * \param dbproc contains all information needed by db-lib to manage communications with the server.
2179 * \param bindcol
2180 *
2181 * \return TDS_SUCCESS or TDS_FAIL.
2182 * \sa _bcp_add_fixed_columns, _bcp_add_variable_columns, _bcp_send_bcp_record
2183 */
2184 static TDSRET
_bcp_get_col_data(TDSBCPINFO * bcpinfo,TDSCOLUMN * bindcol,int offset)2185 _bcp_get_col_data(TDSBCPINFO *bcpinfo, TDSCOLUMN *bindcol, int offset)
2186 {
2187 TDS_SERVER_TYPE coltype, desttype;
2188 int collen;
2189 int bytes_read;
2190 BYTE *dataptr;
2191 DBPROCESS *dbproc = (DBPROCESS *) bcpinfo->parent;
2192 TDSRET rc;
2193
2194 tdsdump_log(TDS_DBG_FUNC, "_bcp_get_col_data(%p, %p)\n", bcpinfo, bindcol);
2195 CHECK_CONN(TDS_FAIL);
2196 CHECK_NULP(bindcol, "_bcp_get_col_data", 2, TDS_FAIL);
2197
2198 dataptr = (BYTE *) bindcol->column_varaddr;
2199
2200 collen = 0;
2201
2202 /* If a prefix length specified, read the correct amount of data. */
2203
2204 if (bindcol->bcp_prefix_len > 0) {
2205
2206 switch (bindcol->bcp_prefix_len) {
2207 case 1:
2208 collen = TDS_GET_UA1(dataptr);
2209 dataptr += 1;
2210 break;
2211 case 2:
2212 collen = (TDS_SMALLINT) TDS_GET_UA2(dataptr);
2213 dataptr += 2;
2214 break;
2215 case 4:
2216 collen = (TDS_INT) TDS_GET_UA4(dataptr);
2217 dataptr += 4;
2218 break;
2219 }
2220 if (collen <= 0)
2221 goto null_data;
2222 }
2223
2224 /* if (Max) column length specified take that into consideration. */
2225
2226 if (bindcol->column_bindlen >= 0) {
2227 if (bindcol->column_bindlen == 0)
2228 goto null_data;
2229 if (collen)
2230 collen = (int) ((bindcol->column_bindlen < (TDS_UINT)collen) ? bindcol->column_bindlen : (TDS_UINT)collen);
2231 else
2232 collen = (int) bindcol->column_bindlen;
2233 }
2234
2235 desttype = tds_get_conversion_type(bindcol->column_type, bindcol->column_size);
2236
2237 coltype = bindcol->column_bindtype == 0 ? desttype : (TDS_SERVER_TYPE) bindcol->column_bindtype;
2238
2239 /* Fixed Length data - this overrides anything else specified */
2240 if (is_fixed_type(coltype))
2241 collen = tds_get_size_by_type(coltype);
2242
2243 /* read the data, finally */
2244
2245 if (bindcol->bcp_term_len > 0) { /* terminated field */
2246 bytes_read = _bcp_get_term_var(dataptr, (BYTE *)bindcol->bcp_terminator, bindcol->bcp_term_len);
2247
2248 if (collen <= 0 || bytes_read < collen)
2249 collen = bytes_read;
2250
2251 if (collen == 0)
2252 goto null_data;
2253 }
2254
2255 if (collen < 0)
2256 collen = (int) strlen((char *) dataptr);
2257
2258 rc = _bcp_convert_in(dbproc, coltype, (const TDS_CHAR*) dataptr, collen,
2259 desttype, bindcol->bcp_column_data);
2260 if (TDS_FAILED(rc))
2261 return rc;
2262
2263 return TDS_SUCCESS;
2264
2265 null_data:
2266 bindcol->bcp_column_data->datalen = 0;
2267 bindcol->bcp_column_data->is_null = true;
2268 return TDS_SUCCESS;
2269 }
2270
2271 /**
2272 * Function to read data from file. I this case is empty as data
2273 * are already on bcp_column_data
2274 */
2275 static TDSRET
_bcp_no_get_col_data(TDSBCPINFO * bcpinfo,TDSCOLUMN * bindcol,int offset)2276 _bcp_no_get_col_data(TDSBCPINFO *bcpinfo, TDSCOLUMN *bindcol, int offset)
2277 {
2278 return TDS_SUCCESS;
2279 }
2280
2281 /**
2282 * Get the data for bcp-in from program variables, where the program data
2283 * have been identified as character terminated,
2284 * This is a low-level, internal function. Call it correctly.
2285 */
2286 /**
2287 * \ingroup dblib_bcp_internal
2288 * \brief
2289 *
2290 * \param pdata
2291 * \param term
2292 * \param term_len
2293 *
2294 * \return data length.
2295 */
2296 static int
_bcp_get_term_var(const BYTE * pdata,const BYTE * term,int term_len)2297 _bcp_get_term_var(const BYTE * pdata, const BYTE * term, int term_len)
2298 {
2299 int bufpos;
2300
2301 assert(term_len > 0);
2302
2303 /* if bufpos becomes negative, we probably failed to find the terminator */
2304 for (bufpos = 0; bufpos >= 0 && memcmp(pdata, term, term_len) != 0; pdata++) {
2305 bufpos++;
2306 }
2307
2308 assert(bufpos >= 0);
2309 return bufpos;
2310 }
2311
2312 /**
2313 * \ingroup dblib_bcp_internal
2314 * \brief trim a string of trailing blanks
2315 *
2316 * Replaces spaces at the end of a string with NULs
2317 * \param str pointer to a character buffer (not null-terminated)
2318 * \param len size of the \a str in bytes
2319 *
2320 * \return modified length
2321 */
2322 static int
rtrim(char * str,int len)2323 rtrim(char *str, int len)
2324 {
2325 char *p = str + len - 1;
2326
2327 while (p > str && *p == ' ') {
2328 *p-- = '\0';
2329 }
2330 return (int)(1 + p - str);
2331 }
2332
2333 static int
rtrim_u16(uint16_t * str,int len,uint16_t space)2334 rtrim_u16(uint16_t *str, int len, uint16_t space)
2335 {
2336 uint16_t *p = str + len / 2 - 1;
2337
2338 while (p > str && *p == space) {
2339 *p-- = '\0';
2340 }
2341 return (int)(1 + p - str) * 2;
2342 }
2343
2344 /**
2345 * \ingroup dblib_bcp_internal
2346 * \brief
2347 *
2348 * \param dbproc contains all information needed by db-lib to manage communications with the server.
2349 */
2350 static void
_bcp_free_columns(DBPROCESS * dbproc)2351 _bcp_free_columns(DBPROCESS * dbproc)
2352 {
2353 int i;
2354
2355 tdsdump_log(TDS_DBG_FUNC, "_bcp_free_columns(%p)\n", dbproc);
2356 assert(dbproc && dbproc->hostfileinfo);
2357
2358 if (dbproc->hostfileinfo->host_columns) {
2359 for (i = 0; i < dbproc->hostfileinfo->host_colcount; i++) {
2360 TDS_ZERO_FREE(dbproc->hostfileinfo->host_columns[i]->terminator);
2361 TDS_ZERO_FREE(dbproc->hostfileinfo->host_columns[i]);
2362 }
2363 TDS_ZERO_FREE(dbproc->hostfileinfo->host_columns);
2364 dbproc->hostfileinfo->host_colcount = 0;
2365 }
2366 }
2367
2368 /**
2369 * \ingroup dblib_bcp_internal
2370 * \brief
2371 *
2372 * \param dbproc contains all information needed by db-lib to manage communications with the server.
2373 *
2374 * \sa bcp_done(), bcp_exec(), bcp_init()
2375 */
2376 static void
_bcp_free_storage(DBPROCESS * dbproc)2377 _bcp_free_storage(DBPROCESS * dbproc)
2378 {
2379 tdsdump_log(TDS_DBG_FUNC, "_bcp_free_storage(%p)\n", dbproc);
2380 assert(dbproc);
2381
2382 if (dbproc->hostfileinfo) {
2383 TDS_ZERO_FREE(dbproc->hostfileinfo->hostfile);
2384 TDS_ZERO_FREE(dbproc->hostfileinfo->errorfile);
2385 _bcp_free_columns(dbproc);
2386 TDS_ZERO_FREE(dbproc->hostfileinfo);
2387 }
2388
2389 tds_free_bcpinfo(dbproc->bcpinfo);
2390 dbproc->bcpinfo = NULL;
2391 }
2392
2393