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