NCBI C++ ToolKit
bulk.c
Go to the documentation of this file.

Go to the SVN repository for this file.

Go to the SVN repository for this file.

Go to the SVN repository for this file.

Go to the SVN repository for this file.

Go to the SVN repository for this file.

Go to the SVN repository for this file.

1 /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2  * Copyright (C) 2008-2010 Frediano Ziglio
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 
20 /**
21  * \file
22  * \brief Handle bulk copy
23  */
24 
25 #include <config.h>
26 
27 #if HAVE_STRING_H
28 #include <string.h>
29 #endif /* HAVE_STRING_H */
30 
31 #if HAVE_ERRNO_H
32 #include <errno.h>
33 #endif /* HAVE_ERRNO_H */
34 
35 #if HAVE_STDLIB_H
36 #include <stdlib.h>
37 #endif /* HAVE_STDLIB_H */
38 
39 #include <assert.h>
40 
41 #include <freetds/tds.h>
42 #include <freetds/checks.h>
43 #include <freetds/bytes.h>
44 #include <freetds/iconv.h>
45 #include <freetds/stream.h>
46 #include <freetds/string.h>
47 #include "replacements.h"
48 
49 /** \cond HIDDEN_SYMBOLS */
50 #ifndef MAX
51 #define MAX(a,b) ( (a) > (b) ? (a) : (b) )
52 #endif
53 
54 #ifndef MIN
55 #define MIN(a,b) ( (a) < (b) ? (a) : (b) )
56 #endif
57 /** \endcond */
58 
59 /**
60  * Holds clause buffer
61  */
62 typedef struct tds_pbcb
63 {
64  /** buffer */
65  char *pb;
66  /** buffer length */
67  unsigned int cb;
68  /** true is buffer came from malloc */
69  unsigned int from_malloc;
71 
74 static int tds_bcp_add_fixed_columns(TDSBCPINFO *bcpinfo, tds_bcp_get_col_data get_col_data, tds_bcp_null_error null_error, int offset, unsigned char * rowbuffer, int start);
75 static int tds_bcp_add_variable_columns(TDSBCPINFO *bcpinfo, tds_bcp_get_col_data get_col_data, tds_bcp_null_error null_error, int offset, TDS_UCHAR *rowbuffer, int start, int *pncols);
76 static void tds_bcp_row_free(TDSRESULTINFO* result, unsigned char *row);
77 static int tds_bcp_is_bound(TDSBCPINFO *bcpinfo, TDSCOLUMN *colinfo);
79 
80 /**
81  * Initialize BCP information.
82  * Query structure of the table to server.
83  * \tds
84  * \param bcpinfo BCP information to initialize. Structure should be allocate
85  * and table name and direction should be already set.
86  */
87 TDSRET
89 {
90  TDSRESULTINFO *resinfo;
91  TDSRESULTINFO *bindinfo = NULL;
92  TDSCOLUMN *curcol;
93  TDS_INT result_type;
94  int i;
95  TDSRET rc;
96  const char *fmt;
97 
98  /* FIXME don't leave state in processing state */
99 
100  /* TODO quote tablename if needed */
101  if (bcpinfo->direction != TDS_BCP_QUERYOUT)
102  fmt = "SET FMTONLY ON select * from %s SET FMTONLY OFF";
103  else
104  fmt = "SET FMTONLY ON %s SET FMTONLY OFF";
105 
106  if (TDS_FAILED(rc=tds_submit_queryf(tds, fmt, tds_dstr_cstr(&bcpinfo->tablename))))
107  /* TODO return an error ?? */
108  /* Attempt to use Bulk Copy with a non-existent Server table (might be why ...) */
109  return rc;
110 
111  /* TODO possibly stop at ROWFMT and copy before going to idle */
112  /* TODO check what happen if table is not present, cleanup on error */
113  while ((rc = tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS))
114  == TDS_SUCCESS)
115  continue;
116  if (TDS_FAILED(rc))
117  return rc;
118 
119  /* copy the results info from the TDS socket */
120  if (!tds->res_info)
121  return TDS_FAIL;
122 
123  resinfo = tds->res_info;
124  if ((bindinfo = tds_alloc_results(resinfo->num_cols)) == NULL) {
125  rc = TDS_FAIL;
126  goto cleanup;
127  }
128 
129  bindinfo->row_size = resinfo->row_size;
130 
131  /* Copy the column metadata */
132  rc = TDS_FAIL;
133  for (i = 0; i < bindinfo->num_cols; i++) {
134 
135  curcol = bindinfo->columns[i];
136 
137  /*
138  * TODO use memcpy ??
139  * curcol and resinfo->columns[i] are both TDSCOLUMN.
140  * Why not "curcol = resinfo->columns[i];"? Because the rest of TDSCOLUMN (below column_timestamp)
141  * isn't being used. Perhaps this "upper" part of TDSCOLUMN should be a substructure.
142  * Or, see if the "lower" part is unused (and zeroed out) at this point, and just do one assignment.
143  */
144  curcol->funcs = resinfo->columns[i]->funcs;
145  curcol->column_type = resinfo->columns[i]->column_type;
146  curcol->column_usertype = resinfo->columns[i]->column_usertype;
147  curcol->column_flags = resinfo->columns[i]->column_flags;
148  if (curcol->column_varint_size == 0)
149  curcol->column_cur_size = resinfo->columns[i]->column_cur_size;
150  else
151  curcol->column_cur_size = -1;
152  curcol->column_size = resinfo->columns[i]->column_size;
153  curcol->column_varint_size = resinfo->columns[i]->column_varint_size;
154  curcol->column_prec = resinfo->columns[i]->column_prec;
155  curcol->column_scale = resinfo->columns[i]->column_scale;
156  curcol->on_server.column_type = resinfo->columns[i]->on_server.column_type;
157  curcol->on_server.column_size = resinfo->columns[i]->on_server.column_size;
158  curcol->char_conv = resinfo->columns[i]->char_conv;
159  if (!tds_dstr_dup(&curcol->column_name, &resinfo->columns[i]->column_name))
160  goto cleanup;
161  if (!tds_dstr_dup(&curcol->table_column_name, &resinfo->columns[i]->table_column_name))
162  goto cleanup;
163  curcol->column_nullable = resinfo->columns[i]->column_nullable;
164  curcol->column_identity = resinfo->columns[i]->column_identity;
165  curcol->column_timestamp = resinfo->columns[i]->column_timestamp;
166 
167  memcpy(curcol->column_collation, resinfo->columns[i]->column_collation, 5);
168 
169  if (is_numeric_type(curcol->column_type)) {
171  ((TDS_NUMERIC *) curcol->bcp_column_data->data)->precision = curcol->column_prec;
172  ((TDS_NUMERIC *) curcol->bcp_column_data->data)->scale = curcol->column_scale;
173  } else if (bcpinfo->bind_count != 0 /* ctlib */
174  && is_blob_col(curcol)) {
176  } else {
177  curcol->bcp_column_data =
179  }
180  if (!curcol->bcp_column_data)
181  goto cleanup;
182  }
183 
184  if (!IS_TDS7_PLUS(tds->conn)) {
185  bindinfo->current_row = tds_new(unsigned char, bindinfo->row_size);
186  if (!bindinfo->current_row)
187  goto cleanup;
188  bindinfo->row_free = tds_bcp_row_free;
189  }
190 
191  if (bcpinfo->identity_insert_on) {
192 
193  rc = tds_submit_queryf(tds, "set identity_insert %s on", tds_dstr_cstr(&bcpinfo->tablename));
194  if (TDS_FAILED(rc))
195  goto cleanup;
196 
197  /* TODO use tds_process_simple_query */
198  while ((rc = tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS))
199  == TDS_SUCCESS) {
200  }
201  if (rc != TDS_NO_MORE_RESULTS)
202  goto cleanup;
203  }
204 
205  bcpinfo->bindinfo = bindinfo;
206  bcpinfo->bind_count = 0;
207  return TDS_SUCCESS;
208 
209 cleanup:
210  tds_free_results(bindinfo);
211  return rc;
212 }
213 
214 /**
215  * Help to build query to be sent to server.
216  * Append column declaration to the query.
217  * Only for TDS 7.0+.
218  * \tds
219  * \param[out] clause output string
220  * \param bcpcol column to append
221  * \param first true if column is the first
222  * \return TDS_SUCCESS or TDS_FAIL.
223  */
224 static TDSRET
226 {
227  char column_type[40];
228 
229  tdsdump_log(TDS_DBG_FUNC, "tds7_build_bulk_insert_stmt(%p, %p, %p, %d)\n", tds, clause, bcpcol, first);
230 
231  if (TDS_FAILED(tds_get_column_declaration(tds, bcpcol, column_type))) {
233  tdsdump_log(TDS_DBG_FUNC, "error: cannot build bulk insert statement. unrecognized server datatype %d\n",
234  bcpcol->on_server.column_type);
235  return TDS_FAIL;
236  }
237 
238  if (clause->cb < strlen(clause->pb)
240  + strlen(column_type)
241  + ((first) ? 2u : 4u)) {
242  char *temp = tds_new(char, 2 * clause->cb);
243 
244  if (!temp) {
245  tdserror(tds_get_ctx(tds), tds, TDSEMEM, errno);
246  return TDS_FAIL;
247  }
248  strcpy(temp, clause->pb);
249  if (clause->from_malloc)
250  free(clause->pb);
251  clause->from_malloc = 1;
252  clause->pb = temp;
253  clause->cb *= 2;
254  }
255 
256  if (!first)
257  strcat(clause->pb, ", ");
258 
259  tds_quote_id(tds, strchr(clause->pb, 0), tds_dstr_cstr(&bcpcol->column_name), tds_dstr_len(&bcpcol->column_name));
260  strcat(clause->pb, " ");
261  strcat(clause->pb, column_type);
262 
263  return TDS_SUCCESS;
264 }
265 
266 /**
267  * Prepare the query to be sent to server to request BCP information
268  * \tds
269  * \param bcpinfo BCP information
270  */
271 static TDSRET
273 {
274  char *query;
275 
276  if (IS_TDS7_PLUS(tds->conn)) {
277  int i, firstcol, erc;
278  char *hint;
279  TDSCOLUMN *bcpcol;
280  TDSPBCB colclause;
281  char clause_buffer[4096] = { 0 };
282 
283  colclause.pb = clause_buffer;
284  colclause.cb = sizeof(clause_buffer);
285  colclause.from_malloc = 0;
286 
287  /* TODO avoid asprintf, use always malloc-ed buffer */
288  firstcol = 1;
289 
290  for (i = 0; i < bcpinfo->bindinfo->num_cols; i++) {
291  bcpcol = bcpinfo->bindinfo->columns[i];
292 
293  if (bcpcol->column_timestamp
294  || !tds_bcp_is_bound(bcpinfo, bcpcol))
295  continue;
296  if (!bcpinfo->identity_insert_on && bcpcol->column_identity)
297  continue;
298  tds7_build_bulk_insert_stmt(tds, &colclause, bcpcol, firstcol);
299  firstcol = 0;
300  }
301 
302  if (bcpinfo->hint) {
303  if (asprintf(&hint, " with (%s)", bcpinfo->hint) < 0)
304  hint = NULL;
305  } else {
306  hint = strdup("");
307  }
308  if (!hint) {
309  if (colclause.from_malloc)
310  TDS_ZERO_FREE(colclause.pb);
311  return TDS_FAIL;
312  }
313 
314  erc = asprintf(&query, "insert bulk %s (%s)%s", tds_dstr_cstr(&bcpinfo->tablename), colclause.pb, hint);
315 
316  free(hint);
317  if (colclause.from_malloc)
318  TDS_ZERO_FREE(colclause.pb); /* just for good measure; not used beyond this point */
319 
320  if (erc < 0)
321  return TDS_FAIL;
322  } else {
323  /* NOTE: if we use "with nodescribe" for following inserts server do not send describe */
324  if (asprintf(&query, "insert bulk %s", tds_dstr_cstr(&bcpinfo->tablename)) < 0)
325  return TDS_FAIL;
326  }
327 
328  /* save the statement for later... */
329  bcpinfo->insert_stmt = query;
330 
331  return TDS_SUCCESS;
332 }
333 
334 /**
335  * Send one row of data to server
336  * \tds
337  * \param bcpinfo BCP information
338  * \param get_col_data function to call to retrieve data to be sent
339  * \param ignored function to call if we try to send NULL if not allowed (not used)
340  * \param offset passed to get_col_data and null_error to specify the row to get
341  * \return TDS_SUCCESS or TDS_FAIL.
342  */
343 TDSRET
345  tds_bcp_get_col_data get_col_data,
346  tds_bcp_null_error null_error, int offset)
347 {
348  TDSCOLUMN *bindcol;
349  int i, start_col = bcpinfo->next_col;
350  TDSRET rc;
351 
353  "tds_bcp_send_bcp_record(%p, %p, %p, %p, %d)\n",
354  tds, bcpinfo, get_col_data, null_error, offset);
355 
357  return TDS_FAIL;
358 
359  if (start_col > 0) {
360  bindcol = bcpinfo->bindinfo->columns[start_col - 1];
361  *bindcol->column_lenbind
362  = MIN((TDS_INT) bindcol->column_bindlen
363  - bcpinfo->text_sent,
364  *bindcol->column_lenbind);
365  tds_put_n(tds, bindcol->column_varaddr,
366  *bindcol->column_lenbind);
367  bcpinfo->text_sent += *bindcol->column_lenbind;
368  if ((TDS_UINT) bcpinfo->text_sent < bindcol->column_bindlen) {
369  return TDS_SUCCESS; /* That's all for now. */
370  } else if (!IS_TDS7_PLUS(tds->conn)) {
371  bcpinfo->blob_cols++;
372  }
373  bcpinfo->next_col = 0;
374  bcpinfo->text_sent = 0;
375  }
376 
377  if (IS_TDS7_PLUS(tds->conn)) {
378 
379  if (start_col == 0) {
380  tds_put_byte(tds, TDS_ROW_TOKEN); /* 0xd1 */
381  }
382  for (i = start_col; i < bcpinfo->bindinfo->num_cols; i++) {
383 
384  TDS_INT save_size;
385  unsigned char *save_data;
386  TDSBLOB blob;
387  int /* bool */ has_text = 0;
388  bindcol = bcpinfo->bindinfo->columns[i];
389 
390  /*
391  * Don't send the (meta)data for timestamp columns or
392  * identity columns unless indentity_insert is enabled.
393  */
394 
395  if ((!bcpinfo->identity_insert_on && bindcol->column_identity) ||
396  bindcol->column_timestamp ||
397  !tds_bcp_is_bound(bcpinfo, bindcol)) {
398  continue;
399  }
400 
401  rc = get_col_data(bcpinfo, bindcol, offset);
402  if (rc == TDS_FAIL) {
403  tdsdump_log(TDS_DBG_INFO1, "get_col_data (column %d) failed\n", i + 1);
404  goto cleanup;
405  } else if (rc != TDS_SUCCESS) { /* CS_BLK_HAS_TEXT? */
406  has_text = 1;
407  }
408  tdsdump_log(TDS_DBG_INFO1, "gotten column %d length %d null %d\n",
409  i + 1, bindcol->bcp_column_data->datalen, bindcol->bcp_column_data->is_null);
410 
411  save_size = bindcol->column_cur_size;
412  save_data = bindcol->column_data;
413  assert(bindcol->column_data == NULL);
414  if (bindcol->bcp_column_data->is_null) {
415  if ( !bindcol->column_nullable
416  && !is_nullable_type(bindcol->on_server
417  .column_type) ) {
418  return TDS_FAIL;
419  }
420  bindcol->column_cur_size = -1;
421  } else if (has_text) {
422  bindcol->column_cur_size
423  = bindcol->bcp_column_data->datalen;
424  } else if (is_blob_col(bindcol)) {
425  bindcol->column_cur_size = bindcol->bcp_column_data->datalen;
426  memset(&blob, 0, sizeof(blob));
427  blob.textvalue = (TDS_CHAR *) bindcol->bcp_column_data->data;
428  bindcol->column_data = (unsigned char *) &blob;
429  } else {
430  bindcol->column_cur_size = bindcol->bcp_column_data->datalen;
431  bindcol->column_data = bindcol->bcp_column_data->data;
432  }
433  rc = bindcol->funcs->put_data(tds, bindcol, 1);
434  bindcol->column_cur_size = save_size;
435  bindcol->column_data = save_data;
436 
437  if (TDS_FAILED(rc))
438  goto cleanup;
439  else if (has_text) {
440  bcpinfo->next_col = i + 1;
441  /* bcpinfo->text_sent = 0; */
442  break;
443  }
444  }
445  } /* IS_TDS7_PLUS */
446  else {
447  if (start_col == 0) {
448  int row_pos;
449  int row_sz_pos;
450  int var_cols_written = 0;
451  TDS_INT old_record_size = bcpinfo->bindinfo->row_size;
452  unsigned char *record = bcpinfo->bindinfo->current_row;
453 
454  memset(record, '\0', old_record_size); /* zero the rowbuffer */
455 
456  /*
457  * offset 0 = number of var columns
458  * offset 1 = row number. zeroed (datasever assigns)
459  */
460  row_pos = 2;
461 
462  rc = TDS_FAIL;
463  if ((row_pos = tds_bcp_add_fixed_columns(bcpinfo, get_col_data,
464  null_error, offset,
465  record, row_pos))
466  < 0)
467  goto cleanup;
468 
469  row_sz_pos = row_pos;
470 
471  /* potential variable columns to write */
472 
473  if ((row_pos = tds_bcp_add_variable_columns(bcpinfo,
474  get_col_data,
475  null_error, offset,
476  record, row_pos,
477  &var_cols_written))
478  < 0)
479  goto cleanup;
480 
481 
482  if (var_cols_written) {
483  TDS_PUT_UA2(&record[row_sz_pos], row_pos);
484  record[0] = var_cols_written;
485  }
486 
487  tdsdump_log(TDS_DBG_INFO1, "old_record_size = %d new size = %d \n", old_record_size, row_pos);
488 
489  tds_put_smallint(tds, row_pos);
490  tds_put_n(tds, record, row_pos);
491 
492  /* row is done, now handle any text/image data */
493 
494  bcpinfo->blob_cols = 0;
495  }
496 
497  for (i = start_col; i < bcpinfo->bindinfo->num_cols; i++) {
498  bindcol = bcpinfo->bindinfo->columns[i];
499  if (is_blob_type(bindcol->column_type)) {
500  /* Elide trailing NULLs */
501  if (bindcol->bcp_column_data->is_null) {
502  int j;
503  for (j = i + 1;
504  j < bcpinfo->bindinfo->num_cols;
505  ++j) {
506  TDSCOLUMN *bindcol2
507  = bcpinfo->bindinfo
508  ->columns[j];
509  if (is_blob_type(bindcol2
510  ->column_type)
511  && !(bindcol2
512  ->bcp_column_data
513  ->is_null)) {
514  break;
515  }
516  }
517  if (j == bcpinfo->bindinfo->num_cols) {
518  i = j;
519  break;
520  }
521  }
522 
523  rc = get_col_data(bcpinfo, bindcol, offset);
524  if (rc == TDS_FAIL)
525  goto cleanup;
526  /* unknown but zero */
527  tds_put_smallint(tds, 0);
529  (unsigned char)
530  bindcol->column_type);
531  tds_put_byte(tds, 0xff - bcpinfo->blob_cols);
532  /*
533  * offset of txptr we stashed during variable
534  * column processing
535  */
538  if (rc != TDS_SUCCESS) { /* CS_BLK_HAS_TEXT? */
539  bcpinfo->next_col = i + 1;
540  /* bcpinfo->text_sent = 0; */
541  break;
542  }
543  tds_put_n(tds, bindcol->bcp_column_data->data, bindcol->bcp_column_data->datalen);
544  bcpinfo->blob_cols++;
545 
546  }
547  }
548  }
549 
550  if (i == bcpinfo->bindinfo->num_cols) {
552  bcpinfo->next_col = 0;
553  }
554  return TDS_SUCCESS;
555 
556 cleanup:
558  return rc;
559 }
560 
561 /**
562  * Add fixed size columns to the row
563  * \param bcpinfo BCP information
564  * \param get_col_data function to call to retrieve data to be sent
565  * \param ignored function to call if we try to send NULL if not allowed (not used)
566  * \param offset passed to get_col_data and null_error to specify the row to get
567  * \param rowbuffer row buffer to write to
568  * \param start row buffer last end position
569  * \returns new row length or -1 on error.
570  */
571 static int
573  tds_bcp_get_col_data get_col_data,
574  tds_bcp_null_error null_error,
575  int offset, unsigned char * rowbuffer, int start)
576 {
577  TDS_NUMERIC *num;
578  int row_pos = start;
579  TDSCOLUMN *bcpcol;
580  int cpbytes;
581  int i, j;
582  int bitleft = 0, bitpos;
583 
584  assert(bcpinfo);
585  assert(rowbuffer);
586 
587  tdsdump_log(TDS_DBG_FUNC, "tds_bcp_add_fixed_columns(%p, %p, ignored, %d, %p, %d)\n", bcpinfo, get_col_data, offset, rowbuffer, start);
588 
589  for (i = 0; i < bcpinfo->bindinfo->num_cols; i++) {
590 
591  bcpcol = bcpinfo->bindinfo->columns[i];
592 
594  || bcpcol->column_nullable)
595  continue;
596 
597  tdsdump_log(TDS_DBG_FUNC, "tds_bcp_add_fixed_columns column %d is a fixed column\n", i + 1);
598 
599  if (TDS_FAILED(get_col_data(bcpinfo, bcpcol, offset))) {
600  tdsdump_log(TDS_DBG_INFO1, "get_col_data (column %d) failed\n", i + 1);
601  return -1;
602  }
603 
604  if (bcpcol->bcp_column_data->is_null && null_error) {
605  /* No value or default value available and NULL not allowed. */
606  null_error(bcpinfo, i, offset);
607  return -1;
608  }
609 
610  if (is_numeric_type(bcpcol->column_type)) {
611  num = (TDS_NUMERIC *) bcpcol->bcp_column_data->data;
612  cpbytes = tds_numeric_bytes_per_prec[num->precision];
613  memcpy(&rowbuffer[row_pos], num->array, cpbytes);
614  } else if (bcpcol->column_type == SYBBIT) {
615  /* all bit are collapsed together */
616  if (!bitleft) {
617  bitpos = row_pos++;
618  bitleft = 8;
619  rowbuffer[bitpos] = 0;
620  }
621  if (bcpcol->bcp_column_data->data[0])
622  rowbuffer[bitpos] |= 256 >> bitleft;
623  --bitleft;
624  continue;
625  } else {
626  cpbytes = bcpcol->bcp_column_data->datalen > bcpcol->column_size ?
627  bcpcol->column_size : bcpcol->bcp_column_data->datalen;
628  memcpy(&rowbuffer[row_pos], bcpcol->bcp_column_data->data, cpbytes);
629 
630  /* CHAR data may need padding out to the database length with blanks */
631  /* TODO check binary !!! */
632  if (bcpcol->column_type == SYBCHAR && cpbytes < bcpcol->column_size) {
633  for (j = cpbytes; j < bcpcol->column_size; j++)
634  rowbuffer[row_pos + j] = ' ';
635  }
636  }
637 
638  row_pos += bcpcol->column_size;
639  }
640  return row_pos;
641 }
642 
643 /**
644  * Add variable size columns to the row
645  *
646  * \param bcpinfo BCP information already prepared
647  * \param get_col_data function to call to retrieve data to be sent
648  * \param null_error function to call if we try to send NULL if not allowed
649  * \param offset passed to get_col_data and null_error to specify the row to get
650  * \param rowbuffer The row image that will be sent to the server.
651  * \param start Where to begin copying data into the rowbuffer.
652  * \param pncols Address of output variable holding the count of columns added to the rowbuffer.
653  *
654  * \return length of (potentially modified) rowbuffer, or -1.
655  */
656 static int
657 tds_bcp_add_variable_columns(TDSBCPINFO *bcpinfo, tds_bcp_get_col_data get_col_data, tds_bcp_null_error null_error, int offset, TDS_UCHAR* rowbuffer, int start, int *pncols)
658 {
659  TDS_USMALLINT offsets[256];
660  unsigned int i, row_pos;
661  unsigned int ncols = 0;
662 
663  assert(bcpinfo);
664  assert(rowbuffer);
665  assert(pncols);
666 
667  tdsdump_log(TDS_DBG_FUNC, "%4s %8s %18s %18s %8s\n", "col",
668  "type",
669  "is_nullable_type",
670  "column_nullable",
671  "is null" );
672  for (i = 0; i < bcpinfo->bindinfo->num_cols; i++) {
673  TDSCOLUMN *bcpcol = bcpinfo->bindinfo->columns[i];
674  tdsdump_log(TDS_DBG_FUNC, "%4d %8d %18s %18s %8s\n", i,
675  bcpcol->column_type,
676  is_nullable_type(bcpcol->on_server.column_type) ? "yes" : "no",
677  bcpcol->column_nullable? "yes" : "no",
678  bcpcol->bcp_column_data->is_null? "yes" : "no" );
679  }
680 
681  /* the first two bytes of the rowbuffer are reserved to hold the entire record length */
682  row_pos = start + 2;
683  offsets[0] = row_pos;
684 
685  tdsdump_log(TDS_DBG_FUNC, "%4s %8s %8s %8s\n", "col", "ncols", "row_pos", "cpbytes");
686 
687  for (i = 0; i < bcpinfo->bindinfo->num_cols; i++) {
688  unsigned int cpbytes = 0;
689  TDSCOLUMN *bcpcol = bcpinfo->bindinfo->columns[i];
690 
691  /*
692  * Is this column of "variable" type, i.e. NULLable
693  * or naturally variable length e.g. VARCHAR
694  */
696  && !bcpcol->column_nullable)
697  continue;
698 
699  tdsdump_log(TDS_DBG_FUNC, "%4d %8d %8d %8d\n", i, ncols, row_pos, cpbytes);
700 
701  if (get_col_data(bcpinfo, bcpcol, offset) == TDS_FAIL)
702  return -1;
703 
704  /* If it's a NOT NULL column, and we have no data, throw an error. */
705  if (!(bcpcol->column_nullable)
706  && bcpcol->bcp_column_data->is_null && null_error) {
707  /* No value or default value available and NULL not allowed. */
708  null_error(bcpinfo, i, offset);
709  return -1;
710  }
711 
712  /* move the column buffer into the rowbuffer */
713  if (!bcpcol->bcp_column_data->is_null) {
714  if (is_blob_type(bcpcol->column_type)) {
715  cpbytes = 16;
716  bcpcol->column_textpos = row_pos; /* save for data write */
717  } else if (is_numeric_type(bcpcol->column_type)) {
718  TDS_NUMERIC *num = (TDS_NUMERIC *) bcpcol->bcp_column_data->data;
719  cpbytes = tds_numeric_bytes_per_prec[num->precision];
720  memcpy(&rowbuffer[row_pos], num->array, cpbytes);
721  } else if ((bcpcol->column_type == SYBVARCHAR
722  || bcpcol->column_type == SYBCHAR)
723  && bcpcol->bcp_column_data->datalen == 0) {
724  cpbytes = 1;
725  rowbuffer[row_pos] = ' ';
726  } else {
727  cpbytes = bcpcol->bcp_column_data->datalen > bcpcol->column_size ?
728  bcpcol->column_size : bcpcol->bcp_column_data->datalen;
729  memcpy(&rowbuffer[row_pos], bcpcol->bcp_column_data->data, cpbytes);
730  }
731  } else if (is_blob_type(bcpcol->column_type)) {
732  bcpcol->column_textpos = row_pos;
733  }
734 
735  row_pos += cpbytes;
736  offsets[++ncols] = row_pos;
737  tdsdump_dump_buf(TDS_DBG_NETWORK, "BCP row buffer so far", rowbuffer, row_pos);
738  }
739 
740  tdsdump_log(TDS_DBG_FUNC, "%4d %8d %8d\n", i, ncols, row_pos);
741 
742  /*
743  * The rowbuffer ends with an offset table and, optionally, an adjustment table.
744  * The offset table has 1-byte elements that describe the locations of the start of each column in
745  * the rowbuffer. If the largest offset is greater than 255, another table -- the adjustment table --
746  * is inserted just before the offset table. It holds the high bytes.
747  *
748  * Both tables are laid out in reverse:
749  * #elements, offset N+1, offset N, offset N-1, ... offset 0
750  * E.g. for 2 columns you have 4 data points:
751  * 1. How many elements (4)
752  * 2. Start of column 3 (non-existent, "one off the end")
753  * 3. Start of column 2
754  * 4. Start of column 1
755  * The length of each column is computed by subtracting its start from the its successor's start.
756  *
757  * The algorithm below computes both tables. If the adjustment table isn't needed, the
758  * effect is to overwrite it with the offset table.
759  */
760  while (ncols && offsets[ncols] == offsets[ncols-1])
761  ncols--; /* trailing NULL columns are not sent and are not included in the offset table */
762 
763  if (ncols) {
764  TDS_UCHAR *poff = rowbuffer + row_pos;
765  unsigned int pfx_top = offsets[ncols] / 256;
766 
767  tdsdump_log(TDS_DBG_FUNC, "ncols=%u poff=%p [%u]\n", ncols, poff, offsets[ncols]);
768 
769  if (offsets[ncols] / 256 == offsets[ncols-1] / 256) {
770  *poff++ = ncols + 1;
771  }
772  /* this is some kind of run-length-prefix encoding */
773  while (pfx_top) {
774  unsigned int n_pfx = 1;
775 
776  for (i = 0; i <= ncols ; ++i)
777  if ((offsets[i] / 256u) < pfx_top)
778  ++n_pfx;
779  *poff++ = n_pfx;
780  --pfx_top;
781  }
782 
783  tdsdump_log(TDS_DBG_FUNC, "poff=%p\n", poff);
784 
785  for (i=0; i <= ncols; i++)
786  *poff++ = offsets[ncols-i] & 0xFF;
787  row_pos = (unsigned int)(poff - rowbuffer);
788  }
789 
790  tdsdump_log(TDS_DBG_FUNC, "%4d %8d %8d\n", i, ncols, row_pos);
791  tdsdump_dump_buf(TDS_DBG_NETWORK, "BCP row buffer", rowbuffer, row_pos);
792 
793  *pncols = ncols;
794 
795  return ncols == 0? start : row_pos;
796 }
797 
798 /**
799  * Send BCP metadata to server.
800  * Only for TDS 7.0+.
801  * \tds
802  * \param bcpinfo BCP information
803  * \return TDS_SUCCESS or TDS_FAIL.
804  */
805 static TDSRET
807 {
808  TDSCOLUMN *bcpcol;
809  int i, num_cols;
810 
811  tdsdump_log(TDS_DBG_FUNC, "tds7_bcp_send_colmetadata(%p, %p)\n", tds, bcpinfo);
812  assert(tds && bcpinfo);
813 
815  return TDS_FAIL;
816 
817  /*
818  * Deep joy! For TDS 7 we have to send a colmetadata message followed by row data
819  */
820  tds_put_byte(tds, TDS7_RESULT_TOKEN); /* 0x81 */
821 
822  num_cols = 0;
823  for (i = 0; i < bcpinfo->bindinfo->num_cols; i++) {
824  bcpcol = bcpinfo->bindinfo->columns[i];
825  if ((!bcpinfo->identity_insert_on && bcpcol->column_identity) ||
826  bcpcol->column_timestamp ||
827  !tds_bcp_is_bound(bcpinfo, bcpcol)) {
828  continue;
829  }
830  num_cols++;
831  }
832 
833  tds_put_smallint(tds, num_cols);
834 
835  for (i = 0; i < bcpinfo->bindinfo->num_cols; i++) {
836  size_t len;
837 
838  bcpcol = bcpinfo->bindinfo->columns[i];
839 
840  /*
841  * dont send the (meta)data for timestamp columns, or
842  * identity columns (unless indentity_insert is enabled
843  */
844 
845  if ((!bcpinfo->identity_insert_on && bcpcol->column_identity) ||
846  bcpcol->column_timestamp ||
847  !tds_bcp_is_bound(bcpinfo, bcpcol)) {
848  continue;
849  }
850 
851  if (IS_TDS72_PLUS(tds->conn))
852  tds_put_int(tds, bcpcol->column_usertype);
853  else
857  (unsigned char) bcpcol->on_server.column_type);
858 
859  assert(bcpcol->funcs);
860  bcpcol->funcs->put_info(tds, bcpcol);
861 
862  /* TODO put this in put_info. It seems that parameter format is
863  * different from BCP format
864  */
865  if (is_blob_type(bcpcol->on_server.column_type)) {
866  /* FIXME support multibyte string */
867  len = tds_dstr_len(&bcpinfo->tablename);
870  (int) len);
871  }
872  /* FIXME support multibyte string */
873  len = tds_dstr_len(&bcpcol->column_name);
874  tds_put_byte(tds, (unsigned char) len);
876  (int) len);
877 
878  }
879 
881  return TDS_SUCCESS;
882 }
883 
884 /**
885  * Tell we finished sending BCP data to server
886  * \tds
887  * \param[out] rows_copied number of rows copied to server
888  */
889 TDSRET
890 tds_bcp_done(TDSSOCKET *tds, int *rows_copied)
891 {
892  TDSRET rc;
893 
894  tdsdump_log(TDS_DBG_FUNC, "tds_bcp_done(%p, %p)\n", tds, rows_copied);
895 
897  return TDS_FAIL;
898 
900 
902 
904  if (TDS_FAILED(rc))
905  return rc;
906 
907  if (rows_copied)
908  *rows_copied = tds->rows_affected;
909 
910  return TDS_SUCCESS;
911 }
912 
913 /**
914  * Start sending BCP data to server.
915  * Initialize stream to accept data.
916  * \tds
917  * \param bcpinfo BCP information already prepared
918  */
919 TDSRET
921 {
922  TDSRET rc;
923 
924  tdsdump_log(TDS_DBG_FUNC, "tds_bcp_start(%p, %p)\n", tds, bcpinfo);
925 
926  rc = tds_submit_query(tds, bcpinfo->insert_stmt);
927  if (TDS_FAILED(rc))
928  return rc;
929 
930  /* set we want to switch to bulk state */
931  tds->bulk_query = 1;
932 
933  if (IS_TDS7_PLUS(tds->conn)) {
935  } else {
936  /*
937  * In TDS 5 we get the column information as a result
938  * set from the "insert bulk" command. We need to get
939  * information about default values from it.
940  */
941  rc = tds_bcp_read_column_defaults(tds, bcpinfo);
942  }
943  if (TDS_FAILED(rc))
944  return rc;
945 
946  tds->out_flag = TDS_BULK;
948  return TDS_FAIL;
949 
950  if (IS_TDS7_PLUS(tds->conn))
951  tds7_bcp_send_colmetadata(tds, bcpinfo);
952 
953  return TDS_SUCCESS;
954 }
955 
956 /**
957  * Free row data allocated in the result set.
958  */
959 static void
960 tds_bcp_row_free(TDSRESULTINFO* result, unsigned char *row)
961 {
962  result->row_size = 0;
963  TDS_ZERO_FREE(result->current_row);
964 }
965 
966 /**
967  * Start bulk copy to server
968  * \tds
969  * \param bcpinfo BCP information already prepared
970  */
971 TDSRET
973 {
974  TDSCOLUMN *bcpcol;
975  int i;
976  int fixed_col_len_tot = 0;
977  int variable_col_len_tot = 0;
978  int column_bcp_data_size = 0;
979  int bcp_record_size = 0;
980  TDSRET rc;
981  TDS_INT var_cols;
982 
983  tdsdump_log(TDS_DBG_FUNC, "tds_bcp_start_copy_in(%p, %p)\n", tds, bcpinfo);
984 
985  rc = tds_bcp_start_insert_stmt(tds, bcpinfo);
986  if (TDS_FAILED(rc))
987  return rc;
988 
989  rc = tds_bcp_start(tds, bcpinfo);
990  if (TDS_FAILED(rc)) {
991  /* TODO, in CTLib was _ctclient_msg(blkdesc->con, "blk_rowxfer", 2, 5, 1, 140, ""); */
992  return rc;
993  }
994 
995  /*
996  * Work out the number of "variable" columns. These are either nullable or of
997  * varying length type e.g. varchar.
998  */
999  var_cols = 0;
1000 
1001  if (IS_TDS50(tds->conn)) {
1002  for (i = 0; i < bcpinfo->bindinfo->num_cols; i++) {
1003 
1004  bcpcol = bcpinfo->bindinfo->columns[i];
1005 
1006  /*
1007  * work out storage required for this datatype
1008  * blobs always require 16, numerics vary, the
1009  * rest can be taken from the server
1010  */
1011 
1012  if (is_blob_type(bcpcol->on_server.column_type))
1013  column_bcp_data_size = 16;
1014  else if (is_numeric_type(bcpcol->on_server.column_type))
1015  column_bcp_data_size = tds_numeric_bytes_per_prec[bcpcol->column_prec];
1016  else
1017  column_bcp_data_size = bcpcol->column_size;
1018 
1019  /*
1020  * now add that size into either fixed or variable
1021  * column totals...
1022  */
1023 
1024  if (is_nullable_type(bcpcol->on_server.column_type) || bcpcol->column_nullable) {
1025  var_cols++;
1026  variable_col_len_tot += column_bcp_data_size;
1027  }
1028  else {
1029  fixed_col_len_tot += column_bcp_data_size;
1030  }
1031  }
1032 
1033  /* this formula taken from sybase manual... */
1034 
1035  bcp_record_size = 4 +
1036  fixed_col_len_tot +
1037  variable_col_len_tot +
1038  ( (int)(variable_col_len_tot / 256 ) + 1 ) +
1039  (var_cols + 1) +
1040  2;
1041 
1042  tdsdump_log(TDS_DBG_FUNC, "current_record_size = %d\n", bcpinfo->bindinfo->row_size);
1043  tdsdump_log(TDS_DBG_FUNC, "bcp_record_size = %d\n", bcp_record_size);
1044 
1045  if (bcp_record_size > bcpinfo->bindinfo->row_size) {
1046  if (!TDS_RESIZE(bcpinfo->bindinfo->current_row, bcp_record_size)) {
1047  tdsdump_log(TDS_DBG_FUNC, "could not realloc current_row\n");
1048  return TDS_FAIL;
1049  }
1050  bcpinfo->bindinfo->row_free = tds_bcp_row_free;
1051  bcpinfo->bindinfo->row_size = bcp_record_size;
1052  }
1053  }
1054 
1055  return TDS_SUCCESS;
1056 }
1057 
1058 /** input stream to read a file */
1059 typedef struct tds_file_stream {
1060  /** common fields, must be the first field */
1062  /** file to read from */
1063  FILE *f;
1064 
1065  /** terminator */
1066  const char *terminator;
1067  /** terminator length in bytes */
1068  size_t term_len;
1069 
1070  /** buffer for store bytes readed that could be the terminator */
1071  char *left;
1072  size_t left_pos;
1074 
1075 /** \cond HIDDEN_SYMBOLS */
1076 #if defined(_WIN32) && defined(HAVE__LOCK_FILE) && defined(HAVE__UNLOCK_FILE)
1077 #define TDS_HAVE_STDIO_LOCKED 1
1078 #define flockfile(s) _lock_file(s)
1079 #define funlockfile(s) _unlock_file(s)
1080 #define getc_unlocked(s) _getc_nolock(s)
1081 #define feof_unlocked(s) _feof_nolock(s)
1082 #endif
1083 
1084 #ifndef TDS_HAVE_STDIO_LOCKED
1085 #undef getc_unlocked
1086 #undef feof_unlocked
1087 #undef flockfile
1088 #undef funlockfile
1089 #define getc_unlocked(s) getc(s)
1090 #define feof_unlocked(s) feof(s)
1091 #define flockfile(s) do { } while(0)
1092 #define funlockfile(s) do { } while(0)
1093 #endif
1094 /** \endcond */
1095 
1096 /**
1097  * Reads a chunk of data from file stream checking for terminator
1098  * \param stream file stream
1099  * \param ptr buffer where to read data
1100  * \param len length of buffer
1101  */
1102 static int
1103 tds_file_stream_read(TDSINSTREAM *stream, void *ptr, size_t len)
1104 {
1105  TDSFILESTREAM *s = (TDSFILESTREAM *) stream;
1106  int c;
1107  char *p = (char *) ptr;
1108 
1109  while (len) {
1110  if (memcmp(s->left, s->terminator - s->left_pos, s->term_len) == 0)
1111  return p - (char *) ptr;
1112 
1113  c = getc_unlocked(s->f);
1114  if (c == EOF)
1115  return -1;
1116 
1117  *p++ = s->left[s->left_pos];
1118  --len;
1119 
1120  s->left[s->left_pos++] = c;
1121  s->left_pos %= s->term_len;
1122  }
1123  return p - (char *) ptr;
1124 }
1125 
1126 /**
1127  * Read a data file, passing the data through iconv().
1128  * \retval TDS_SUCCESS success
1129  * \retval TDS_FAIL error reading the column
1130  * \retval TDS_NO_MORE_RESULTS end of file detected
1131  */
1132 TDSRET
1133 tds_bcp_fread(TDSSOCKET * tds, TDSICONV * char_conv, FILE * stream, const char *terminator, size_t term_len, char **outbuf, size_t * outbytes)
1134 {
1135  TDSRET res;
1136  TDSFILESTREAM r;
1137  TDSDYNAMICSTREAM w;
1138  size_t readed;
1139 
1140  /* prepare streams */
1141  r.stream.read = tds_file_stream_read;
1142  r.f = stream;
1143  r.term_len = term_len;
1144  r.left = tds_new0(char, term_len*3);
1145  r.left_pos = 0;
1146  if (!r.left) return TDS_FAIL;
1147 
1148  /* copy terminator twice, let terminator points to second copy */
1149  memcpy(r.left + term_len, terminator, term_len);
1150  memcpy(r.left + term_len*2u, terminator, term_len);
1151  r.terminator = r.left + term_len*2u;
1152 
1153  /* read initial buffer to test with terminator */
1154  readed = fread(r.left, 1, term_len, stream);
1155  if (readed != term_len) {
1156  free(r.left);
1157  if (readed == 0 && feof(stream))
1158  return TDS_NO_MORE_RESULTS;
1159  return TDS_FAIL;
1160  }
1161 
1162  res = tds_dynamic_stream_init(&w, (void**) outbuf, 0);
1163  if (TDS_FAILED(res)) {
1164  free(r.left);
1165  return res;
1166  }
1167 
1168  /* convert/copy from input stream to output one */
1169  flockfile(stream);
1170  if (char_conv == NULL)
1171  res = tds_copy_stream(tds, &r.stream, &w.stream);
1172  else
1173  res = tds_convert_stream(tds, char_conv, to_server, &r.stream, &w.stream);
1174  funlockfile(stream);
1175  free(r.left);
1176 
1177  if (TDS_FAILED(res))
1178  return res;
1179 
1180  *outbytes = w.size;
1181 
1182  /* terminate buffer */
1183  if (!w.stream.buf_len)
1184  return TDS_FAIL;
1185 
1186  ((char *) w.stream.buffer)[0] = 0;
1187  w.stream.write(&w.stream, 1);
1188 
1189  return res;
1190 }
1191 
1192 /**
1193  * Start writing writetext request.
1194  * This request start a bulk session.
1195  * \tds
1196  * \param objname table name
1197  * \param textptr TEXTPTR (see sql documentation)
1198  * \param timestamp data timestamp
1199  * \param with_log is log is enabled during insert
1200  * \param size bytes to be inserted
1201  */
1202 TDSRET
1203 tds_writetext_start(TDSSOCKET *tds, const char *objname, const char *textptr, const char *timestamp, int with_log, TDS_UINT size)
1204 {
1205  TDSRET rc;
1206 
1207  /* TODO mssql does not like timestamp */
1208  rc = tds_submit_queryf(tds,
1209  "writetext bulk %s 0x%s timestamp = 0x%s%s",
1210  objname, textptr, timestamp, with_log ? " with log" : "");
1211  if (TDS_FAILED(rc))
1212  return rc;
1213 
1214  /* set we want to switch to bulk state */
1215  tds->bulk_query = 1;
1216 
1217  /* read the end token */
1219  if (TDS_FAILED(rc))
1220  return rc;
1221 
1222  tds->out_flag = TDS_BULK;
1224  return TDS_FAIL;
1225 
1226  tds_put_int(tds, size);
1227 
1229  return TDS_SUCCESS;
1230 }
1231 
1232 /**
1233  * Send some data in the writetext request started by tds_writetext_start.
1234  * You should write in total (with multiple calls to this function) all
1235  * bytes declared calling tds_writetext_start.
1236  * \tds
1237  * \param text data to write
1238  * \param size data size in bytes
1239  */
1240 TDSRET
1242 {
1244  return TDS_FAIL;
1245 
1246  /* TODO check size left */
1247  tds_put_n(tds, text, size);
1248 
1250  return TDS_SUCCESS;
1251 }
1252 
1253 /**
1254  * Finish sending writetext data.
1255  * \tds
1256  */
1257 TDSRET
1259 {
1261  return TDS_FAIL;
1262 
1265  return TDS_SUCCESS;
1266 }
1267 
1268 
1269 static int tds_bcp_is_bound(TDSBCPINFO *bcpinfo, TDSCOLUMN *colinfo)
1270 {
1271  return (bcpinfo && colinfo &&
1272  /* Don't interfere with dblib bulk insertion from files. */
1273  (bcpinfo->xfer_init == 0
1274  || colinfo->column_varaddr != NULL
1275  || (colinfo->column_lenbind != NULL
1276  && (*colinfo->column_lenbind != 0
1277  || (colinfo->column_nullbind != NULL
1278  /* null-value for blk_textxfer ... */
1279  /* && *colinfo->column_nullbind == -1 */)))));
1280 }
1281 
1282 
1284 {
1285  TDS_INT res_type;
1286  TDS_INT done_flags;
1287  int rc;
1288  int ret = TDS_SUCCESS;
1289 
1290  int num_defs = 0;
1291  int colnum, res_colnum;
1292  TDS_TINYINT byte_val;
1293  unsigned char* src;
1294  TDSRESULTINFO* resinfo;
1295  TDSRESULTINFO* bindinfo = bcpinfo->bindinfo;
1296  TDSCOLUMN* curcol;
1297  TDSCOLUMN* bindcol;
1298 
1299  /* Read metainformation about all columns */
1300  for (colnum = 0; ; ++colnum) {
1301  rc = tds_process_tokens(tds, &res_type, &done_flags,
1303  if (TDS_FAILED(rc)) {
1304  ret = TDS_FAIL;
1305  break;
1306  }
1307 
1308  if (res_type == TDS_DONE_RESULT) {
1309  if ((done_flags & TDS_DONE_ERROR) != 0)
1310  ret = TDS_FAIL;
1311  /*
1312  * First recordset with columnsmetainfo is done
1313  * - go to the next
1314  */
1315  break;
1316  }
1317 
1318  if (res_type != TDS_ROW_RESULT)
1319  continue;
1320 
1321  resinfo = tds->current_results;
1322 
1323 #if ENABLE_EXTRA_CHECKS
1324  /*
1325  * Most probably the format of result is fixed, but
1326  * couple of asserts are still needed to be sure
1327  */
1328  assert(resinfo->num_cols == 12);
1329  assert(colnum < bindinfo->num_cols);
1330 #endif
1331 
1332  bindcol = bindinfo->columns[colnum];
1333 
1334  /* Read "default" flag of the column */
1335  curcol = resinfo->columns[9];
1336 
1337 #if ENABLE_EXTRA_CHECKS
1338  assert(curcol->column_type == SYBINT1);
1339 #endif
1340 
1341  src = curcol->column_data;
1342  byte_val = *((TDS_TINYINT*) src);
1343 
1344  if (byte_val == 1) {
1345  ++num_defs;
1346  bindcol->column_hasdefault = 1;
1347  }
1348  }
1349 
1350  if (TDS_SUCCEED(ret) && num_defs > 0
1351  && TDS_SUCCEED(tds_process_tokens(tds, &res_type, &done_flags,
1352  TDS_RETURN_ROW)))
1353  {
1354  resinfo = tds->current_results;
1355 
1356 #if ENABLE_EXTRA_CHECKS
1357  assert(resinfo->num_cols == num_defs);
1358 #endif
1359 
1360  /* Now read all default values */
1361  res_colnum = 0;
1362  for (colnum = 0; colnum < bindinfo->num_cols;
1363  ++colnum) {
1364  bindcol = bindinfo->columns[colnum];
1365  if ( !bindcol->column_hasdefault ) {
1366  continue;
1367  }
1368 
1369  curcol = resinfo->columns[res_colnum];
1370  ++res_colnum;
1371  src = curcol->column_data;
1372  if (is_blob_type(curcol->column_type)) {
1373  src = (unsigned char*)
1374  ((TDSBLOB*)src)->textvalue;
1376  (bindcol->bcp_column_data);
1377  bindcol->bcp_column_data
1379  (curcol->column_cur_size);
1380  }
1381  /*
1382  * Maybe it's better to ignore all requests
1383  * of defaults after first request
1384  */
1385  if (bindcol->column_default) {
1386  bindcol->column_default
1387  = realloc(bindcol->column_default,
1388  curcol->column_cur_size);
1389  }
1390  else {
1391  bindcol->column_default
1392  = malloc(curcol->column_cur_size);
1393  }
1394  if (bindcol->column_default == NULL) {
1395  ret = TDS_FAIL;
1396  break;
1397  }
1398 
1399  bindcol->column_def_size
1400  = curcol->column_cur_size;
1401  memcpy(bindcol->column_default, src,
1402  bindcol->column_def_size);
1403  }
1404  }
1405 
1406  if (TDS_SUCCEED(ret)) {
1408  }
1409 
1410  return ret;
1411 }
static int tds_bcp_add_variable_columns(TDSBCPINFO *bcpinfo, tds_bcp_get_col_data get_col_data, tds_bcp_null_error null_error, int offset, TDS_UCHAR *rowbuffer, int start, int *pncols)
Add variable size columns to the row.
Definition: bulk.c:657
static int tds_bcp_add_fixed_columns(TDSBCPINFO *bcpinfo, tds_bcp_get_col_data get_col_data, tds_bcp_null_error null_error, int offset, unsigned char *rowbuffer, int start)
Add fixed size columns to the row.
Definition: bulk.c:572
static int tds_file_stream_read(TDSINSTREAM *stream, void *ptr, size_t len)
Reads a chunk of data from file stream checking for terminator.
Definition: bulk.c:1103
static TDSRET tds7_build_bulk_insert_stmt(TDSSOCKET *tds, TDSPBCB *clause, TDSCOLUMN *bcpcol, int first)
Help to build query to be sent to server.
Definition: bulk.c:225
static TDSRET tds7_bcp_send_colmetadata(TDSSOCKET *tds, TDSBCPINFO *bcpinfo)
Send BCP metadata to server.
Definition: bulk.c:806
TDSRET tds_bcp_start_copy_in(TDSSOCKET *tds, TDSBCPINFO *bcpinfo)
Start bulk copy to server \tds.
Definition: bulk.c:972
TDSRET tds_writetext_start(TDSSOCKET *tds, const char *objname, const char *textptr, const char *timestamp, int with_log, TDS_UINT size)
Start writing writetext request.
Definition: bulk.c:1203
static void tds_bcp_row_free(TDSRESULTINFO *result, unsigned char *row)
Free row data allocated in the result set.
Definition: bulk.c:960
TDSRET tds_bcp_start(TDSSOCKET *tds, TDSBCPINFO *bcpinfo)
Start sending BCP data to server.
Definition: bulk.c:920
TDSRET tds_bcp_fread(TDSSOCKET *tds, TDSICONV *char_conv, FILE *stream, const char *terminator, size_t term_len, char **outbuf, size_t *outbytes)
Read a data file, passing the data through iconv().
Definition: bulk.c:1133
static int tds_bcp_is_bound(TDSBCPINFO *bcpinfo, TDSCOLUMN *colinfo)
Definition: bulk.c:1269
static TDSRET tds_bcp_start_insert_stmt(TDSSOCKET *tds, TDSBCPINFO *bcpinfo)
Prepare the query to be sent to server to request BCP information \tds.
Definition: bulk.c:272
TDSRET tds_writetext_continue(TDSSOCKET *tds, const TDS_UCHAR *text, TDS_UINT size)
Send some data in the writetext request started by tds_writetext_start.
Definition: bulk.c:1241
static int tds_bcp_read_column_defaults(TDSSOCKET *tds, TDSBCPINFO *bcpinfo)
Definition: bulk.c:1283
TDSRET tds_writetext_end(TDSSOCKET *tds)
Finish sending writetext data.
Definition: bulk.c:1258
struct tds_file_stream TDSFILESTREAM
input stream to read a file
TDSRET tds_bcp_init(TDSSOCKET *tds, TDSBCPINFO *bcpinfo)
Initialize BCP information.
Definition: bulk.c:88
TDSRET tds_bcp_send_record(TDSSOCKET *tds, TDSBCPINFO *bcpinfo, tds_bcp_get_col_data get_col_data, tds_bcp_null_error null_error, int offset)
Send one row of data to server \tds.
Definition: bulk.c:344
TDSRET tds_bcp_done(TDSSOCKET *tds, int *rows_copied)
Tell we finished sending BCP data to server \tds.
Definition: bulk.c:890
struct tds_pbcb TDSPBCB
Holds clause buffer.
#define TDS_PUT_UA2(ptr, val)
Definition: bytes.h:146
static TDSSOCKET * tds
Definition: collations.c:37
static void cleanup(void)
Definition: ct_dynamic.c:30
static DLIST_TYPE *DLIST_NAME() first(DLIST_LIST_TYPE *list)
Definition: dlist.tmpl.h:46
#define NULL
Definition: ncbistd.hpp:225
static const char * tds_dstr_cstr(DSTR *s)
Returns a C version (NUL terminated string) of dstr.
Definition: string.h:66
DSTR * tds_dstr_dup(DSTR *s, const DSTR *src) TDS_WUR
Duplicate a string from another dynamic string.
Definition: tdsstring.c:135
static size_t tds_dstr_len(DSTR *s)
Returns the length of the string in bytes.
Definition: string.h:73
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
@ to_server
Definition: iconv.h:70
int i
int len
static void text(MDB_val *v)
Definition: mdb_dump.c:62
const struct ncbi::grid::netcache::search::fields::SIZE size
#define strdup
Definition: ncbi_ansi_ext.h:70
#define MIN(a, b)
returns smaller of a and b.
Definition: ncbi_std.h:112
#define MAX(a, b)
returns larger of a and b.
Definition: ncbi_std.h:117
static char terminator
Definition: njn_ioutil.cpp:56
double r(size_t dimension_, const Int4 *score_, const double *prob_, double theta_)
@ TDS_BULK
Definition: proto.h:338
#define TDS7_RESULT_TOKEN
Definition: proto.h:83
#define TDS_ROW_TOKEN
Definition: proto.h:100
#define tds_put_string
#define tds_alloc_results
#define tds_put_n
#define tds_convert_stream
#define tds_put_int
#define tds_free_bcp_column_data
#define tds_put_smallint
#define tds_quote_id
#define tds_dynamic_stream_init
#define tds_process_simple_query
#define tds_get_column_declaration
#define tds_flush_packet
#define tds_numeric_bytes_per_prec
#define tds_submit_query
#define tds_set_state
#define tds_alloc_bcp_column_data
#define tds_put_byte
#define tds_submit_queryf
#define tdserror
#define tds_copy_stream
#define tds_process_tokens
#define tds_free_results
#define asprintf
Definition: replacements.h:54
int offset
Definition: replacements.h:160
#define strcat(s, k)
#define assert(x)
Definition: srv_diag.hpp:58
static string query
TDS_UCHAR * data
Definition: tds.h:694
TDS_INT is_null
Definition: tds.h:696
TDS_INT datalen
Definition: tds.h:695
TDS_INT blob_cols
Definition: tds.h:1672
const char * hint
Definition: tds.h:1661
TDS_CHAR * insert_stmt
Definition: tds.h:1664
TDS_INT text_sent
Definition: tds.h:1670
TDS_INT identity_insert_on
Definition: tds.h:1666
TDSRESULTINFO * bindinfo
Definition: tds.h:1669
TDS_INT xfer_init
Definition: tds.h:1667
TDS_INT next_col
Definition: tds.h:1671
DSTR tablename
Definition: tds.h:1663
TDS_INT direction
Definition: tds.h:1665
TDS_INT bind_count
Definition: tds.h:1668
Information about blobs (e.g.
Definition: tds.h:658
TDS_CHAR * textvalue
Definition: tds.h:659
tds_func_put_data * put_data
Send column data to server.
Definition: tds.h:734
tds_func_put_info * put_info
Send metadata column information to server.
Definition: tds.h:724
Metadata about columns in regular and compute rows.
Definition: tds.h:761
TDS_TINYINT column_varint_size
size of length when reading from wire (0, 1, 2 or 4)
Definition: tds.h:773
TDS_SMALLINT * column_nullbind
Definition: tds.h:818
TDS_INT column_textpos
Definition: tds.h:821
TDS_INT column_size
maximun size of data.
Definition: tds.h:766
BCPCOLDATA * bcp_column_data
Definition: tds.h:825
unsigned int column_hasdefault
Definition: tds.h:802
DSTR column_name
Definition: tds.h:787
unsigned int column_timestamp
Definition: tds.h:801
TDS_UCHAR column_collation[5]
Definition: tds.h:803
TDS_UINT column_bindlen
Definition: tds.h:817
const TDSCOLUMNFUNCS * funcs
Definition: tds.h:762
TDS_INT * column_lenbind
Definition: tds.h:820
unsigned char * column_data
Definition: tds.h:793
DSTR table_column_name
Definition: tds.h:788
TDS_TINYINT column_prec
precision for decimal/numeric
Definition: tds.h:775
TDS_SERVER_TYPE column_type
This type can be different from wire type because conversion (e.g.
Definition: tds.h:768
unsigned int column_identity
Definition: tds.h:797
unsigned int column_nullable
Definition: tds.h:795
TDSICONV * char_conv
refers to previously allocated iconv information
Definition: tds.h:784
TDS_INT column_def_size
Definition: tds.h:790
TDS_TINYINT column_scale
scale for decimal/numeric
Definition: tds.h:776
TDS_CHAR * column_varaddr
Definition: tds.h:819
struct tds_column::@124 on_server
unsigned char * column_default
Definition: tds.h:791
TDS_INT column_flags
Definition: tds.h:764
TDS_INT column_cur_size
size written in variable (ie: char, text, binary).
Definition: tds.h:811
TDS_INT column_usertype
Definition: tds.h:763
output stream to write data to a dynamic buffer
Definition: stream.h:99
TDSOUTSTREAM stream
Definition: stream.h:100
size_t size
size of data inside buffer
Definition: stream.h:106
input stream to read a file
Definition: bulk.c:1059
size_t left_pos
Definition: bulk.c:1072
char * left
buffer for store bytes readed that could be the terminator
Definition: bulk.c:1071
FILE * f
file to read from
Definition: bulk.c:1063
const char * terminator
terminator
Definition: bulk.c:1066
size_t term_len
terminator length in bytes
Definition: bulk.c:1068
TDSINSTREAM stream
common fields, must be the first field
Definition: bulk.c:1061
define a stream of data used for input
Definition: stream.h:30
size_t buf_len
Definition: stream.h:51
char * buffer
write buffer.
Definition: stream.h:50
int(* write)(struct tds_output_stream *stream, size_t len)
write len bytes from buffer, return <0 if error or len
Definition: stream.h:41
Holds clause buffer.
Definition: bulk.c:63
char * pb
buffer
Definition: bulk.c:65
unsigned int from_malloc
true is buffer came from malloc
Definition: bulk.c:69
unsigned int cb
buffer length
Definition: bulk.c:67
Hold information for any results.
Definition: tds.h:842
unsigned char * current_row
Definition: tds.h:849
void(* row_free)(struct tds_result_info *result, unsigned char *row)
Definition: tds.h:850
TDS_USMALLINT num_cols
Definition: tds.h:845
TDSCOLUMN ** columns
Definition: tds.h:844
TDS_INT row_size
Definition: tds.h:851
Information for a server connection.
Definition: tds.h:1211
TDSRESULTINFO * current_results
Current query information.
Definition: tds.h:1263
TDSRESULTINFO * res_info
Definition: tds.h:1264
TDS_INT8 rows_affected
rows updated/deleted/inserted/selected, TDS_NO_COUNT if not valid
Definition: tds.h:1278
TDS_TINYINT bulk_query
true is query sent was a bulk query so we need to switch state to QUERYING
Definition: tds.h:1269
unsigned char out_flag
output buffer type
Definition: tds.h:1241
TDSCONNECTION conn[1]
Definition: tds.h:1215
unsigned char precision
Definition: proto.h:27
unsigned char array[33]
Definition: proto.h:29
#define SYBVARCHAR
Definition: sybdb.h:162
#define SYBINT1
Definition: sybdb.h:166
#define SYBCHAR
Definition: sybdb.h:160
#define SYBBIT
Definition: sybdb.h:178
Main include file for libtds.
#define TDS_FAIL
Definition: tds.h:204
#define tds_new(type, n)
Definition: tds.h:1392
#define is_numeric_type(x)
Definition: tds.h:454
#define TDS_FAILED(rc)
Definition: tds.h:206
tds_sysdep_int32_type TDS_INT
Definition: tds.h:149
@ TDS_RETURN_ROW
Definition: tds.h:256
@ TDS_TOKEN_RESULTS
Definition: tds.h:261
@ TDS_RETURN_DONE
Definition: tds.h:255
#define TDS_DONE_RESULT
Definition: tds.h:227
#define tdsdump_log
Definition: tds.h:1561
#define TDS_DBG_INFO1
Definition: tds.h:900
#define TDS_NO_MORE_RESULTS
Definition: tds.h:202
#define IS_TDS50(x)
Definition: tds.h:1701
#define is_blob_type(x)
Definition: tds.h:443
void(* tds_bcp_null_error)(TDSBCPINFO *bulk, int index, int offset)
Definition: tds.h:1677
unsigned char TDS_UCHAR
Definition: tds.h:145
#define is_blob_col(x)
Definition: tds.h:445
#define IS_TDS72_PLUS(x)
Definition: tds.h:1710
unsigned char TDS_TINYINT
Definition: tds.h:146
@ TDS_PENDING
cilent is waiting for data
Definition: tds.h:866
@ TDS_SENDING
client would send data
Definition: tds.h:865
@ TDS_WRITING
client is writing data
Definition: tds.h:864
#define tdsdump_dump_buf
Definition: tds.h:1564
@ TDSEBPROBADTYP
Definition: tds.h:327
@ TDSEMEM
Definition: tds.h:310
#define IS_TDS7_PLUS(x)
Definition: tds.h:1708
TDSRET(* tds_bcp_get_col_data)(TDSBCPINFO *bulk, TDSCOLUMN *bcpcol, int offset)
Definition: tds.h:1676
#define tds_new0(type, n)
Definition: tds.h:1393
char TDS_CHAR
Definition: tds.h:144
#define is_nullable_type(x)
Definition: tds.h:439
#define TDS_ROW_RESULT
Definition: tds.h:216
@ TDS_DONE_ERROR
error occurred
Definition: tds.h:272
int TDSRET
Definition: tds.h:201
tds_sysdep_uint16_type TDS_USMALLINT
Definition: tds.h:148
#define TDS_SUCCESS
Definition: tds.h:203
#define TDS_RESIZE(p, n_elem)
Definition: tds.h:1390
@ TDS_BCP_QUERYOUT
Definition: tds.h:1656
#define TDS_SUCCEED(rc)
Definition: tds.h:207
#define TDS_ZERO_FREE(x)
Definition: tds.h:359
tds_sysdep_uint32_type TDS_UINT
Definition: tds.h:150
#define tds_get_ctx(tds)
Definition: tds.h:1294
#define TDS_PUT_SMALLINT(tds, v)
Definition: tds.h:1743
#define TDS_DBG_FUNC
Definition: tds.h:898
#define TDS_DBG_NETWORK
Definition: tds.h:901
else result
Definition: token2.c:20
uchar outbuf[(1000000+1000000)]
Definition: unzcrash.c:41
void free(voidpf ptr)
voidp malloc(uInt size)
Modified on Tue Apr 09 07:57:01 2024 by modify_doxy.py rev. 669887
Modified on Wed Apr 10 07:32:26 2024 by modify_doxy.py rev. 669887
Modified on Thu Apr 11 15:04:51 2024 by modify_doxy.py rev. 669887
Modified on Fri Apr 12 17:16:59 2024 by modify_doxy.py rev. 669887
Modified on Sat Apr 13 11:45:09 2024 by modify_doxy.py rev. 669887
Modified on Sun Apr 14 05:25:46 2024 by modify_doxy.py rev. 669887