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