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