src/dbapi/driver/ftds64/freetds/dblib/bcp.c

Go to the documentation of this file.
00001 /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
00002  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005  Brian Bruns
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Library General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Library General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Library General Public
00015  * License along with this library; if not, write to the
00016  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00017  * Boston, MA 02111-1307, USA.
00018  */
00019 
00020 #if HAVE_CONFIG_H
00021 #include <config.h>
00022 #endif
00023 
00024 #include <stdio.h>
00025 #include <assert.h>
00026 
00027 #if HAVE_STRING_H
00028 #include <string.h>
00029 #endif /* HAVE_STRING_H */
00030 
00031 #if HAVE_STDLIB_H
00032 #include <stdlib.h>
00033 #endif /* HAVE_STDLIB_H */
00034 
00035 #if HAVE_UNISTD_H
00036 #include <unistd.h>
00037 #endif /* HAVE_UNISTD_H */
00038 
00039 #include "tds.h"
00040 #include "tdsiconv.h"
00041 #include "tdsconvert.h"
00042 #include "replacements.h"
00043 #include "sybfront.h"
00044 #include "sybdb.h"
00045 #include "syberror.h"
00046 #include "dblib.h"
00047 
00048 #ifdef DMALLOC
00049 #include <dmalloc.h>
00050 #endif
00051 
00052 #define HOST_COL_CONV_ERROR 1
00053 #define HOST_COL_NULL_ERROR 2
00054 
00055 #define BCP_REC_FETCH_DATA   1
00056 #define BCP_REC_NOFETCH_DATA 0
00057 
00058 #ifndef MAX
00059 #define MAX(a,b) ( (a) > (b) ? (a) : (b) )
00060 #endif
00061 
00062 typedef struct _pbcb
00063 {
00064     char *pb;
00065     int cb;
00066     unsigned int from_malloc;
00067 }
00068 TDS_PBCB;
00069 
00070 TDS_RCSID(var, "$Id: bcp.c 174668 2009-10-29 19:44:31Z ivanovp $");
00071 
00072 #ifdef HAVE_FSEEKO
00073 typedef off_t offset_type;
00074 #else
00075 #define fseeko(f,o,w) fseek(f,o,w)
00076 #define ftello(f) ftell(f)
00077 typedef long offset_type;
00078 #endif
00079 
00080 static RETCODE _bcp_send_bcp_record(DBPROCESS * dbproc, int behaviour);
00081 static RETCODE _bcp_build_bulk_insert_stmt(TDSSOCKET *, TDS_PBCB *, TDSCOLUMN *, int);
00082 static RETCODE _bcp_free_storage(DBPROCESS * dbproc);
00083 static void _bcp_free_columns(DBPROCESS * dbproc);
00084 static RETCODE _bcp_get_col_data(DBPROCESS * dbproc, TDSCOLUMN *bindcol);
00085 static RETCODE _bcp_send_colmetadata(DBPROCESS *);
00086 static RETCODE _bcp_start_copy_in(DBPROCESS *);
00087 static RETCODE _bcp_start_new_batch(DBPROCESS *);
00088 
00089 static int rtrim(char *, int);
00090 static offset_type _bcp_measure_terminated_field(FILE * hostfile, BYTE * terminator, int term_len);
00091 static RETCODE _bcp_read_hostfile(DBPROCESS * dbproc, FILE * hostfile, int *row_error);
00092 static int _bcp_readfmt_colinfo(DBPROCESS * dbproc, char *buf, BCP_HOSTCOLINFO * ci);
00093 static RETCODE _bcp_get_term_var(BYTE * pdata, BYTE * term, int term_len);
00094 
00095 /**
00096  * \ingroup dblib_bcp
00097  * \brief Prepare for bulk copy operation on a table
00098  *
00099  * \param dbproc contains all information needed by db-lib to manage communications with the server.
00100  * \param tblname the name of the table receiving or providing the data.
00101  * \param hfile the data file opposite the table, if any.
00102  * \param errfile the "error file" captures messages and, if errors are encountered,
00103  *  copies of any rows that could not be written to the table.
00104  * \param direction one of
00105  *      - \b DB_IN writing to the table
00106  *      - \b DB_OUT writing to the host file
00107  *      .
00108  * \remarks bcp_init() sets the host file data format and acquires the table metadata.
00109  *  It is called before the other bulk copy functions.
00110  *
00111  *  When writing to a table, bcp can use as its data source a data file (\a hfile),
00112  *  or program data in an application's variables.  In the latter case, call bcp_bind()
00113  *  to associate your data with the appropriate table column.
00114  * \return SUCCEED or FAIL.
00115  * \sa  BCP_SETL(), bcp_bind(), bcp_done(), bcp_exec()
00116  */
00117 RETCODE
00118 bcp_init(DBPROCESS * dbproc, const char *tblname, const char *hfile, const char *errfile, int direction)
00119 {
00120     TDSRESULTINFO *resinfo;
00121     TDSRESULTINFO *bindinfo;
00122     TDSCOLUMN *curcol;
00123 
00124     TDS_INT result_type;
00125     int i, rc;
00126 
00127     if (dbproc == NULL) {   /* sanity */
00128         dbperror(dbproc, SYBENULL, 0);
00129         return (FAIL);
00130     }
00131 
00132     /* Free previously allocated storage in dbproc & initialise flags, etc. */
00133     
00134     _bcp_free_storage(dbproc);
00135 
00136     /*
00137      * Validate other parameters
00138      */
00139 #define SYBETDSVER -100
00140     if (dbproc->tds_socket->major_version < 5) {
00141         dbperror(dbproc, SYBETDSVER, 0);
00142         return (FAIL);
00143     }
00144 
00145     if (tblname == NULL) {
00146         dbperror(dbproc, SYBEBCITBNM, 0);
00147         return (FAIL);
00148     }
00149 
00150     /* TODO even for TDS7+ ?? */
00151     if (strlen(tblname) > 92) { /* 30.30.30 */
00152         dbperror(dbproc, SYBEBCITBLEN, 0);
00153         return (FAIL);
00154     }
00155 
00156     if (direction != DB_IN && direction != DB_OUT && direction != DB_QUERYOUT) {
00157         dbperror(dbproc, SYBEBDIO, 0);
00158         return (FAIL);
00159     }
00160 
00161     if (hfile != NULL) {
00162 
00163         dbproc->hostfileinfo = calloc(1, sizeof(BCP_HOSTFILEINFO));
00164 
00165         if (dbproc->hostfileinfo == NULL)
00166             goto memory_error;
00167         if ((dbproc->hostfileinfo->hostfile = strdup(hfile)) == NULL)
00168             goto memory_error;
00169 
00170         if (errfile != NULL)
00171             if ((dbproc->hostfileinfo->errorfile = strdup(errfile)) == NULL)
00172                 goto memory_error;
00173     } else {
00174         dbproc->hostfileinfo = NULL;
00175     }
00176 
00177     /* Allocate storage */
00178     
00179     dbproc->bcpinfo = malloc(sizeof(DB_BCPINFO));
00180     if (dbproc->bcpinfo == NULL)
00181         goto memory_error;
00182 
00183     memset(dbproc->bcpinfo, '\0', sizeof(DB_BCPINFO));
00184 
00185     if ((dbproc->bcpinfo->tablename = strdup(tblname)) == NULL)
00186         goto memory_error;
00187 
00188     dbproc->bcpinfo->direction = direction;
00189 
00190     dbproc->bcpinfo->xfer_init  = 0;
00191     dbproc->bcpinfo->var_cols   = 0;
00192     dbproc->bcpinfo->bind_count = 0;
00193 
00194     if (direction == DB_IN) {
00195         TDSSOCKET *tds = dbproc->tds_socket;
00196 
00197         if (tds_submit_queryf(tds, "SET FMTONLY ON select * from %s SET FMTONLY OFF", dbproc->bcpinfo->tablename) == TDS_FAIL) {
00198             return FAIL;
00199         }
00200     
00201         /* TODO check what happen if table is not present, cleanup on error */
00202         while ((rc = tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS))
00203                == TDS_SUCCEED) {
00204         }
00205         if (rc != TDS_NO_MORE_RESULTS) {
00206             return FAIL;
00207         }
00208     
00209         if (!tds->res_info) {
00210             return FAIL;
00211         }
00212     
00213         /* TODO check what happen if table is not present, cleanup on error */
00214         resinfo = tds->res_info;
00215         if ((bindinfo = tds_alloc_results(resinfo->num_cols)) == NULL) {
00216             return FAIL;
00217         }
00218     
00219         bindinfo->row_size = resinfo->row_size;
00220     
00221         dbproc->bcpinfo->bindinfo = bindinfo;
00222         dbproc->bcpinfo->bind_count = 0;
00223     
00224         /* Copy the column metadata */
00225         for (i = 0; i < bindinfo->num_cols; i++) {
00226     
00227             curcol = bindinfo->columns[i];
00228             
00229             /*
00230              * TODO use memcpy ??
00231              * curcol and resinfo->columns[i] are both TDSCOLUMN.
00232              * Why not "curcol = resinfo->columns[i];"?  Because the rest of TDSCOLUMN (below column_timestamp)
00233              * isn't being used.  Perhaps this "upper" part of TDSCOLUMN should be a substructure.
00234              * Or, see if the "lower" part is unused (and zeroed out) at this point, and just do one assignment.
00235              */
00236             curcol->column_type = resinfo->columns[i]->column_type;
00237             curcol->column_usertype = resinfo->columns[i]->column_usertype;
00238             curcol->column_flags = resinfo->columns[i]->column_flags;
00239             curcol->column_size = resinfo->columns[i]->column_size;
00240             curcol->column_varint_size = resinfo->columns[i]->column_varint_size;
00241             curcol->column_prec = resinfo->columns[i]->column_prec;
00242             curcol->column_scale = resinfo->columns[i]->column_scale;
00243             curcol->column_namelen = resinfo->columns[i]->column_namelen;
00244             curcol->on_server.column_type = resinfo->columns[i]->on_server.column_type;
00245             curcol->on_server.column_size = resinfo->columns[i]->on_server.column_size;
00246             curcol->char_conv = resinfo->columns[i]->char_conv;
00247             memcpy(curcol->column_name, resinfo->columns[i]->column_name, resinfo->columns[i]->column_namelen);
00248             curcol->column_nullable = resinfo->columns[i]->column_nullable;
00249             curcol->column_identity = resinfo->columns[i]->column_identity;
00250             curcol->column_timestamp = resinfo->columns[i]->column_timestamp;
00251             
00252             memcpy(curcol->column_collation, resinfo->columns[i]->column_collation, 5);
00253             
00254             if (is_numeric_type(curcol->column_type)) {
00255                 curcol->bcp_column_data = tds_alloc_bcp_column_data(sizeof(TDS_NUMERIC));
00256                 ((TDS_NUMERIC *) curcol->bcp_column_data->data)->precision = curcol->column_prec;
00257                 ((TDS_NUMERIC *) curcol->bcp_column_data->data)->scale = curcol->column_scale;
00258             } else {
00259                 curcol->bcp_column_data = tds_alloc_bcp_column_data(MAX(curcol->column_size,curcol->on_server.column_size));
00260             }
00261         }
00262 
00263         /* TODO check + clean */
00264         bindinfo->current_row = tds_alloc_row(bindinfo);
00265     
00266     }
00267 
00268     return SUCCEED;
00269 
00270 memory_error:
00271     _bcp_free_storage(dbproc);
00272     dbperror(dbproc, SYBEMEM, ENOMEM);
00273     return FAIL;
00274 }
00275 
00276 
00277 /**
00278  * \ingroup dblib_bcp
00279  * \brief Set the length of a host variable to be written to a table.
00280  *
00281  * \param dbproc contains all information needed by db-lib to manage communications with the server.
00282  * \param varlen size of the variable, in bytes, or
00283  *  - \b 0 indicating NULL
00284  *  - \b -1 indicating size is determined by the prefix or terminator.
00285  *      (If both a prefix and a terminator are present, bcp is supposed to use the smaller of the
00286  *       two.  This feature might or might not actually work.)
00287  * \param table_column the number of the column in the table (starting with 1, not zero).
00288  *
00289  * \return SUCCEED or FAIL.
00290  * \sa  bcp_bind(), bcp_colptr(), bcp_sendrow()
00291  */
00292 RETCODE
00293 bcp_collen(DBPROCESS * dbproc, DBINT varlen, int table_column)
00294 {
00295     TDSCOLUMN *curcol;
00296 
00297     if (dbproc->bcpinfo == NULL) {
00298         dbperror(dbproc, SYBEBCPI, 0);
00299         return FAIL;
00300     }
00301 
00302     if (dbproc->bcpinfo->direction != DB_IN) {
00303         dbperror(dbproc, SYBEBCPN, 0);
00304         return FAIL;
00305     }
00306 
00307     if (dbproc->hostfileinfo != NULL) {
00308         dbperror(dbproc, SYBEBCPI, 0);
00309         return FAIL;
00310     }
00311 
00312     /* TODO return specific error on FAIL ?? */
00313     if (table_column <= 0 || table_column > dbproc->bcpinfo->bindinfo->num_cols)
00314         return FAIL;
00315 
00316     curcol = dbproc->bcpinfo->bindinfo->columns[table_column - 1];
00317     curcol->column_bindlen = varlen;
00318 
00319     return SUCCEED;
00320 }
00321 
00322 /**
00323  * \ingroup dblib_bcp
00324  * \brief Indicate how many columns are to be found in the datafile.
00325  *
00326  * \param dbproc contains all information needed by db-lib to manage communications with the server.
00327  * \param host_colcount count of columns in the datafile, irrespective of how many you intend to use.
00328  * \remarks This function describes the file as it is, not how it will be used.
00329  *
00330  * \return SUCCEED or FAIL.  It's hard to see how it could fail.
00331  * \sa  bcp_colfmt()    
00332  */
00333 RETCODE
00334 bcp_columns(DBPROCESS * dbproc, int host_colcount)
00335 {
00336 
00337     int i;
00338 
00339     if (dbproc->bcpinfo == NULL) {
00340         dbperror(dbproc, SYBEBCPI, 0);
00341         return FAIL;
00342     }
00343 
00344     if (dbproc->hostfileinfo == NULL) {
00345         dbperror(dbproc, SYBEBIVI, 0);
00346         return FAIL;
00347     }
00348 
00349     if (host_colcount < 1) {
00350         dbperror(dbproc, SYBEBCFO, 0);
00351         return FAIL;
00352     }
00353 
00354     _bcp_free_columns(dbproc);
00355 
00356     /* FIXME handle out of memory */
00357     /* TODO if already allocated ?? */
00358     dbproc->hostfileinfo->host_columns = (BCP_HOSTCOLINFO **) malloc(host_colcount * sizeof(BCP_HOSTCOLINFO *));
00359     if (dbproc->hostfileinfo->host_columns == NULL) {
00360         dbperror(dbproc, SYBEMEM, ENOMEM);
00361         return FAIL;
00362     }
00363     dbproc->hostfileinfo->host_colcount = host_colcount;
00364 
00365     for (i = 0; i < host_colcount; i++) {
00366         dbproc->hostfileinfo->host_columns[i] = (BCP_HOSTCOLINFO *) malloc(sizeof(BCP_HOSTCOLINFO));
00367         if (dbproc->hostfileinfo->host_columns[i] == NULL) {
00368             dbproc->hostfileinfo->host_colcount = i;
00369             _bcp_free_columns(dbproc);
00370             dbperror(dbproc, SYBEMEM, ENOMEM);
00371             return FAIL;
00372         }
00373         memset(dbproc->hostfileinfo->host_columns[i], '\0', sizeof(BCP_HOSTCOLINFO));
00374     }
00375 
00376     return SUCCEED;
00377 }
00378 
00379 /**
00380  * \ingroup dblib_bcp
00381  * \brief Specify the format of a datafile prior to writing to a table.
00382  *
00383  * \param dbproc contains all information needed by db-lib to manage communications with the server.
00384  * \param host_colnum datafile column number (starting with 1, not zero).
00385  * \param host_type dataype token describing the data type in \a host_colnum.  E.g. SYBCHAR for character data.
00386  * \param host_prefixlen size of the prefix in the datafile column, if any.  For delimited files: zero.
00387  *          May be 0, 1, 2, or 4 bytes.  The prefix will be read as an integer (not a character string) from the
00388  *          data file, and will be interpreted the data size of that column, in bytes.
00389  * \param host_collen maximum size of datafile column, exclusive of any prefix/terminator.  Just the data, ma'am.
00390  *      Special values:
00391  *          - \b 0 indicates NULL.
00392  *          - \b -1 for fixed-length non-null datatypes
00393  *          - \b -1 for variable-length datatypes (e.g. SYBCHAR) where the length is established
00394  *              by a prefix/terminator.
00395  * \param host_term the sequence of characters that will serve as a column terminator (delimiter) in the datafile.
00396  *          Often a tab character, but can be any string of any length.  Zero indicates no terminator.
00397  *          Special characters:
00398  *              - \b '\\0' terminator is an ASCII NUL.
00399  *              - \b '\\t' terminator is an ASCII TAB.
00400  *              - \b '\\n' terminator is an ASCII NL.
00401  * \param host_termlen the length of \a host_term, in bytes.
00402  * \param table_colnum Nth column, starting at 1, in the table that maps to \a host_colnum.
00403  *  If there is a column in the datafile that does not map to a table column, set \a table_colnum to zero.
00404  *
00405  *\remarks  bcp_colfmt() is called once for each column in the datafile, as specified with bcp_columns().
00406  * In so doing, you describe to FreeTDS how to parse each line of your datafile, and where to send each field.
00407  *
00408  * When a prefix or terminator is used with variable-length data, \a host_collen may have one of three values:
00409  *      - \b positive indicating the maximum number of bytes to be used
00410  *      - \b 0 indicating NULL
00411  *      - \b -1 indicating no maximum; all data, as described by the prefix/terminator will be used.
00412  *      .
00413  * \return SUCCEED or FAIL.
00414  * \sa  bcp_batch(), bcp_bind(), bcp_colfmt_ps(), bcp_collen(), bcp_colptr(), bcp_columns(),
00415  *  bcp_control(), bcp_done(), bcp_exec(), bcp_init(), bcp_sendrow
00416  */
00417 RETCODE
00418 bcp_colfmt(DBPROCESS * dbproc, int host_colnum, int host_type, int host_prefixlen, DBINT host_collen, const BYTE * host_term,
00419        int host_termlen, int table_colnum)
00420 {
00421     BCP_HOSTCOLINFO *hostcol;
00422 
00423     /* Microsoft specifies a "file_termlen" of zero if there's no terminator */
00424     if (dbproc->msdblib && host_termlen == 0)
00425         host_termlen = -1;
00426 
00427     if (dbproc->bcpinfo == NULL) {
00428         dbperror(dbproc, SYBEBCPI, 0);
00429         return FAIL;
00430     }
00431 
00432     if (dbproc->hostfileinfo == NULL) {
00433         dbperror(dbproc, SYBEBIVI, 0);
00434         return FAIL;
00435     }
00436 
00437     if (dbproc->hostfileinfo->host_colcount == 0) {
00438         dbperror(dbproc, SYBEBCBC, 0);
00439         return FAIL;
00440     }
00441 
00442     if (host_colnum < 1)
00443         return FAIL;
00444 
00445     if (host_prefixlen != 0 && host_prefixlen != 1 && host_prefixlen != 2 && host_prefixlen != 4 && host_prefixlen != -1) {
00446         dbperror(dbproc, SYBEBCPREF, 0);
00447         return FAIL;
00448     }
00449 
00450     if (table_colnum <= 0 && host_type == 0) {
00451         dbperror(dbproc, SYBEBCPCTYP, 0);
00452         return FAIL;
00453     }
00454 
00455     if (host_prefixlen == 0 && host_collen == -1 && host_termlen == -1 && !is_fixed_type(host_type)) {
00456         dbperror(dbproc, SYBEVDPT, 0);
00457         return FAIL;
00458     }
00459 
00460     if (host_collen < -1) {
00461         dbperror(dbproc, SYBEBCHLEN, 0);
00462         return FAIL;
00463     }
00464 
00465     /* TODO return error */
00466     if (is_fixed_type(host_type) && (host_collen != -1 && host_collen != 0))
00467         return FAIL;
00468 
00469     /*
00470      * If there's a positive terminator length, we need a valid terminator pointer.
00471      * If the terminator length is 0 or -1, then there's no terminator.
00472      * FIXME: look up the correct error code for a bad terminator pointer or length and return that before arriving here.
00473      */
00474     if (host_termlen > 0 && host_term == NULL)
00475         return FAIL;
00476 
00477     hostcol = dbproc->hostfileinfo->host_columns[host_colnum - 1];
00478 
00479     /* TODO add precision scale and join with bcp_colfmt_ps */
00480     hostcol->host_column = host_colnum;
00481     hostcol->datatype = host_type;
00482     hostcol->prefix_len = host_prefixlen;
00483     hostcol->column_len = host_collen;
00484     if (host_term && host_termlen >= 0) {
00485         hostcol->terminator = (BYTE *) malloc(host_termlen);
00486         memcpy(hostcol->terminator, host_term, host_termlen);
00487     }
00488     hostcol->term_len = host_termlen;
00489     hostcol->tab_colnum = table_colnum;
00490 
00491     return SUCCEED;
00492 }
00493 
00494 /**
00495  * \ingroup dblib_bcp
00496  * \brief Specify the format of a host file for bulk copy purposes,
00497  *  with precision and scale support for numeric and decimal columns.
00498  *
00499  * \param dbproc contains all information needed by db-lib to manage communications with the server.
00500  * \param host_colnum
00501  * \param host_type
00502  * \param etc.
00503  * \todo Not implemented.
00504  *
00505  * \return SUCCEED or FAIL.
00506  * \sa  bcp_batch(), bcp_bind(), bcp_colfmt(), bcp_collen(), bcp_colptr(), bcp_columns(),
00507  *  bcp_control(), bcp_done(), bcp_exec(), bcp_init(), bcp_sendrow
00508  */
00509 RETCODE
00510 bcp_colfmt_ps(DBPROCESS * dbproc, int host_colnum, int host_type,
00511           int host_prefixlen, DBINT host_collen, BYTE * host_term, int host_termlen, int table_colnum, DBTYPEINFO * typeinfo)
00512 {
00513     /* TODO see bcp_colfmt */
00514     if (dbproc->bcpinfo == NULL) {
00515         dbperror(dbproc, SYBEBCPI, 0);
00516         return FAIL;
00517     }
00518     return FAIL;
00519 }
00520 
00521 
00522 
00523 /**
00524  * \ingroup dblib_bcp
00525  * \brief Set BCP options for uploading a datafile
00526  *
00527  * \param dbproc contains all information needed by db-lib to manage communications with the server.
00528  * \param field symbolic constant indicating the option to be set, one of:
00529  *          - \b BCPMAXERRS Maximum errors tolerated before quitting. The default is 10.
00530  *          - \b BCPFIRST The first row to read in the datafile. The default is 1.
00531  *          - \b BCPLAST The last row to read in the datafile. The default is to copy all rows. A value of
00532  *                      -1 resets this field to its default?
00533  *          - \b BCPBATCH The number of rows per batch.  Default is 0, meaning a single batch.
00534  * \param value The value for \a field.
00535  *
00536  * \remarks These options control the behavior of bcp_exec().
00537  * When writing to a table from application host memory variables,
00538  * program logic controls error tolerance and batch size.
00539  *
00540  * \return SUCCEED or FAIL.
00541  * \sa  bcp_batch(), bcp_bind(), bcp_colfmt(), bcp_collen(), bcp_colptr(), bcp_columns(), bcp_done(), bcp_exec(), bcp_options()
00542  */
00543 RETCODE
00544 bcp_control(DBPROCESS * dbproc, int field, DBINT value)
00545 {
00546     if (dbproc->bcpinfo == NULL) {
00547         dbperror(dbproc, SYBEBCPI, 0);
00548         return FAIL;
00549     }
00550 
00551     if (dbproc->hostfileinfo == NULL) {
00552         dbperror(dbproc, SYBEBIVI, 0);
00553         return FAIL;
00554     }
00555 
00556     switch (field) {
00557 
00558     case BCPMAXERRS:
00559         dbproc->hostfileinfo->maxerrs = value;
00560         break;
00561     case BCPFIRST:
00562         dbproc->hostfileinfo->firstrow = value;
00563         break;
00564     case BCPLAST:
00565         dbproc->hostfileinfo->firstrow = value;
00566         break;
00567     case BCPBATCH:
00568         dbproc->hostfileinfo->batch = value;
00569         break;
00570     case BCPKEEPIDENTITY:
00571         dbproc->bcpinfo->identity_insert_on = (value != 0);
00572         break;
00573 
00574     default:
00575         dbperror(dbproc, SYBEIFNB, 0);
00576         return FAIL;
00577     }
00578     return SUCCEED;
00579 }
00580 
00581 /**
00582  * \ingroup dblib_bcp
00583  * \brief Set "hints" for uploading a file.  A FreeTDS-only function.
00584  *
00585  * \param dbproc contains all information needed by db-lib to manage communications with the server.
00586  * \param option symbolic constant indicating the option to be set, one of:
00587  *      - \b BCPLABELED Not implemented.
00588  *      - \b BCPHINTS The hint to be passed when the bulk-copy begins.
00589  * \param value The string constant for \a option a/k/a the hint.  One of:
00590  *      - \b ORDER The data are ordered in accordance with the table's clustered index.
00591  *      - \b ROWS_PER_BATCH The batch size
00592  *      - \b KILOBYTES_PER_BATCH The approximate number of kilobytes to use for a batch size
00593  *      - \b TABLOCK Lock the table
00594  *      - \b CHECK_CONSTRAINTS Apply constraints
00595  * \param valuelen The strlen of \a value.
00596  *
00597  * \return SUCCEED or FAIL.
00598  * \sa  bcp_control(),
00599  *  bcp_exec(),
00600  * \todo Simplify.  Remove \a valuelen, and dbproc->bcpinfo->hint = strdup(hints[i])
00601  */
00602 RETCODE
00603 bcp_options(DBPROCESS * dbproc, int option, BYTE * value, int valuelen)
00604 {
00605     int i;
00606     static const char *const hints[] = {
00607         "ORDER", "ROWS_PER_BATCH", "KILOBYTES_PER_BATCH", "TABLOCK", "CHECK_CONSTRAINTS", NULL
00608     };
00609 
00610     if (!dbproc)
00611         return FAIL;
00612 
00613     if (dbproc->bcpinfo == NULL) {
00614         dbperror(dbproc, SYBEBCPI, 0);
00615         return FAIL;
00616     }
00617 
00618     switch (option) {
00619     case BCPLABELED:
00620         tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED bcp option: BCPLABELED\n");
00621         return FAIL;
00622     case BCPHINTS:
00623         if (!value || valuelen <= 0)
00624             return FAIL;
00625 
00626         /* TODO return error ?? */
00627         if (dbproc->bcpinfo->hint != NULL)  /* hint already set */
00628             return FAIL;
00629 
00630         for (i = 0; hints[i]; i++) {    /* do we know about this hint? */
00631             /* Does not matter if value is not null terminated; strlen(hints[i]) refers to a static constant, above */
00632             if (strncasecmp((char *) value, hints[i], strlen(hints[i])) == 0)
00633                 break;
00634         }
00635         if (!hints[i]) {    /* no such hint */
00636             return FAIL;
00637         }
00638 
00639         /*
00640          * Store the bare hint, as passed from the application.
00641          * The process that constructs the "insert bulk" statement will incorporate the hint text.
00642          */
00643         dbproc->bcpinfo->hint = (char *) malloc(1 + valuelen);
00644         if (!dbproc->bcpinfo->hint) {
00645             dbperror(dbproc, SYBEMEM, errno);
00646             return FAIL;
00647         }
00648         memcpy(dbproc->bcpinfo->hint, value, valuelen);
00649         dbproc->bcpinfo->hint[valuelen] = '\0'; /* null terminate it */
00650         break;
00651     default:
00652         tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED bcp option: %u\n", option);
00653         return FAIL;
00654     }
00655 
00656     return SUCCEED;
00657 }
00658 
00659 /**
00660  * \ingroup dblib_bcp
00661  * \brief Override bcp_bind() by pointing to a different host variable.
00662  *
00663  * \param dbproc contains all information needed by db-lib to manage communications with the server.
00664  * \param colptr The pointer, the address of your variable.
00665  * \param table_column The 1-based column ordinal in the table.
00666  * \remarks Use between calls to bcp_sendrow().  After calling bcp_colptr(),
00667  *      subsequent calls to bcp_sendrow() will bind to the new address.
00668  * \return SUCCEED or FAIL.
00669  * \sa  bcp_bind(), bcp_collen(), bcp_sendrow()
00670  */
00671 RETCODE
00672 bcp_colptr(DBPROCESS * dbproc, BYTE * colptr, int table_column)
00673 {
00674     TDSCOLUMN *curcol;
00675 
00676     /* TODO check bindinfo too ?? */
00677 
00678     if (dbproc->bcpinfo == NULL || dbproc->bcpinfo->bindinfo == NULL) {
00679         dbperror(dbproc, SYBEBCPI, 0);
00680         return FAIL;
00681     }
00682     if (dbproc->bcpinfo->direction != DB_IN) {
00683         dbperror(dbproc, SYBEBCPN, 0);
00684         return FAIL;
00685     }
00686 
00687     if (table_column <= 0 || table_column > dbproc->bcpinfo->bindinfo->num_cols)
00688         return FAIL;
00689 
00690     curcol = dbproc->bcpinfo->bindinfo->columns[table_column - 1];
00691     curcol->column_varaddr = (TDS_CHAR *)colptr;
00692 
00693     return SUCCEED;
00694 }
00695 
00696 
00697 /**
00698  * \ingroup dblib_bcp
00699  * \brief See if BCP_SETL() was used to set the LOGINREC for BCP work.
00700  *
00701  * \param login Address of the LOGINREC variable to be passed to dbopen().
00702  *
00703  * \return TRUE or FALSE.
00704  * \sa  BCP_SETL(), bcp_init(), dblogin(), dbopen()
00705  */
00706 DBBOOL
00707 bcp_getl(LOGINREC * login)
00708 {
00709     TDSLOGIN *tdsl = login->tds_login;
00710 
00711     return (tdsl->bulk_copy);
00712 }
00713 
00714 /**
00715  * \ingroup dblib_bcp_internal
00716  * \brief
00717  *
00718  *
00719  * \param dbproc contains all information needed by db-lib to manage communications with the server.
00720  * \param rows_copied
00721  *
00722  * \return SUCCEED or FAIL.
00723  * \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()
00724  */
00725 static RETCODE
00726 _bcp_exec_out(DBPROCESS * dbproc, DBINT * rows_copied)
00727 {
00728 
00729     FILE *hostfile;
00730     int i;
00731 
00732     TDSSOCKET *tds;
00733     TDSRESULTINFO *resinfo;
00734     TDSCOLUMN *curcol = NULL;
00735     BCP_HOSTCOLINFO *hostcol;
00736     BYTE *src;
00737     int srctype;
00738     int srclen;
00739     int buflen;
00740     int destlen;
00741     int plen;
00742 
00743     TDS_INT result_type;
00744 
00745     TDS_TINYINT ti;
00746     TDS_SMALLINT si;
00747     TDS_INT li;
00748 
00749     TDSDATEREC when;
00750 
00751     int row_of_query;
00752     int rows_written;
00753     char *bcpdatefmt = NULL;
00754     int tdsret;
00755 
00756     tds = dbproc->tds_socket;
00757     assert(tds);
00758 
00759     if (!(hostfile = fopen(dbproc->hostfileinfo->hostfile, "w"))) {
00760         dbperror(dbproc, SYBEBCUO, errno);
00761         return FAIL;
00762     }
00763 
00764     bcpdatefmt = getenv("FREEBCP_DATEFMT");
00765 
00766     if (dbproc->bcpinfo->direction == DB_QUERYOUT ) {
00767         if (tds_submit_query(tds, dbproc->bcpinfo->tablename) == TDS_FAIL) {
00768             return FAIL;
00769         }
00770     } else {
00771         /* TODO quote if needed */
00772         if (tds_submit_queryf(tds, "select * from %s", dbproc->bcpinfo->tablename)
00773             == TDS_FAIL) {
00774             return FAIL;
00775         }
00776     }
00777 
00778     tdsret = tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS);
00779     if (tdsret == TDS_FAIL || tdsret == TDS_CANCELLED) {
00780         fclose(hostfile);
00781         return FAIL;
00782     }
00783     if (!tds->res_info) {
00784         /* TODO flush/cancel to keep consistent state */
00785         fclose(hostfile);
00786         return FAIL;
00787     }
00788 
00789     resinfo = tds->res_info;
00790 
00791     row_of_query = 0;
00792     rows_written = 0;
00793 
00794     /*
00795      * before we start retrieving the data, go through the defined
00796      * host file columns. If the host file column is related to a
00797      * table column, then allocate some space sufficient to hold
00798      * the resulting data (converted to whatever host file format)
00799      */
00800 
00801     for (i = 0; i < dbproc->hostfileinfo->host_colcount; i++) {
00802 
00803         hostcol = dbproc->hostfileinfo->host_columns[i];
00804         if (hostcol->tab_colnum < 1 || hostcol->tab_colnum > resinfo->num_cols)
00805             continue;
00806 
00807         curcol = resinfo->columns[hostcol->tab_colnum - 1];
00808 
00809         if (hostcol->datatype == 0)
00810             hostcol->datatype = curcol->column_type;
00811 
00812         /* work out how much space to allocate for output data */
00813 
00814         /* TODO use a function for fixed types */
00815         switch (hostcol->datatype) {
00816 
00817         case SYBINT1:
00818             buflen = destlen = 1;
00819             break;
00820         case SYBINT2:
00821             buflen = destlen = 2;
00822             break;
00823         case SYBINT4:
00824             buflen = destlen = 4;
00825             break;
00826         case SYBINT8:
00827             buflen = destlen = 8;
00828             break;
00829         case SYBREAL:
00830             buflen = destlen = 4;
00831             break;
00832         case SYBFLT8:
00833             buflen = destlen = 8;
00834             break;
00835         case SYBDATETIME:
00836             buflen = destlen = 8;
00837             break;
00838         case SYBDATETIME4:
00839             buflen = destlen = 4;
00840             break;
00841         case SYBBIT:
00842             buflen = destlen = 1;
00843             break;
00844         case SYBBITN:
00845             buflen = destlen = 1;
00846             break;
00847         case SYBMONEY:
00848             buflen = destlen = 8;
00849             break;
00850         case SYBMONEY4:
00851             buflen = destlen = 4;
00852             break;
00853         case SYBCHAR:
00854         case SYBVARCHAR:
00855             switch (curcol->column_type) {
00856             case SYBVARCHAR:
00857                 buflen = curcol->column_size + 1;
00858                 destlen = -1;
00859                 break;
00860             case SYBCHAR:
00861                 buflen = curcol->column_size + 1;
00862                 if (curcol->column_nullable)
00863                     destlen = -1;
00864                 else
00865                     destlen = -2;
00866                 break;
00867             case SYBTEXT:
00868                 /* FIXME column_size ?? if 2gb ?? */
00869                 buflen = curcol->column_size + 1;
00870                 destlen = -2;
00871                 break;
00872             case SYBINT1:
00873                 buflen = 4 + 1; /*  255         */
00874                 destlen = -1;
00875                 break;
00876             case SYBINT2:
00877                 buflen = 6 + 1; /* -32768       */
00878                 destlen = -1;
00879                 break;
00880             case SYBINT4:
00881                 buflen = 11 + 1;    /* -2147483648  */
00882                 destlen = -1;
00883                 break;
00884             case SYBINT8:
00885                 buflen = 20 + 1;    /* -9223372036854775808  */
00886                 destlen = -1;
00887                 break;
00888             case SYBNUMERIC:
00889             case SYBDECIMAL:
00890                 buflen = 40 + 1;    /* 10 to the 38 */
00891                 destlen = -1;
00892                 break;
00893             case SYBFLT8:
00894                 buflen = 40 + 1;    /* 10 to the 38 */
00895                 destlen = -1;
00896                 break;
00897             case SYBDATETIME:
00898             case SYBDATETIME4:
00899                 buflen = 255 + 1;
00900                 destlen = -1;
00901                 break;
00902             default:
00903                 buflen = 255 + 1;
00904                 destlen = -1;
00905                 break;
00906             }
00907             break;
00908         default:
00909             buflen = destlen = 255;
00910         }
00911 
00912         hostcol->bcp_column_data = tds_alloc_bcp_column_data(buflen);
00913         hostcol->bcp_column_data->datalen = destlen;
00914     }
00915 
00916     /* fetch a row of data from the server */
00917 
00918     /*
00919      * TODO above we allocate many buffer just to convert and store
00920      * to file.. avoid all that passages...
00921      */
00922 
00923     while (tds_process_tokens(tds, &result_type, NULL, TDS_STOPAT_ROWFMT|TDS_RETURN_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE) == TDS_SUCCEED) {
00924 
00925         if (result_type != TDS_ROW_RESULT && result_type != TDS_COMPUTE_RESULT)
00926             break;
00927 
00928         row_of_query++;
00929 
00930         /* skip rows outside of the firstrow/lastrow range , if specified */
00931         if (dbproc->hostfileinfo->firstrow <= row_of_query &&
00932                               row_of_query <= MAX(dbproc->hostfileinfo->lastrow, 0x7FFFFFFF)) {
00933 
00934             /* Go through the hostfile columns, finding those that relate to database columns. */
00935             for (i = 0; i < dbproc->hostfileinfo->host_colcount; i++) {
00936         
00937                 hostcol = dbproc->hostfileinfo->host_columns[i];
00938                 if (hostcol->tab_colnum < 1 || hostcol->tab_colnum > resinfo->num_cols) {
00939                     continue;
00940                 }
00941         
00942                 curcol = resinfo->columns[hostcol->tab_colnum - 1];
00943 
00944                 src = &resinfo->current_row[curcol->column_offset];
00945 
00946                 if (is_blob_type(curcol->column_type)) {
00947                     src = (BYTE *) ((TDSBLOB *) src)->textvalue;
00948                 }
00949 
00950                 srctype = tds_get_conversion_type(curcol->column_type, curcol->column_size);
00951 
00952                 if (curcol->column_cur_size < 0) {
00953                     srclen = 0;
00954                     hostcol->bcp_column_data->null_column = 1;
00955                 } else {
00956                     if (is_numeric_type(curcol->column_type))
00957                         srclen = sizeof(TDS_NUMERIC);
00958                     else
00959                         srclen = curcol->column_cur_size;
00960                     hostcol->bcp_column_data->null_column = 0;
00961                 }
00962 
00963                 if (hostcol->bcp_column_data->null_column) {
00964                     buflen = 0;
00965                 } else {
00966 
00967                     /*
00968                      * if we are converting datetime to string, need to override any
00969                      * date time formats already established
00970                      */
00971                     if ((srctype == SYBDATETIME || srctype == SYBDATETIME4)
00972                         && (hostcol->datatype == SYBCHAR || hostcol->datatype == SYBVARCHAR)) {
00973                         tds_datecrack(srctype, src, &when);
00974                         if (bcpdatefmt)
00975                             buflen = tds_strftime((TDS_CHAR *)hostcol->bcp_column_data->data, 256, bcpdatefmt, &when);
00976                         else
00977                             buflen = tds_strftime((TDS_CHAR *)hostcol->bcp_column_data->data, 256, "%Y-%m-%d %H:%M:%S.%z", &when);
00978                     } else {
00979                         /*
00980                          * For null columns, the above work to determine the output buffer size is moot,
00981                          * because bcpcol->data_size is zero, so dbconvert() won't write anything, and returns zero.
00982                          */
00983                         /* TODO check for text !!! */
00984                         buflen =  dbconvert(dbproc, srctype, src, srclen, hostcol->datatype,
00985                                     hostcol->bcp_column_data->data, hostcol->bcp_column_data->datalen);
00986                         /*
00987                          * Special case:  When outputting database varchar data
00988                          * (either varchar or nullable char) dbconvert may have
00989                          * trimmed trailing blanks such that nothing is left.
00990                          * In this case we need to put a single blank to the output file.
00991                          */
00992                         if (( curcol->column_type == SYBVARCHAR ||
00993                              (curcol->column_type == SYBCHAR && curcol->column_nullable)
00994                             ) && srclen > 0 && buflen == 0) {
00995                             strcpy ((char *)hostcol->bcp_column_data->data, " ");
00996                             buflen = 1;
00997                         }
00998                     }
00999                 }
01000 
01001                 /* The prefix */
01002                 if ((plen = hostcol->prefix_len) == -1) {
01003                     if (is_blob_type(hostcol->datatype))
01004                         plen = 4;
01005                     else if (!(is_fixed_type(hostcol->datatype)))
01006                         plen = 2;
01007                     else if (curcol->column_nullable)
01008                         plen = 1;
01009                     else
01010                         plen = 0;
01011                     /* cache */
01012                     hostcol->prefix_len = plen;
01013                 }
01014                 switch (plen) {
01015                 case 0:
01016                     break;
01017                 case 1:
01018                     ti = buflen;
01019                     fwrite(&ti, sizeof(ti), 1, hostfile);
01020                     break;
01021                 case 2:
01022                     si = buflen;
01023                     fwrite(&si, sizeof(si), 1, hostfile);
01024                     break;
01025                 case 4:
01026                     li = buflen;
01027                     fwrite(&li, sizeof(li), 1, hostfile);
01028                     break;
01029                 }
01030 
01031                 /* The data */
01032                 if (hostcol->column_len != -1) {
01033                     buflen = buflen > hostcol->column_len ? hostcol->column_len : buflen;
01034                 }
01035 
01036                 if (buflen > 0)
01037                     fwrite(hostcol->bcp_column_data->data, buflen, 1, hostfile);
01038 
01039                 /* The terminator */
01040                 if (hostcol->terminator && hostcol->term_len > 0) {
01041                     fwrite(hostcol->terminator, hostcol->term_len, 1, hostfile);
01042                 }
01043             }
01044             rows_written++;
01045         }
01046     }
01047     if (fclose(hostfile) != 0) {
01048         dbperror(dbproc, SYBEBCUC, errno);
01049         return (FAIL);
01050     }
01051 
01052     if (dbproc->hostfileinfo->firstrow > 0 && row_of_query < dbproc->hostfileinfo->firstrow) {
01053         /*
01054          * The table which bulk-copy is attempting to
01055          * copy to a host-file is shorter than the
01056          * number of rows which bulk-copy was instructed to skip.
01057          */
01058         /* TODO reset TDSSOCKET state */
01059         dbperror(dbproc, SYBETTS, 0);
01060         return (FAIL);
01061     }
01062 
01063     *rows_copied = rows_written;
01064     return SUCCEED;
01065 }
01066 
01067 static RETCODE
01068 _bcp_check_eof(DBPROCESS * dbproc, FILE *file, int icol)
01069 {
01070     int errnum = errno;
01071 
01072     if (feof(file)) {
01073         if (icol == 0) {
01074             tdsdump_log(TDS_DBG_FUNC, "Normal end-of-file reached while loading bcp data file.\n");
01075             return (NO_MORE_ROWS);
01076         }
01077         dbperror(dbproc, SYBEBEOF, errnum);
01078         return (FAIL);
01079     }
01080     dbperror(dbproc, SYBEBCRE, errnum);
01081     return (FAIL);
01082 }
01083 
01084 /**
01085  * \ingroup dblib_bcp_internal
01086  * \brief
01087  * \param dbproc contains all information needed by db-lib to manage communications with the server.
01088  * \param hostfile
01089  * \param row_error
01090  *
01091  * \return MORE_ROWS, NO_MORE_ROWS, or FAIL.
01092  * \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()
01093  */
01094 static RETCODE
01095 _bcp_read_hostfile(DBPROCESS * dbproc, FILE * hostfile, int *row_error)
01096 {
01097     TDSCOLUMN *bcpcol = NULL;
01098     BCP_HOSTCOLINFO *hostcol;
01099 
01100     TDS_TINYINT ti;
01101     TDS_SMALLINT si;
01102     TDS_INT li;
01103     TDS_INT desttype;
01104     BYTE *coldata;
01105 
01106     int i, collen, data_is_null;
01107 
01108     /* for each host file column defined by calls to bcp_colfmt */
01109 
01110     for (i = 0; i < dbproc->hostfileinfo->host_colcount; i++) {
01111         tdsdump_log(TDS_DBG_FUNC, "parsing host column %d\n", i + 1);
01112         hostcol = dbproc->hostfileinfo->host_columns[i];
01113 
01114         data_is_null = 0;
01115         collen = 0;
01116         hostcol->column_error = 0;
01117 
01118         /*
01119          * If this host file column contains table data,
01120          * find the right element in the table/column list.
01121          */
01122 
01123         /* FIXME I think tab_colnum can be out of range - freddy77 */
01124         if (hostcol->tab_colnum) {
01125             bcpcol = dbproc->bcpinfo->bindinfo->columns[hostcol->tab_colnum - 1];
01126         }
01127 
01128         /* detect prefix len */
01129         if (bcpcol && hostcol->prefix_len == -1) {
01130             hostcol->prefix_len = bcpcol->column_varint_size;
01131         }
01132 
01133         /* a prefix length, if extant, specifies how many bytes to read */
01134         if (hostcol->prefix_len > 0) {
01135 
01136             switch (hostcol->prefix_len) {
01137             case 1:
01138                 if (fread(&ti, 1, 1, hostfile) != 1)
01139                     return _bcp_check_eof(dbproc, hostfile, i);
01140                 collen = ti ? ti : -1;
01141                 break;
01142             case 2:
01143                 if (fread(&si, 2, 1, hostfile) != 1)
01144                     return _bcp_check_eof(dbproc, hostfile, i);
01145                 collen = si;
01146                 break;
01147             case 4:
01148                 if (fread(&li, 4, 1, hostfile) != 1)
01149                     return _bcp_check_eof(dbproc, hostfile, i);
01150                 collen = li;
01151                 break;
01152             default:
01153                 /* FIXME return error, remember that prefix_len can be 3 */
01154                 assert(hostcol->prefix_len <= 4);
01155                 break;
01156             }
01157 
01158             /* TODO test all NULL types */
01159             /* TODO for < -1 error */
01160             if (collen <= -1) {
01161                 data_is_null = 1;
01162                 collen = 0;
01163             }
01164         }
01165 
01166         /* if (Max) column length specified take that into consideration. (Meaning what, exactly?) */
01167 
01168         if (!data_is_null && hostcol->column_len >= 0) {
01169             if (hostcol->column_len == 0)
01170                 data_is_null = 1;
01171             else {
01172                 if (collen)
01173                     collen = (hostcol->column_len < collen) ? hostcol->column_len : collen;
01174                 else
01175                     collen = hostcol->column_len;
01176             }
01177         }
01178 
01179         tdsdump_log(TDS_DBG_FUNC, "prefix_len = %d collen = %d \n", hostcol->prefix_len, collen);
01180 
01181         /* Fixed Length data - this overrides anything else specified */
01182 
01183         if (is_fixed_type(hostcol->datatype)) {
01184             collen = tds_get_size_by_type(hostcol->datatype);
01185         }
01186 
01187         /*
01188          * The data file either contains prefixes stating the length, or is delimited.
01189          * If delimited, we "measure" the field by looking for the terminator, then read it,
01190          * and set collen to the field's post-iconv size.
01191          */
01192         if (hostcol->term_len > 0) { /* delimited data file */
01193             int file_bytes_left, file_len;
01194             size_t col_bytes_left;
01195             offset_type len;
01196             iconv_t cd;
01197 
01198             len = _bcp_measure_terminated_field(hostfile, hostcol->terminator, hostcol->term_len);
01199             if (len > 0x7fffffffl || len < 0) {
01200                 *row_error = TRUE;
01201                 tdsdump_log(TDS_DBG_FUNC, "_bcp_measure_terminated_field returned -1!\n");
01202                 /* FIXME emit message? dbperror(dbproc, SYBEMEM, 0); */
01203                 return (FAIL);
01204             }
01205             collen = len;
01206             if (collen == 0)
01207                 data_is_null = 1;
01208 
01209 
01210             tdsdump_log(TDS_DBG_FUNC, "_bcp_measure_terminated_field returned %d\n", collen);
01211             /*
01212              * Allocate a column buffer guaranteed to be big enough hold the post-iconv data.
01213              */
01214             file_len = collen;
01215             if (bcpcol->char_conv) {
01216                 if (bcpcol->on_server.column_size > bcpcol->column_size)
01217                     collen = (collen * bcpcol->on_server.column_size) / bcpcol->column_size;
01218                 cd = bcpcol->char_conv->to_wire;
01219                 tdsdump_log(TDS_DBG_FUNC, "Adjusted collen is %d.\n", collen);
01220 
01221             } else {
01222                 cd = (iconv_t) - 1;
01223             }
01224 
01225             coldata = (BYTE *) calloc(1, 1 + collen);
01226             if (coldata == NULL) {
01227                 *row_error = TRUE;
01228                 tdsdump_log(TDS_DBG_FUNC, "calloc returned NULL pointer!\n");
01229                 dbperror(dbproc, SYBEMEM, errno);
01230                 return (FAIL);
01231             }
01232 
01233             /*
01234              * Read and convert the data
01235              */
01236             col_bytes_left = collen;
01237             /* TODO make tds_iconv_fread handle terminator directly to avoid fseek in _bcp_measure_terminated_field */
01238             file_bytes_left = tds_iconv_fread(cd, hostfile, file_len, hostcol->term_len, (TDS_CHAR *)coldata, &col_bytes_left);
01239             collen -= col_bytes_left;
01240 
01241             /* tdsdump_log(TDS_DBG_FUNC, "collen is %d after tds_iconv_fread()\n", collen); */
01242 
01243             if (file_bytes_left != 0) {
01244                 tdsdump_log(TDS_DBG_FUNC, "col %d: %d of %d bytes unread\nfile_bytes_left != 0!\n",
01245                             (i+1), file_bytes_left, collen);
01246                 *row_error = TRUE;
01247                 free(coldata);
01248                 return FAIL;
01249             }
01250 
01251             /*
01252              * TODO:
01253              *    Dates are a problem.  In theory, we should be able to read non-English dates, which
01254              *    would contain non-ASCII characters.  One might suppose we should convert date
01255              *    strings to ISO-8859-1 (or another canonical form) here, because tds_convert() can't be
01256              *    expected to deal with encodings. But instead date strings are read verbatim and
01257              *    passed to tds_convert() without even waving to iconv().  For English dates, this works,
01258              *    because English dates expressed as UTF-8 strings are indistinguishable from the ASCII.
01259              */
01260         } else {    /* unterminated field */
01261 #if 0
01262             bcpcol = dbproc->bcpinfo->bindinfo->columns[hostcol->tab_colnum - 1];
01263             if (collen == 0 || bcpcol->column_nullable) {
01264                 if (collen != 0) {
01265                     /* A fixed length type */
01266                     TDS_TINYINT len;
01267                     if (fread(&len, sizeof(len), 1, hostfile) != 1) {
01268                         if (i != 0)
01269                             dbperror(dbproc, SYBEBCRE, errno);
01270                         return (FAIL);
01271                     }
01272                     /* TODO 255 for NULL ?? check it, perhaps 0 */
01273                     collen = len == 255 ? -1 : len;
01274                 } else {
01275                     TDS_SMALLINT len;
01276 
01277                     if (fread(&len, sizeof(len), 1, hostfile) != 1) {
01278                         if (i != 0)
01279                             dbperror(dbproc, SYBEBCRE, errno);
01280                         return (FAIL);
01281                     }
01282                     collen = len;
01283                 }
01284                 /* TODO if collen < -1 error */
01285                 if (collen <= -1) {
01286                     collen = 0;
01287                     data_is_null = 1;
01288                 }
01289 
01290                 tdsdump_log(TDS_DBG_FUNC, "Length read from hostfile: collen is now %d, data_is_null is %d\n", collen, data_is_null);
01291             }
01292 #endif
01293 
01294             coldata = (BYTE *) calloc(1, 1 + collen);
01295             if (coldata == NULL) {
01296                 *row_error = TRUE;
01297                 dbperror(dbproc, SYBEMEM, errno);
01298                 return (FAIL);
01299             }
01300 
01301             if (collen) {
01302                 /*
01303                  * Read and convert the data
01304                  * TODO: Call tds_iconv_fread() instead of fread(3).
01305                  *       The columns should each have their iconv cd set, and noncharacter data
01306                  *       should have -1 as the iconv cd, causing tds_iconv_fread() to not attempt
01307                  *   any conversion.  We do not need a datatype switch here to decide what to do.
01308                  *   As of 0.62, this *should* actually work.  All that remains is to change the
01309                  *   call and test it.
01310                  */
01311                 tdsdump_log(TDS_DBG_FUNC, "Reading %d bytes from hostfile.\n", collen);
01312                 if (fread(coldata, collen, 1, hostfile) != 1) {
01313                     free(coldata);
01314                     return _bcp_check_eof(dbproc, hostfile, i);
01315                 }
01316             }
01317         }
01318 
01319         /*
01320          * If we read no bytes and we're at end of file AND this is the first column,
01321          * then we've stumbled across the finish line.  Tell the caller we failed to read
01322          * anything but encountered no error.
01323          */
01324         if (i == 0 && collen == 0 && feof(hostfile)) {
01325             free(coldata);
01326             tdsdump_log(TDS_DBG_FUNC, "Normal end-of-file reached while loading bcp data file.\n");
01327             return NO_MORE_ROWS;
01328         }
01329 
01330         /*
01331          * At this point, however the field was read, however big it was, its address is coldata and its size is collen.
01332          */
01333         tdsdump_log(TDS_DBG_FUNC, "Data read from hostfile: collen is now %d, data_is_null is %d\n", collen, data_is_null);
01334         if (hostcol->tab_colnum) {
01335             if (data_is_null) {
01336                 bcpcol->bcp_column_data->null_column = 1;
01337                 bcpcol->bcp_column_data->datalen = 0;
01338             } else {
01339                 bcpcol->bcp_column_data->null_column = 0;
01340                 desttype = tds_get_conversion_type(bcpcol->column_type, bcpcol->column_size);
01341 
01342                 /* special hack for text columns */
01343 
01344                 if (bcpcol->column_size == 4096 && collen > bcpcol->column_size) {  /* "4096" might not really matter */
01345                     BYTE *oldbuffer = bcpcol->bcp_column_data->data;
01346                     switch (desttype) {
01347                     case SYBTEXT:
01348                     case SYBNTEXT:
01349                     case SYBIMAGE:
01350                     case SYBVARBINARY:
01351                     case XSYBVARBINARY:
01352                     case SYBLONGBINARY: /* Reallocate enough space for the data from the file. */
01353                         bcpcol->column_size = 8 + collen;   /* room to breathe */
01354                         bcpcol->bcp_column_data->data = (BYTE *) realloc(bcpcol->bcp_column_data->data, bcpcol->column_size);
01355                         if (!bcpcol->bcp_column_data->data) {
01356                             dbperror(dbproc, SYBEMEM, errno);
01357                             free(oldbuffer);
01358                             free(coldata);
01359                             return FAIL;
01360                         }
01361                         break;
01362                     default:
01363                         break;
01364                     }
01365                 }
01366                 /* end special hack for text columns */
01367 
01368                 /*
01369                  * FIXME bcpcol->bcp_column_data->data && bcpcol->column_size ??
01370                  * It seems a buffer overflow waiting...
01371                  */
01372                 bcpcol->bcp_column_data->datalen =
01373                     dbconvert(dbproc, hostcol->datatype, coldata, collen, desttype, bcpcol->bcp_column_data->data, bcpcol->column_size);
01374 
01375                 if (bcpcol->bcp_column_data->datalen == -1) {
01376                     hostcol->column_error = HOST_COL_CONV_ERROR;
01377                     *row_error = 1;
01378                     /* FIXME possible integer overflow if off_t is 64bit and long int 32bit */
01379                     tdsdump_log(TDS_DBG_FUNC,
01380                             "_bcp_read_hostfile failed to convert %d bytes at offset 0x%lx in the data file.\n",
01381                             collen, (unsigned long int) ftello(hostfile) - collen);
01382                 }
01383 
01384                 /* trim trailing blanks from character data */
01385                 if (desttype == SYBCHAR || desttype == SYBVARCHAR) {
01386                     bcpcol->bcp_column_data->datalen = rtrim((char *) bcpcol->bcp_column_data->data, bcpcol->bcp_column_data->datalen);
01387                 }
01388             }
01389             /* Disabled by ssikorsk */
01390             /* Collumn can have a default value */
01391             if (0 && !hostcol->column_error) {
01392                 if (bcpcol->bcp_column_data->datalen <= 0) {    /* Are we trying to insert a NULL ? */
01393                     if (!bcpcol->column_nullable) {
01394                         /* too bad if the column is not nullable */
01395                         hostcol->column_error = HOST_COL_NULL_ERROR;
01396                         *row_error = 1;
01397                         dbperror(dbproc, SYBEBCNN, 0);
01398                     }
01399                 }
01400             }
01401         }
01402         free(coldata);
01403     }
01404     return MORE_ROWS;
01405 }
01406 
01407 /*
01408  * Look for the next terminator in a host data file, and return the data size.
01409  * \return size of field, excluding the terminator.
01410  * \remarks The current offset will be unchanged.  If an error was encountered, the returned size will be -1.
01411  *  The caller should check for that possibility, but the appropriate message should already have been emitted.
01412  *  The caller can then use tds_iconv_fread() to read-and-convert the file's data
01413  *  into host format, or, if we're not dealing with a character column, just fread(3).
01414  */
01415 /**
01416  * \ingroup dblib_bcp_internal
01417  * \brief
01418  * \param hostfile
01419  * \param terminator
01420  * \param term_len
01421  *
01422  * \return SUCCEED or FAIL.
01423  * \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()
01424  */
01425 static offset_type
01426 _bcp_measure_terminated_field(FILE * hostfile, BYTE * terminator, int term_len)
01427 {
01428     char *sample;
01429     int errnum;
01430     int sample_size, bytes_read = 0;
01431     offset_type size;
01432 
01433     const offset_type initial_offset = ftello(hostfile);
01434 
01435     sample = malloc(term_len);
01436 
01437     if (!sample) {
01438         dbperror(NULL, SYBEMEM, errno);
01439         return -1;
01440     }
01441 
01442     for (sample_size = 1; (bytes_read = fread(sample, sample_size, 1, hostfile)) != 0;) {
01443 
01444         bytes_read *= sample_size;
01445 
01446         /*
01447          * Check for terminator.
01448          */
01449         /*
01450          * TODO use memchr for performance,
01451          * optimize this strange loop - freddy77
01452          */
01453         if (*sample == *terminator) {
01454             int found = 0;
01455 
01456             if (sample_size == term_len) {
01457                 /*
01458                  * If we read a whole terminator, compare the whole sequence and, if found, go home.
01459                  */
01460                 found = 0 == memcmp(sample, terminator, term_len);
01461 
01462                 if (found) {
01463                     free(sample);
01464                     size = ftello(hostfile) - initial_offset;
01465                     if (size < 0 || 0 != fseeko(hostfile, initial_offset, SEEK_SET)) {
01466                         /* FIXME emit message */
01467                         return -1;
01468                     }
01469                     return size - term_len;
01470                 }
01471                 /*
01472                  * If we tried to read a terminator and found something else, then we read a
01473                  * terminator's worth of data.  Back up N-1 bytes, and revert to byte-at-a-time testing.
01474                  */
01475                 if (sample_size > 1) {
01476                     sample_size--;
01477                     if (0 != fseeko(hostfile, -sample_size, SEEK_CUR)) {
01478                         /* FIXME emit message */
01479                         return -1;
01480                     }
01481                 }
01482                 sample_size = 1;
01483                 continue;
01484             } else {
01485                 /*
01486                  * Found start of terminator, but haven't read a full terminator's length yet.
01487                  * Back up, read a whole terminator, and try again.
01488                  */
01489                 assert(bytes_read == 1);
01490                 ungetc(*sample, hostfile);
01491                 sample_size = term_len;
01492                 continue;
01493             }
01494             assert(0); /* should not arrive here */
01495         }
01496     }
01497 
01498     free(sample);
01499 
01500     /*
01501      * To get here, we ran out of memory, or encountered an error (or EOF) with the file.
01502      * EOF is a surprise, because if we read a complete field with its terminator,
01503      * we would have returned without attempting to read past end of file.
01504      */
01505 
01506     if (feof(hostfile)) {
01507         errnum = errno;
01508         if (initial_offset == ftello(hostfile)) {
01509             return 0;
01510         } else {
01511             /* a cheat: we don't have dbproc, so pass zero */
01512             dbperror(0, SYBEBEOF, errnum);
01513         }
01514     } else if (ferror(hostfile)) {
01515         dbperror(0, SYBEBCRE, errno);
01516     }
01517 
01518     return -1;
01519 }
01520 
01521 /**
01522  * Add fixed size columns to the row
01523  */
01524 /**
01525  * \ingroup dblib_bcp_internal
01526  * \brief
01527  * \param dbproc contains all information needed by db-lib to manage communications with the server.
01528  * \param behaviour
01529  * \param rowbuffer
01530  * \param start
01531  *
01532  * \return SUCCEED or FAIL.
01533  * \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()
01534  */
01535 static int
01536 _bcp_add_fixed_columns(DBPROCESS * dbproc, int behaviour, BYTE * rowbuffer, int start)
01537 {
01538     TDS_NUMERIC *num;
01539     int row_pos = start;
01540     TDSCOLUMN *bcpcol;
01541     int cpbytes;
01542 
01543     int i, j;
01544 
01545     for (i = 0; i < dbproc->bcpinfo->bindinfo->num_cols; i++) {
01546 
01547         bcpcol = dbproc->bcpinfo->bindinfo->columns[i];
01548 
01549         if (!is_nullable_type(bcpcol->column_type) && !(bcpcol->column_nullable)) {
01550 
01551             tdsdump_log(TDS_DBG_FUNC, "_bcp_add_fixed_columns column %d is a fixed column\n", i + 1);
01552 
01553             if (behaviour == BCP_REC_FETCH_DATA) {
01554                 if ((_bcp_get_col_data(dbproc, bcpcol)) != SUCCEED) {
01555                     tdsdump_log(TDS_DBG_INFO1, "bcp_get_colData (column %d) failed\n", i + 1);
01556                     return FAIL;
01557                 }
01558             }
01559 
01560             if (bcpcol->bcp_column_data->null_column) {
01561                 dbperror(dbproc, SYBEBCNN, 0);
01562                 return FAIL;
01563             }
01564 
01565             if (is_numeric_type(bcpcol->column_type)) {
01566                 num = (TDS_NUMERIC *) bcpcol->bcp_column_data->data;
01567                 cpbytes = tds_numeric_bytes_per_prec[num->precision];
01568                 memcpy(&rowbuffer[row_pos], num->array, cpbytes);
01569             } else {
01570                 cpbytes = bcpcol->bcp_column_data->datalen > bcpcol->column_size ? bcpcol->column_size : bcpcol->bcp_column_data->datalen;
01571                 memcpy(&rowbuffer[row_pos], bcpcol->bcp_column_data->data, cpbytes);
01572 
01573                 /* CHAR data may need padding out to the database length with blanks */
01574 
01575                 if (bcpcol->column_type == SYBCHAR && cpbytes < bcpcol->column_size) {
01576                     for (j = cpbytes; j <  bcpcol->column_size; j++)
01577                         rowbuffer[row_pos + j] = ' ';
01578 
01579                 }
01580             }
01581 
01582             row_pos += bcpcol->column_size;
01583         }
01584     }
01585     return row_pos;
01586 }
01587 
01588 /*
01589  * Add variable size columns to the row
01590  */
01591 /**
01592  * \ingroup dblib_bcp_internal
01593  * \brief
01594  * \param dbproc contains all information needed by db-lib to manage communications with the server.
01595  * \param behaviour
01596  * \param rowbuffer
01597  * \param start
01598  * \param var_cols
01599  *
01600  * \return SUCCEED or FAIL.
01601  * \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()
01602  */
01603 static int
01604 _bcp_add_variable_columns(DBPROCESS * dbproc, int behaviour, BYTE * rowbuffer, int start, int *var_cols)
01605 {
01606     TDSCOLUMN *bcpcol;
01607     TDS_NUMERIC *num;
01608     int row_pos;
01609     int cpbytes;
01610 
01611     BYTE offset_table[256];
01612     BYTE adjust_table[256];
01613 
01614     int offset_pos     = 0;
01615     int adjust_pos     = 0;
01616     int num_cols       = 0;
01617     int last_adjustment_increment = 0;
01618     int this_adjustment_increment = 0;
01619 
01620     int i, adjust_table_entries_required;
01621 
01622     /* Skip over two bytes. These will be used to hold the entire record length */
01623     /* once the record has been completely built.                               */
01624 
01625     row_pos = start + 2;
01626 
01627     /* for each column in the target table */
01628 
01629     for (i = 0; i < dbproc->bcpinfo->bindinfo->num_cols; i++) {
01630 
01631         bcpcol = dbproc->bcpinfo->bindinfo->columns[i];
01632 
01633         /* is this column of "variable" type, i.e. NULLable */
01634         /* or naturally variable length e.g. VARCHAR        */
01635 
01636         if (is_nullable_type(bcpcol->column_type) || bcpcol->column_nullable) {
01637 
01638             tdsdump_log(TDS_DBG_FUNC, "_bcp_add_variable_columns column %d is a variable column\n", i + 1);
01639 
01640             if (behaviour == BCP_REC_FETCH_DATA) {
01641                 if ((_bcp_get_col_data(dbproc, bcpcol)) != SUCCEED) {
01642                     return FAIL;
01643                 }
01644             }
01645 
01646             /* but if its a NOT NULL column, and we have no data */
01647             /* throw an error                                    */
01648 
01649             if (!(bcpcol->column_nullable) && bcpcol->bcp_column_data->null_column) {
01650                 dbperror(dbproc, SYBEBCNN, 0);
01651                 return FAIL;
01652             }
01653 
01654             if (is_blob_type(bcpcol->column_type)) {
01655                 cpbytes = 16;
01656                 bcpcol->column_textpos = row_pos;               /* save for data write */
01657             } else if (is_numeric_type(bcpcol->column_type)) {
01658                 num = (TDS_NUMERIC *) bcpcol->bcp_column_data->data;
01659                 cpbytes = tds_numeric_bytes_per_prec[num->precision];
01660                 memcpy(&rowbuffer[row_pos], num->array, cpbytes);
01661             } else {
01662                 /* compute the length to copy to the row ** buffer */
01663                 if (bcpcol->bcp_column_data->null_column) {
01664                     cpbytes = 0;
01665                 } else {
01666                     cpbytes = bcpcol->bcp_column_data->datalen > bcpcol->column_size ? bcpcol->column_size : bcpcol->bcp_column_data->datalen;
01667                     memcpy(&rowbuffer[row_pos], bcpcol->bcp_column_data->data, cpbytes);
01668                 }
01669             }
01670 
01671             /* if we have written data to the record for this column */
01672 
01673             if (cpbytes > 0) {
01674 
01675                 /*
01676                  * update offset table. Each entry in the offset table is a single byte
01677                  * so can only hold a maximum value of 255. If the real offset is more
01678                  * than 255 we will have to add one or more entries in the adjust table
01679                  */
01680 
01681                 offset_table[offset_pos++] = row_pos % 256;
01682 
01683                 /* increment count of variable columns added to the record */
01684 
01685                 num_cols++;
01686 
01687                 /*
01688                  * how many times does 256 have to be added to the one byte offset to
01689                  * calculate the REAL offset...
01690                  */
01691 
01692                 this_adjustment_increment = row_pos / 256;
01693 
01694                 /* has this changed since we did the last column...      */
01695 
01696                 if (this_adjustment_increment > last_adjustment_increment) {
01697 
01698                     /*
01699                      * add n entries to the adjust table. each entry represents
01700                      * an adjustment of 256 bytes, and each entry holds the
01701                      * column number for which the adjustment needs to be made
01702                      */
01703 
01704                     for ( adjust_table_entries_required = this_adjustment_increment - last_adjustment_increment;
01705                           adjust_table_entries_required > 0;
01706                           adjust_table_entries_required-- ) {
01707                             adjust_table[adjust_pos++] = num_cols;
01708                     }
01709                     last_adjustment_increment = this_adjustment_increment;
01710                 }
01711 
01712                 row_pos += cpbytes;
01713             }
01714         }
01715     }
01716 
01717     if (num_cols) { 
01718         /*
01719          * If we have written any variable columns to the record, add entries
01720          * to the offset and adjust tables for the end of data offset (as above).
01721          */
01722 
01723         offset_table[offset_pos++] = row_pos % 256;
01724 
01725         /*
01726          * Write the offset data etc. to the end of the record, starting with
01727          * a count of variable columns (plus 1 for the eod offset)
01728          */
01729 
01730         rowbuffer[row_pos++] = num_cols + 1;
01731     
01732         /* write the adjust table (right to left) */
01733         for (i = adjust_pos - 1; i >= 0; i--) {
01734             rowbuffer[row_pos++] = adjust_table[i];
01735         }
01736     
01737         /* write the offset table (right to left) */
01738         for (i = offset_pos - 1; i >= 0; i--) {
01739             rowbuffer[row_pos++] = offset_table[i];
01740         }
01741     }
01742 
01743     *var_cols = num_cols;
01744 
01745     if (num_cols == 0) /* we haven't written anything */
01746         return start;
01747     else
01748         return row_pos;
01749 }
01750 
01751 /**
01752  * \ingroup dblib_bcp
01753  * \brief Write data in host variables to the table.
01754  *
01755  * \param dbproc contains all information needed by db-lib to manage communications with the server.
01756  *
01757  * \remarks Call bcp_bind() first to describe the variables to be used.
01758  *  Use bcp_batch() to commit sets of rows.
01759  *  After sending the last row call bcp_done().
01760  * \return SUCCEED or FAIL.
01761  * \sa  bcp_batch(), bcp_bind(), bcp_colfmt(), bcp_collen(), bcp_colptr(), bcp_columns(),
01762  *  bcp_control(), bcp_done(), bcp_exec(), bcp_init(), bcp_moretext(), bcp_options()
01763  */
01764 RETCODE
01765 bcp_sendrow(DBPROCESS * dbproc)
01766 {
01767 
01768     TDSSOCKET *tds = dbproc->tds_socket;
01769 
01770     if (dbproc->bcpinfo == NULL) {
01771         dbperror(dbproc, SYBEBCPI, 0);
01772         return FAIL;
01773     }
01774 
01775     if (dbproc->bcpinfo->direction != DB_IN) {
01776         dbperror(dbproc, SYBEBCPN, 0);
01777         return FAIL;
01778     }
01779 
01780     if (dbproc->hostfileinfo != NULL) {
01781         dbperror(dbproc, SYBEBCPB, 0);
01782         return FAIL;
01783     }
01784 
01785     /*
01786      * The first time sendrow is called after bcp_init,
01787      * there is a certain amount of initialisation to be done.
01788      */
01789     if (dbproc->bcpinfo->xfer_init == 0) {
01790 
01791         /* first call the start_copy function, which will */
01792         /* retrieve details of the database table columns */
01793 
01794         if (_bcp_start_copy_in(dbproc) == FAIL) {
01795             dbperror(dbproc, SYBEBULKINSERT, 0);
01796             return (FAIL);
01797         }
01798 
01799         /* set packet type to send bulk data */
01800         tds->out_flag = TDS_BULK;
01801         tds_set_state(tds, TDS_QUERYING);
01802 
01803         if (IS_TDS7_PLUS(tds)) {
01804             _bcp_send_colmetadata(dbproc);
01805         }
01806 
01807         dbproc->bcpinfo->xfer_init = 1;
01808 
01809     }
01810 
01811     return _bcp_send_bcp_record(dbproc, BCP_REC_FETCH_DATA);
01812 }
01813 
01814 
01815 /**
01816  * \ingroup dblib_bcp_internal
01817  * \brief
01818  * \param dbproc contains all information needed by db-lib to manage communications with the server.
01819  * \param rows_copied
01820  *
01821  * \return SUCCEED or FAIL.
01822  * \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()
01823  */
01824 static RETCODE
01825 _bcp_exec_in(DBPROCESS * dbproc, DBINT * rows_copied)
01826 {
01827     FILE *hostfile, *errfile = NULL;
01828     TDSSOCKET *tds = dbproc->tds_socket;
01829     BCP_HOSTCOLINFO *hostcol;
01830     RETCODE ret;
01831 
01832     int i;
01833     int row_of_hostfile, rows_written_so_far;
01834 
01835     int row_error, row_error_count;
01836     offset_type row_start, row_end;
01837     offset_type error_row_size;
01838 
01839     const size_t chunk_size = 0x20000u;
01840     
01841     *rows_copied = 0;
01842     
01843     if (!(hostfile = fopen(dbproc->hostfileinfo->hostfile, "r"))) {
01844         dbperror(dbproc, SYBEBCUO, 0);
01845         return FAIL;
01846     }
01847 
01848     if (_bcp_start_copy_in(dbproc) == FAIL)
01849         return FAIL;
01850 
01851     tds->out_flag = TDS_BULK;
01852     tds_set_state(tds, TDS_QUERYING);
01853 
01854     if (IS_TDS7_PLUS(tds)) {
01855         _bcp_send_colmetadata(dbproc);
01856     }
01857 
01858     row_of_hostfile = 0;
01859     rows_written_so_far = 0;
01860 
01861     row_start = ftello(hostfile);
01862     row_error_count = 0;
01863     row_error = 0;
01864 
01865     while ((ret=_bcp_read_hostfile(dbproc, hostfile, &row_error)) == MORE_ROWS) {
01866 
01867         row_of_hostfile++;
01868 
01869         if (row_error) {
01870 
01871             if (errfile == NULL && dbproc->hostfileinfo->errorfile) {
01872                 if (!(errfile = fopen(dbproc->hostfileinfo->errorfile, "w"))) {
01873                     dbperror(dbproc, SYBEBUOE, 0);
01874                     return FAIL;
01875                 }
01876             }
01877 
01878             if (errfile != NULL) {
01879                 char *row_in_error = NULL;
01880 
01881                 for (i = 0; i < dbproc->hostfileinfo->host_colcount; i++) {
01882                     hostcol = dbproc->hostfileinfo->host_columns[i];
01883                     if (hostcol->column_error == HOST_COL_CONV_ERROR) {
01884                         fprintf(errfile, "#@ data conversion error on host data file Row %d Column %d\n",
01885                             row_of_hostfile, i + 1);
01886                     } else if (hostcol->column_error == HOST_COL_NULL_ERROR) {
01887                         fprintf(errfile, "#@ Attempt to bulk-copy a NULL value into Server column"
01888                             " which does not accept NULL values. Row %d, Column %d\n",
01889                             row_of_hostfile, i + 1);
01890                     }
01891                 }
01892 
01893                 row_end = ftello(hostfile);
01894 
01895                 /* error data can be very long so split in chunks */
01896                 error_row_size = row_end - row_start;
01897                 fseeko(hostfile, row_start, SEEK_SET);
01898 
01899                 while (error_row_size > 0) {
01900                     size_t chunk = error_row_size > chunk_size ? chunk_size : error_row_size;
01901 
01902                     if (!row_in_error)
01903                         row_in_error = malloc(chunk);
01904 
01905                     if (fread(row_in_error, chunk, 1, hostfile) != 1) {
01906                         printf("BILL fread failed after fseek\n");
01907                     }
01908                     fwrite(row_in_error, chunk, 1, errfile);
01909                     error_row_size -= chunk;
01910                 }
01911                 if (row_in_error)
01912                     free(row_in_error);
01913 
01914                 fseeko(hostfile, row_end, SEEK_SET);
01915                 fprintf(errfile, "\n");
01916             }
01917             row_error_count++;
01918             if (row_error_count > dbproc->hostfileinfo->maxerrs)
01919                 break;
01920         } else {
01921             if (dbproc->hostfileinfo->firstrow <= row_of_hostfile &&
01922                                   row_of_hostfile <= MAX(dbproc->hostfileinfo->lastrow, 0x7FFFFFFF)) {
01923 
01924                 if (_bcp_send_bcp_record(dbproc, BCP_REC_NOFETCH_DATA) == SUCCEED) {
01925             
01926                     rows_written_so_far++;
01927     
01928                     if (dbproc->hostfileinfo->batch > 0 && rows_written_so_far == dbproc->hostfileinfo->batch) {
01929                         rows_written_so_far = 0;
01930     
01931                         tds_flush_packet(tds);
01932     
01933                         tds_set_state(tds, TDS_PENDING);
01934     
01935                         if (tds_process_simple_query(tds) != TDS_SUCCEED) {
01936                             if (errfile)
01937                                 fclose(errfile);
01938                             return FAIL;
01939                         }
01940                             
01941                         *rows_copied += tds->rows_affected;
01942     
01943                         dbperror(dbproc, SYBEBBCI, 0); /* batch copied to server */
01944     
01945                         _bcp_start_new_batch(dbproc);
01946     
01947                     }
01948                 }
01949             }
01950         }
01951 
01952         row_start = ftello(hostfile);
01953         row_error = 0;
01954     }
01955 
01956     if (errfile) {
01957         fclose(errfile);
01958         errfile = NULL;
01959     }
01960 
01961     if (fclose(hostfile) != 0) {
01962         dbperror(dbproc, SYBEBCUC, 0);
01963         return (FAIL);
01964     }
01965 
01966     tds_flush_packet(tds);
01967 
01968     tds_set_state(tds, TDS_PENDING);
01969 
01970     if (tds_process_simple_query(tds) != TDS_SUCCEED)
01971         return FAIL;
01972 
01973     *rows_copied += tds->rows_affected;
01974 
01975     return ret == NO_MORE_ROWS? SUCCEED : FAIL; /* (ret is returned from _bcp_read_hostfile) */
01976 }
01977 
01978 /**
01979  * \ingroup dblib_bcp
01980  * \brief Write a datafile to a table.
01981  *
01982  *
01983  * \param dbproc contains all information needed by db-lib to manage communications with the server.
01984  * \param rows_copied bcp_exec will write the count of rows successfully written to this address.
01985  *  If \a rows_copied is NULL, it will be ignored by db-lib.
01986  *
01987  * \return SUCCEED or FAIL.
01988  * \sa  bcp_batch(), bcp_bind(), bcp_colfmt(), bcp_collen(), bcp_colptr(), bcp_columns(),
01989  *  bcp_control(), bcp_done(), bcp_init(), bcp_sendrow()
01990  */
01991 RETCODE
01992 bcp_exec(DBPROCESS * dbproc, DBINT *rows_copied)
01993 {
01994     DBINT dummy_copied;
01995     RETCODE ret = 0;
01996 
01997     if (rows_copied == NULL) /* NULL means we should ignore it */
01998         rows_copied = &dummy_copied;
01999 
02000     if (dbproc->bcpinfo == NULL) {
02001         dbperror(dbproc, SYBEBCPI, 0);
02002         return FAIL;
02003     }
02004     if (dbproc->hostfileinfo == NULL) {
02005         dbperror(dbproc, SYBEBCVH, 0);
02006         return FAIL;
02007     }
02008 
02009     if (dbproc->bcpinfo->direction == DB_OUT || dbproc->bcpinfo->direction == DB_QUERYOUT) {
02010         ret = _bcp_exec_out(dbproc, rows_copied);
02011     } else if (dbproc->bcpinfo->direction == DB_IN) {
02012         ret = _bcp_exec_in(dbproc, rows_copied);
02013     }
02014     _bcp_free_storage(dbproc);
02015     
02016     return ret;
02017 }
02018 
02019 
02020 /**
02021  * \ingroup dblib_bcp_internal
02022  * \brief
02023  * \param dbproc contains all information needed by db-lib to manage communications with the server.
02024  *
02025  * \return SUCCEED or FAIL.
02026  * \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()
02027  */
02028 static RETCODE
02029 _bcp_start_copy_in(DBPROCESS * dbproc)
02030 {
02031 
02032     TDSSOCKET *tds = dbproc->tds_socket;
02033     TDSCOLUMN *bcpcol;
02034 
02035     int i;
02036     int firstcol;
02037 
02038     int fixed_col_len_tot     = 0;
02039     int variable_col_len_tot  = 0;
02040     int column_bcp_data_size  = 0;
02041     int bcp_record_size       = 0;
02042 
02043     char *query;
02044 
02045     if (IS_TDS7_PLUS(tds)) {
02046         int erc;
02047         char *hint;
02048         TDS_PBCB colclause;
02049         char clause_buffer[4096] = { 0 };
02050 
02051         colclause.pb = clause_buffer;
02052         colclause.cb = sizeof(clause_buffer);
02053         colclause.from_malloc = 0;
02054 
02055         firstcol = 1;
02056 
02057         for (i = 0; i < dbproc->bcpinfo->bindinfo->num_cols; i++) {
02058             bcpcol = dbproc->bcpinfo->bindinfo->columns[i];
02059 
02060             if (dbproc->bcpinfo->identity_insert_on) {
02061                 if (!bcpcol->column_timestamp) {
02062                     _bcp_build_bulk_insert_stmt(tds, &colclause, bcpcol, firstcol);
02063                     firstcol = 0;
02064                 }
02065             } else {
02066                 if (!bcpcol->column_identity && !bcpcol->column_timestamp) {
02067                     _bcp_build_bulk_insert_stmt(tds, &colclause, bcpcol, firstcol);
02068                     firstcol = 0;
02069                 }
02070             }
02071         }
02072 
02073         if (dbproc->bcpinfo->hint) {
02074             if (asprintf(&hint, " with (%s)", dbproc->bcpinfo->hint) < 0) {
02075                 return FAIL;
02076             }
02077         } else {
02078             hint = strdup("");
02079         }
02080         if (!hint)
02081             return FAIL;
02082 
02083         erc = asprintf(&query, "insert bulk %s (%s) %s", dbproc->bcpinfo->tablename, colclause.pb, hint);
02084 
02085         free(hint);
02086         if (colclause.from_malloc)
02087             TDS_ZERO_FREE(colclause.pb);    /* just for good measure; not used beyond this point */
02088 
02089         if (erc < 0) {
02090             return FAIL;
02091         }
02092 
02093     } else {
02094         if (asprintf(&query, "insert bulk %s", dbproc->bcpinfo->tablename) < 0) {
02095             return FAIL;
02096         }
02097     }
02098 
02099     tds_submit_query(tds, query);
02100 
02101     /* save the statement for later... */
02102 
02103     dbproc->bcpinfo->insert_stmt = query;
02104 
02105     /*
02106      * In TDS 5 we get the column information as a result set from the "insert bulk" command.
02107      * We're going to ignore it.
02108      */
02109     if (tds_process_simple_query(tds) != TDS_SUCCEED)
02110         return FAIL;
02111 
02112     /*
02113      * Work out the number of "variable" columns.  These are either nullable or of
02114      * varying length type e.g. varchar.
02115      */
02116     dbproc->bcpinfo->var_cols = 0;
02117 
02118     if (IS_TDS50(tds)) {
02119         for (i = 0; i < dbproc->bcpinfo->bindinfo->num_cols; i++) {
02120     
02121             bcpcol = dbproc->bcpinfo->bindinfo->columns[i];
02122 
02123             /* work out storage required for thsi datatype */
02124             /* blobs always require 16, numerics vary, the */
02125             /* rest can be taken from the server           */
02126 
02127             if (is_blob_type(bcpcol->on_server.column_type))
02128                 column_bcp_data_size  = 16;
02129             else if (is_numeric_type(bcpcol->on_server.column_type))
02130                 column_bcp_data_size  = tds_numeric_bytes_per_prec[bcpcol->column_prec];
02131             else
02132                 column_bcp_data_size  = bcpcol->column_size;
02133 
02134             /* now add that size into either fixed or variable */
02135             /* column totals...                                */
02136 
02137             if (is_nullable_type(bcpcol->on_server.column_type) || bcpcol->column_nullable) {
02138                 dbproc->bcpinfo->var_cols++;
02139                 variable_col_len_tot += column_bcp_data_size;
02140             }
02141             else {
02142                 fixed_col_len_tot += column_bcp_data_size;
02143             }
02144         }
02145 
02146         /* this formula taken from sybase manual... */
02147 
02148         bcp_record_size =   4 +
02149                             fixed_col_len_tot +
02150                             variable_col_len_tot +
02151                             ( (int)(variable_col_len_tot / 256 ) + 1 ) +
02152                             (dbproc->bcpinfo->var_cols + 1) +
02153                             2;
02154 
02155         tdsdump_log(TDS_DBG_FUNC, "current_record_size = %d\n", dbproc->bcpinfo->bindinfo->row_size);
02156         tdsdump_log(TDS_DBG_FUNC, "bcp_record_size     = %d\n", bcp_record_size);
02157 
02158         if (bcp_record_size > dbproc->bcpinfo->bindinfo->row_size) {
02159             /* FIXME remove memory leak */
02160             dbproc->bcpinfo->bindinfo->current_row = realloc(dbproc->bcpinfo->bindinfo->current_row, bcp_record_size);
02161             if (dbproc->bcpinfo->bindinfo->current_row == NULL) {
02162                 tdsdump_log(TDS_DBG_FUNC, "could not realloc current_row\n");
02163                 return FAIL;
02164             }
02165             dbproc->bcpinfo->bindinfo->row_size = bcp_record_size;
02166         }
02167     }
02168     if (IS_TDS7_PLUS(tds)) {
02169         for (i = 0; i < dbproc->bcpinfo->bindinfo->num_cols; i++) {
02170     
02171             bcpcol = dbproc->bcpinfo->bindinfo->columns[i];
02172 
02173             /*
02174              * dont send the (meta)data for timestamp columns, or
02175              * identity columns (unless indentity_insert is enabled
02176              */
02177 
02178             if ((!dbproc->bcpinfo->identity_insert_on && bcpcol->column_identity) ||
02179                 bcpcol->column_timestamp) {
02180                 continue;
02181             }
02182 
02183             switch (bcpcol->column_varint_size) {
02184                 case 4:
02185                     if (is_blob_type(bcpcol->column_type)) {
02186                         bcp_record_size += 25;
02187                     }
02188                     bcp_record_size += 4;
02189                     break;
02190                 case 2:
02191                     bcp_record_size +=2;
02192                     break;
02193                 case 1:
02194                     bcp_record_size++;
02195                     break;
02196                 case 0:
02197                     break;
02198             }
02199 
02200             if (is_numeric_type(bcpcol->column_type)) {
02201                 bcp_record_size += tds_numeric_bytes_per_prec[bcpcol->column_prec];
02202             } else {
02203                 bcp_record_size += bcpcol->column_size;
02204             }
02205         }
02206         tdsdump_log(TDS_DBG_FUNC, "current_record_size = %d\n", dbproc->bcpinfo->bindinfo->row_size);
02207         tdsdump_log(TDS_DBG_FUNC, "bcp_record_size     = %d\n", bcp_record_size);
02208 
02209         if (bcp_record_size > dbproc->bcpinfo->bindinfo->row_size) {
02210             dbproc->bcpinfo->bindinfo->current_row = realloc(dbproc->bcpinfo->bindinfo->current_row, bcp_record_size);
02211             if (dbproc->bcpinfo->bindinfo->current_row == NULL) {
02212                 tdsdump_log(TDS_DBG_FUNC, "could not realloc current_row\n");
02213                 return FAIL;
02214             }
02215             dbproc->bcpinfo->bindinfo->row_size = bcp_record_size;
02216         }
02217     }
02218 
02219     return SUCCEED;
02220 }
02221 
02222 /**
02223  * \ingroup dblib_bcp_internal
02224  * \brief
02225  * \param tds
02226  * \param clause
02227  * \param bcpcol
02228  * \param first
02229  *
02230  * \return SUCCEED or FAIL.
02231  * \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()
02232  */
02233 static RETCODE
02234 _bcp_build_bulk_insert_stmt(TDSSOCKET * tds, TDS_PBCB * clause, TDSCOLUMN * bcpcol, int first)
02235 {
02236     char buffer[32];
02237     char *column_type = buffer;
02238 
02239     /* TODO reuse function in tds/query.c */
02240     switch (bcpcol->on_server.column_type) {
02241     case SYBINT1:
02242         column_type = "tinyint";
02243         break;
02244     case SYBBIT:
02245         column_type = "bit";
02246         break;
02247     case SYBINT2:
02248         column_type = "smallint";
02249         break;
02250     case SYBINT4:
02251         column_type = "int";
02252         break;
02253     case SYBINT8:
02254         column_type = "bigint";
02255         break;
02256     case SYBDATETIME:
02257         column_type = "datetime";
02258         break;
02259     case SYBDATETIME4:
02260         column_type = "smalldatetime";
02261         break;
02262     case SYBREAL:
02263         column_type = "real";
02264         break;
02265     case SYBMONEY:
02266         column_type = "money";
02267         break;
02268     case SYBMONEY4:
02269         column_type = "smallmoney";
02270         break;
02271     case SYBFLT8:
02272         column_type = "float";
02273         break;
02274 
02275     case SYBINTN:
02276         switch (bcpcol->column_size) {
02277         case 1:
02278             column_type = "tinyint";
02279             break;
02280         case 2:
02281             column_type = "smallint";
02282             break;
02283         case 4:
02284             column_type = "int";
02285             break;
02286         case 8:
02287             column_type = "bigint";
02288             break;
02289         }
02290         break;
02291 
02292     case SYBBITN:
02293         column_type = "bit";
02294         break;
02295     case SYBFLTN:
02296         switch (bcpcol->column_size) {
02297         case 4:
02298             column_type = "real";
02299             break;
02300         case 8:
02301             column_type = "float";
02302             break;
02303         }
02304         break;
02305     case SYBMONEYN:
02306         switch (bcpcol->column_size) {
02307         case 4:
02308             column_type = "smallmoney";
02309             break;
02310         case 8:
02311             column_type = "money";
02312             break;
02313         }
02314         break;
02315     case SYBDATETIMN:
02316         switch (bcpcol->column_size) {
02317         case 4:
02318             column_type = "smalldatetime";
02319             break;
02320         case 8:
02321             column_type = "datetime";
02322             break;
02323         }
02324         break;
02325     case SYBDECIMAL:
02326         sprintf(column_type, "decimal(%d,%d)", bcpcol->column_prec, bcpcol->column_scale);
02327         break;
02328     case SYBNUMERIC:
02329         sprintf(column_type, "numeric(%d,%d)", bcpcol->column_prec, bcpcol->column_scale);
02330         break;
02331 
02332     case XSYBVARBINARY:
02333         sprintf(column_type, "varbinary(%d)", bcpcol->column_size);
02334         break;
02335     case XSYBVARCHAR:
02336         sprintf(column_type, "varchar(%d)", bcpcol->column_size);
02337         break;
02338     case XSYBBINARY:
02339         sprintf(column_type, "binary(%d)", bcpcol->column_size);
02340         break;
02341     case XSYBCHAR:
02342         sprintf(column_type, "char(%d)", bcpcol->column_size);
02343         break;
02344     case SYBTEXT:
02345         sprintf(column_type, "text");
02346         break;
02347     case SYBIMAGE:
02348         sprintf(column_type, "image");
02349         break;
02350     case XSYBNVARCHAR:
02351         sprintf(column_type, "nvarchar(%d)", bcpcol->column_size);
02352         break;
02353     case XSYBNCHAR:
02354         sprintf(column_type, "nchar(%d)", bcpcol->column_size);
02355         break;
02356     case SYBNTEXT:
02357         sprintf(column_type, "ntext");
02358         break;
02359     case SYBUNIQUE:
02360         sprintf(column_type, "uniqueidentifier  ");
02361         break;
02362     default:
02363         tdsdump_log(TDS_DBG_FUNC, "error: cannot build bulk insert statement. unrecognized server datatype %d\n", bcpcol->on_server.column_type);
02364         return FAIL;
02365     }
02366 
02367     if (clause->cb < strlen(clause->pb) + tds_quote_id(tds, NULL, bcpcol->column_name, bcpcol->column_namelen) + strlen(column_type) + ((first) ? 2 : 4)) {
02368         char *temp = (char *) malloc(2 * clause->cb);
02369 
02370         if (!temp)
02371             return FAIL;
02372         strcpy(temp, clause->pb);
02373         if (clause->from_malloc)
02374             free(clause->pb);
02375         clause->from_malloc = 1;
02376         clause->pb = temp;
02377         clause->cb *= 2;
02378     }
02379 
02380     if (!first)
02381         strcat(clause->pb, ", ");
02382 
02383     tds_quote_id(tds, strchr(clause->pb, 0), bcpcol->column_name, bcpcol->column_namelen);
02384     strcat(clause->pb, " ");
02385     strcat(clause->pb, column_type);
02386 
02387     return SUCCEED;
02388 }
02389 
02390 /**
02391  * \ingroup dblib_bcp_internal
02392  * \brief
02393  * \param dbproc contains all information needed by db-lib to manage communications with the server.
02394  *
02395  * \return SUCCEED or FAIL.
02396  * \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()
02397  */
02398 static RETCODE
02399 _bcp_start_new_batch(DBPROCESS * dbproc)
02400 {
02401     TDSSOCKET *tds = dbproc->tds_socket;
02402 
02403     tds_submit_query(tds, dbproc->bcpinfo->insert_stmt);
02404 
02405     if (tds_process_simple_query(tds) != TDS_SUCCEED)
02406         return FAIL;
02407 
02408     /* TODO problem with thread safety */
02409     tds->out_flag = TDS_BULK;
02410     tds_set_state(tds, TDS_QUERYING);
02411 
02412     if (IS_TDS7_PLUS(tds)) {
02413         _bcp_send_colmetadata(dbproc);
02414     }
02415     
02416     return SUCCEED;
02417 }
02418 
02419 /**
02420  * \ingroup dblib_bcp_internal
02421  * \brief
02422  * \param dbproc contains all information needed by db-lib to manage communications with the server.
02423  *
02424  * \return SUCCEED or FAIL.
02425  * \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()
02426  */
02427 static RETCODE
02428 _bcp_send_colmetadata(DBPROCESS * dbproc)
02429 {
02430 
02431     TDSSOCKET *tds = dbproc->tds_socket;
02432     unsigned char colmetadata_token = 0x81;
02433     TDSCOLUMN *bcpcol;
02434     int i;
02435     int num_cols;
02436 
02437     /*
02438      * Deep joy! For TDS 8 we have to send a colmetadata message followed by row data
02439      */
02440     tds_put_byte(tds, colmetadata_token);   /* 0x81 */
02441 
02442     num_cols = 0;
02443     for (i = 0; i < dbproc->bcpinfo->bindinfo->num_cols; i++) {
02444         bcpcol = dbproc->bcpinfo->bindinfo->columns[i];
02445         if ((!dbproc->bcpinfo->identity_insert_on && bcpcol->column_identity) ||
02446             bcpcol->column_timestamp) {
02447             continue;
02448         }
02449         num_cols++;
02450     }
02451 
02452     tds_put_smallint(tds, num_cols);
02453 
02454     for (i = 0; i < dbproc->bcpinfo->bindinfo->num_cols; i++) {
02455         bcpcol = dbproc->bcpinfo->bindinfo->columns[i];
02456 
02457     /*
02458      * dont send the (meta)data for timestamp columns, or
02459      * identity columns (unless indentity_insert is enabled
02460      */
02461 
02462         if ((!dbproc->bcpinfo->identity_insert_on && bcpcol->column_identity) ||
02463             bcpcol->column_timestamp) {
02464             continue;
02465         }
02466 
02467         tds_put_smallint(tds, bcpcol->column_usertype);
02468         tds_put_smallint(tds, bcpcol->column_flags);
02469         tds_put_byte(tds, bcpcol->on_server.column_type);
02470 
02471         switch (bcpcol->column_varint_size) {
02472         case 4:
02473             tds_put_int(tds, bcpcol->column_size);
02474             break;
02475         case 2:
02476             tds_put_smallint(tds, bcpcol->column_size);
02477             break;
02478         case 1:
02479             tds_put_byte(tds, bcpcol->column_size);
02480             break;
02481         case 0:
02482             break;
02483         default:
02484             break;
02485         }
02486 
02487         if (is_numeric_type(bcpcol->on_server.column_type)) {
02488             tds_put_byte(tds, bcpcol->column_prec);
02489             tds_put_byte(tds, bcpcol->column_scale);
02490         }
02491         if (IS_TDS80(tds)
02492             && is_collate_type(bcpcol->on_server.column_type)) {
02493             tds_put_n(tds, bcpcol->column_collation, 5);
02494         }
02495         if (is_blob_type(bcpcol->on_server.column_type)) {
02496             /* FIXME strlen return len in bytes not in characters required here */
02497             tds_put_smallint(tds, strlen(dbproc->bcpinfo->tablename));
02498             tds_put_string(tds, dbproc->bcpinfo->tablename, strlen(dbproc->bcpinfo->tablename));
02499         }
02500         /* FIXME column_namelen contains len in bytes not in characters required here */
02501         tds_put_byte(tds, bcpcol->column_namelen);
02502         tds_put_string(tds, bcpcol->column_name, bcpcol->column_namelen);
02503 
02504     }
02505 
02506     return SUCCEED;
02507 }
02508 
02509 /**
02510  * \ingroup dblib_bcp_internal
02511  * \brief
02512  * \param buffer
02513  * \param size
02514  * \param f
02515  *
02516  * \return SUCCEED or FAIL.
02517  * \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()
02518  */
02519 static char *
02520 _bcp_fgets(char *buffer, size_t size, FILE *f)
02521 {
02522     char *p = fgets(buffer, size, f);
02523     if (p == NULL)
02524         return p;
02525 
02526     /* discard newline */
02527     p = strchr(buffer, 0) - 1;
02528     if (p >= buffer && *p == '\n')
02529         *p = 0;
02530     return buffer;
02531 }
02532 
02533 /**
02534  * \ingroup dblib_bcp
02535  * \brief Read a format definition file.
02536  *
02537  * \param dbproc contains all information needed by db-lib to manage communications with the server.
02538  * \param filename Name that will be passed to fopen(3).
02539  *
02540  * \remarks Reads a format file and calls bcp_columns() and bcp_colfmt() as needed.
02541  *
02542  * \return SUCCEED or FAIL.
02543  * \sa  bcp_colfmt(), bcp_colfmt_ps(), bcp_columns(), bcp_writefmt()
02544  */
02545 RETCODE
02546 bcp_readfmt(DBPROCESS * dbproc, char *filename)
02547 {
02548     FILE *ffile;
02549     char buffer[1024];
02550 
02551     float lf_version = 0.0;
02552     int li_numcols = 0;
02553     int colinfo_count = 0;
02554 
02555     struct fflist
02556     {
02557         struct fflist *nextptr;
02558         BCP_HOSTCOLINFO colinfo;
02559     };
02560 
02561     struct fflist *topptr = NULL;
02562     struct fflist *curptr = NULL;
02563 
02564     BCP_HOSTCOLINFO *hostcol;
02565 
02566     if (dbproc->bcpinfo == NULL) {
02567         dbperror(dbproc, SYBEBCPI, 0);
02568         return FAIL;
02569     }
02570 
02571     if ((ffile = fopen(filename, "r")) == NULL) {
02572         dbperror(dbproc, SYBEBUOF, 0);
02573         return (FAIL);
02574     }
02575 
02576     if ((_bcp_fgets(buffer, sizeof(buffer), ffile)) != NULL)
02577         lf_version = atof(buffer);
02578 
02579     if ((_bcp_fgets(buffer, sizeof(buffer), ffile)) != NULL)
02580         li_numcols = atoi(buffer);
02581 
02582     /* FIXME fix memory leak, if this function returns FAIL... */
02583     while ((_bcp_fgets(buffer, sizeof(buffer), ffile)) != NULL) {
02584 
02585         if (topptr == NULL) {   /* first time */
02586             if ((curptr = (struct fflist *) malloc(sizeof(struct fflist))) == NULL) {
02587                 dbperror(dbproc, SYBEMEM, 0);
02588                 return (FAIL);
02589             }
02590             topptr = curptr;
02591         } else {
02592             if ((curptr->nextptr = (struct fflist *) malloc(sizeof(struct fflist))) == NULL) {
02593                 dbperror(dbproc, SYBEMEM, 0);
02594                 return (FAIL);
02595             }
02596             curptr = curptr->nextptr;
02597         }
02598         curptr->nextptr = NULL;
02599         if (_bcp_readfmt_colinfo(dbproc, buffer, &(curptr->colinfo)))
02600             colinfo_count++;
02601         else
02602             return (FAIL);
02603 
02604     }
02605     if (fclose(ffile) != 0) {
02606         dbperror(dbproc, SYBEBUCF, 0);
02607         return (FAIL);
02608     }
02609 
02610     if (colinfo_count != li_numcols)
02611         return (FAIL);
02612 
02613     if (bcp_columns(dbproc, li_numcols) == FAIL) {
02614         return (FAIL);
02615     }
02616 
02617     for (curptr = topptr; curptr->nextptr != NULL; curptr = curptr->nextptr) {
02618         hostcol = &(curptr->colinfo);
02619         if (bcp_colfmt(dbproc, hostcol->host_column, hostcol->datatype,
02620                    hostcol->prefix_len, hostcol->column_len,
02621                    hostcol->terminator, hostcol->term_len, hostcol->tab_colnum) == FAIL) {
02622             return (FAIL);
02623         }
02624     }
02625     hostcol = &(curptr->colinfo);
02626     if (bcp_colfmt(dbproc, hostcol->host_column, hostcol->datatype,
02627                hostcol->prefix_len, hostcol->column_len,
02628                hostcol->terminator, hostcol->term_len, hostcol->tab_colnum) == FAIL) {
02629         return (FAIL);
02630     }
02631 
02632     return (SUCCEED);
02633 }
02634 
02635 /**
02636  * \ingroup dblib_bcp_internal
02637  * \brief
02638  * \param dbproc contains all information needed by db-lib to manage communications with the server.
02639  * \param buf
02640  * \param ci
02641  *
02642  * \return SUCCEED or FAIL.
02643  * \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()
02644  */
02645 static int
02646 _bcp_readfmt_colinfo(DBPROCESS * dbproc, char *buf, BCP_HOSTCOLINFO * ci)
02647 {
02648 
02649     char *tok;
02650     int whichcol;
02651     char term[30];
02652     int i;
02653 
02654     enum nextcol
02655     {
02656         HOST_COLUMN,
02657         DATATYPE,
02658         PREFIX_LEN,
02659         COLUMN_LEN,
02660         TERMINATOR,
02661         TAB_COLNUM,
02662         NO_MORE_COLS
02663     };
02664 
02665     tok = strtok(buf, " \t");
02666     whichcol = HOST_COLUMN;
02667 
02668     /* TODO use a better way to get an int atoi is very error prone */
02669     while (tok != NULL && whichcol != NO_MORE_COLS) {
02670         switch (whichcol) {
02671 
02672         case HOST_COLUMN:
02673             ci->host_column = atoi(tok);
02674 
02675             if (ci->host_column < 1) {
02676                 dbperror(dbproc, SYBEBIHC, 0);
02677                 return (FALSE);
02678             }
02679 
02680             whichcol = DATATYPE;
02681             break;
02682 
02683         case DATATYPE:
02684             if (strcmp(tok, "SYBCHAR") == 0)
02685                 ci->datatype = SYBCHAR;
02686             else if (strcmp(tok, "SYBTEXT") == 0)
02687                 ci->datatype = SYBTEXT;
02688             else if (strcmp(tok, "SYBBINARY") == 0)
02689                 ci->datatype = SYBBINARY;
02690             else if (strcmp(tok, "SYBIMAGE") == 0)
02691                 ci->datatype = SYBIMAGE;
02692             else if (strcmp(tok, "SYBINT1") == 0)
02693                 ci->datatype = SYBINT1;
02694             else if (strcmp(tok, "SYBINT2") == 0)
02695                 ci->datatype = SYBINT2;
02696             else if (strcmp(tok, "SYBINT4") == 0)
02697                 ci->datatype = SYBINT4;
02698             else if (strcmp(tok, "SYBINT8") == 0)
02699                 ci->datatype = SYBINT8;
02700             else if (strcmp(tok, "SYBFLT8") == 0)
02701                 ci->datatype = SYBFLT8;
02702             else if (strcmp(tok, "SYBREAL") == 0)
02703                 ci->datatype = SYBREAL;
02704             else if (strcmp(tok, "SYBBIT") == 0)
02705                 ci->datatype = SYBBIT;
02706             else if (strcmp(tok, "SYBNUMERIC") == 0)
02707                 ci->datatype = SYBNUMERIC;
02708             else if (strcmp(tok, "SYBDECIMAL") == 0)
02709                 ci->datatype = SYBDECIMAL;
02710             else if (strcmp(tok, "SYBMONEY") == 0)
02711                 ci->datatype = SYBMONEY;
02712             else if (strcmp(tok, "SYBDATETIME") == 0)
02713                 ci->datatype = SYBDATETIME;
02714             else if (strcmp(tok, "SYBDATETIME4") == 0)
02715                 ci->datatype = SYBDATETIME4;
02716             else {
02717                 dbperror(dbproc, SYBEBUDF, 0);
02718                 return (FALSE);
02719             }
02720 
02721             whichcol = PREFIX_LEN;
02722             break;
02723 
02724         case PREFIX_LEN:
02725             ci->prefix_len = atoi(tok);
02726             whichcol = COLUMN_LEN;
02727             break;
02728         case COLUMN_LEN:
02729             ci->column_len = atoi(tok);
02730             whichcol = TERMINATOR;
02731             break;
02732         case TERMINATOR:
02733 
02734             if (*tok++ != '\"')
02735                 return (FALSE);
02736 
02737             for (i = 0; *tok != '\"' && i < sizeof(term); i++) {
02738                 if (*tok == '\\') {
02739                     tok++;
02740                     switch (*tok) {
02741                     case 't':
02742                         term[i] = '\t';
02743                         break;
02744                     case 'n':
02745                         term[i] = '\n';
02746                         break;
02747                     case 'r':
02748                         term[i] = '\r';
02749                         break;
02750                     case '\\':
02751                         term[i] = '\\';
02752                         break;
02753                     case '0':
02754                         term[i] = '\0';
02755                         break;
02756                     default:
02757                         return (FALSE);
02758                     }
02759                     tok++;
02760                 } else
02761                     term[i] = *tok++;
02762             }
02763 
02764             if (*tok != '\"')
02765                 return (FALSE);
02766 
02767             ci->terminator = (BYTE *) malloc(i);
02768             memcpy((char *) ci->terminator, term, i);
02769             ci->term_len = i;
02770 
02771             whichcol = TAB_COLNUM;
02772             break;
02773 
02774         case TAB_COLNUM:
02775             ci->tab_colnum = atoi(tok);
02776             whichcol = NO_MORE_COLS;
02777             break;
02778 
02779         }
02780         tok = strtok(NULL, " \t");
02781     }
02782     if (whichcol == NO_MORE_COLS)
02783         return (TRUE);
02784     else
02785         return (FALSE);
02786 }
02787 
02788 /**
02789  * \ingroup dblib_bcp
02790  * \brief Write a format definition file. Not Implemented.
02791  *
02792  * \param dbproc contains all information needed by db-lib to manage communications with the server.
02793  * \param filename Name that would be passed to fopen(3).
02794  *
02795  * \remarks Reads a format file and calls bcp_columns() and bcp_colfmt() as needed.
02796  * \a FreeTDS includes freebcp, a utility to copy data to or from a host file.
02797  *
02798  * \todo For completeness, \a freebcp ought to be able to create format files, but that functionality
02799  *  is currently lacking, as is bcp_writefmt().
02800  * \todo See the vendors' documentation for the format of these files.
02801  *
02802  * \return SUCCEED or FAIL.
02803  * \sa  bcp_colfmt(), bcp_colfmt_ps(), bcp_columns(), bcp_readfmt()
02804  */
02805 RETCODE
02806 bcp_writefmt(DBPROCESS * dbproc, char *filename)
02807 {
02808     if (dbproc->bcpinfo == NULL) {
02809         dbperror(dbproc, SYBEBCPI, 0);
02810         return FAIL;
02811     }
02812     return FAIL;
02813 }
02814 
02815 /**
02816  * \ingroup dblib_bcp
02817  * \brief Write some text or image data to the server.  Not implemented, sadly.
02818  *
02819  * \param dbproc contains all information needed by db-lib to manage communications with the server.
02820  * \param size How much to write, in bytes.
02821  * \param text Address of the data to be written.
02822  * \remarks For a SYBTEXT or SYBIMAGE column, bcp_bind() can be called with
02823  *  a NULL varaddr parameter.  If it is, bcp_sendrow() will return control
02824  *  to the application after the non-text data have been sent.  The application then calls
02825  *  bcp_moretext() -- usually in a loop -- to send the text data in manageable chunks.
02826  * \todo implement bcp_moretext().
02827  * \return SUCCEED or FAIL.
02828  * \sa  bcp_bind(), bcp_sendrow(), dbmoretext(), dbwritetext()
02829  */
02830 RETCODE
02831 bcp_moretext(DBPROCESS * dbproc, DBINT size, BYTE * text)
02832 {
02833     if (dbproc->bcpinfo == NULL) {
02834         dbperror(dbproc, SYBEBCPI, 0);
02835         return FAIL;
02836     }
02837     return FAIL;
02838 }
02839 
02840 /**
02841  * \ingroup dblib_bcp
02842  * \brief Commit a set of rows to the table.
02843  *
02844  * \param dbproc contains all information needed by db-lib to manage communications with the server.
02845  * \remarks If not called, bcp_done() will cause the rows to be saved.
02846  * \return Count of rows saved, or -1 on error.
02847  * \sa  bcp_bind(), bcp_done(), bcp_sendrow()
02848  */
02849 DBINT
02850 bcp_batch(DBPROCESS * dbproc)
02851 {
02852     TDSSOCKET *tds = dbproc->tds_socket;
02853     int rows_copied = 0;
02854 
02855     if (dbproc->bcpinfo == NULL) {
02856         dbperror(dbproc, SYBEBCPI, 0);
02857         return -1;
02858     }
02859 
02860     tds_flush_packet(tds);
02861 
02862     tds_set_state(tds, TDS_PENDING);
02863 
02864     if (tds_process_simple_query(tds) != TDS_SUCCEED)
02865         return FAIL;
02866 
02867     rows_copied = tds->rows_affected;
02868 
02869     _bcp_start_new_batch(dbproc);
02870 
02871     return (rows_copied);
02872 }
02873 
02874 /**
02875  * \ingroup dblib_bcp
02876  * \brief Conclude the transfer of data from program variables.
02877  *
02878  * \param dbproc contains all information needed by db-lib to manage communications with the server.
02879  * \remarks Do not overlook this function.  According to Sybase, failure to call bcp_done()
02880  * "will result in unpredictable errors".
02881  * \return As with bcp_batch(), the count of rows saved, or -1 on error.
02882  * \sa  bcp_batch(), bcp_bind(), bcp_moretext(), bcp_sendrow()
02883  */
02884 DBINT
02885 bcp_done(DBPROCESS * dbproc)
02886 {
02887     TDSSOCKET *tds = dbproc->tds_socket;
02888     int rows_copied = -1;
02889 
02890     if (dbproc->bcpinfo == NULL) {
02891         dbperror(dbproc, SYBEBCPI, 0);
02892         return -1;
02893     }
02894 
02895     /* TODO check proper tds state */
02896 
02897     tds_flush_packet(tds);
02898 
02899     tds_set_state(tds, TDS_PENDING);
02900 
02901     if (tds_process_simple_query(tds) != TDS_SUCCEED)
02902         return FAIL;
02903     rows_copied = tds->rows_affected;
02904 
02905     _bcp_free_storage(dbproc);
02906 
02907     return (rows_copied);
02908 
02909 }
02910 
02911 /**
02912  * \ingroup dblib_bcp
02913  * \brief Bind a program host variable to a database column
02914  *
02915  * \param dbproc contains all information needed by db-lib to manage communications with the server.
02916  * \param varaddr address of host variable
02917  * \param prefixlen length of any prefix found at the beginning of \a varaddr, in bytes.
02918     Use zero for fixed-length datatypes.
02919  * \param varlen bytes of data in \a varaddr.  Zero for NULL, -1 for fixed-length datatypes.
02920  * \param terminator byte sequence that marks the end of the data in \a varaddr
02921  * \param termlen length of \a terminator
02922  * \param vartype datatype of the host variable
02923  * \param table_column Nth column, starting at 1, in the table.
02924  *
02925  * \remarks The order of operation is:
02926  *  - bcp_init() with \a hfile == NULL and \a direction == DB_IN.
02927  *  - bcp_bind(), once per column you want to write to
02928  *  - bcp_batch(), optionally, to commit a set of rows
02929  *  - bcp_done()
02930  * \return SUCCEED or FAIL.
02931  * \sa  bcp_batch(), bcp_colfmt(), bcp_collen(), bcp_colptr(), bcp_columns(), bcp_control(),
02932  *  bcp_done(), bcp_exec(), bcp_moretext(), bcp_sendrow()
02933  */
02934 RETCODE
02935 bcp_bind(DBPROCESS * dbproc, BYTE * varaddr, int prefixlen, DBINT varlen,
02936      BYTE * terminator, int termlen, int vartype, int table_column)
02937 {
02938 
02939     TDSCOLUMN *colinfo;
02940 
02941     if (dbproc->bcpinfo == NULL) {
02942         dbperror(dbproc, SYBEBCPI, 0);
02943         return FAIL;
02944     }
02945 
02946     if (dbproc->hostfileinfo != NULL) {
02947         dbperror(dbproc, SYBEBCPB, 0);
02948         return FAIL;
02949     }
02950 
02951     if (dbproc->bcpinfo->direction != DB_IN) {
02952         dbperror(dbproc, SYBEBCPN, 0);
02953         return FAIL;
02954     }
02955 
02956     if (varlen < -1) {
02957         dbperror(dbproc, SYBEBCVLEN, 0);
02958         return FAIL;
02959     }
02960 
02961     if (prefixlen != 0 && prefixlen != 1 && prefixlen != 2 && prefixlen != 4) {
02962         dbperror(dbproc, SYBEBCBPREF, 0);
02963         return FAIL;
02964     }
02965 
02966     if (prefixlen == 0 && varlen == -1 && termlen == -1 && !is_fixed_type(vartype)) {
02967         return FAIL;
02968     }
02969 
02970     if (is_fixed_type(vartype) && (varlen != -1 && varlen != 0)) {
02971         return FAIL;
02972     }
02973 
02974     if (table_column <= 0 ||  table_column > dbproc->bcpinfo->bindinfo->num_cols)
02975         return FAIL;
02976 
02977     if (varaddr == NULL && (prefixlen != 0 || termlen != 0)) {
02978         dbperror(dbproc, SYBEBCBNPR, 0);
02979         return FAIL;
02980     }
02981 
02982     colinfo = dbproc->bcpinfo->bindinfo->columns[table_column - 1];
02983 
02984     colinfo->column_varaddr  = (char *)varaddr;
02985     colinfo->column_bindtype = vartype;
02986     colinfo->column_bindlen  = varlen;
02987     colinfo->bcp_terminator =  malloc(termlen);
02988     memcpy(colinfo->bcp_terminator, terminator, termlen);
02989     colinfo->bcp_term_len = termlen;
02990 
02991     return SUCCEED;
02992 }
02993 
02994 /**
02995  * \ingroup dblib_bcp_internal
02996  * \brief
02997  * \param dbproc contains all information needed by db-lib to manage communications with the server.
02998  * \param behaviour
02999  *
03000  * \return SUCCEED or FAIL.
03001  * \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()
03002  */
03003 static RETCODE
03004 _bcp_send_bcp_record(DBPROCESS * dbproc, int behaviour)
03005 {
03006     TDSSOCKET  *tds = dbproc->tds_socket;
03007     TDSCOLUMN  *bindcol;
03008 
03009     static const unsigned char CHARBIN_NULL[] = { 0xff, 0xff };
03010     static const unsigned char GEN_NULL = 0x00;
03011     static const unsigned char textptr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
03012                                              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
03013     };
03014     static const unsigned char timestamp[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
03015 
03016     static const TDS_TINYINT textptr_size = 16;
03017 
03018     unsigned char *record;
03019     TDS_INT  old_record_size;
03020     TDS_INT  new_record_size;
03021 
03022     TDS_INT      varint_4;
03023     TDS_SMALLINT varint_2;
03024     TDS_TINYINT  varint_1;
03025 
03026     int row_pos;
03027     int row_sz_pos;
03028     TDS_SMALLINT row_size;
03029 
03030     int blob_cols = 0;
03031     int var_cols_written = 0;
03032 
03033     int i;
03034 
03035     tdsdump_log(TDS_DBG_FUNC, "_bcp_send_bcp_record\n");
03036 
03037     record = dbproc->bcpinfo->bindinfo->current_row;
03038     old_record_size = dbproc->bcpinfo->bindinfo->row_size;
03039     new_record_size = 0;
03040 
03041     if (IS_TDS7_PLUS(tds)) {
03042 
03043         for (i = 0; i < dbproc->bcpinfo->bindinfo->num_cols; i++) {
03044     
03045             bindcol = dbproc->bcpinfo->bindinfo->columns[i];
03046 
03047             /*
03048              * dont send the (meta)data for timestamp columns, or
03049              * identity columns (unless indentity_insert is enabled
03050              */
03051 
03052             if ((!dbproc->bcpinfo->identity_insert_on && bindcol->column_identity) ||
03053                 bindcol->column_timestamp) {
03054                 continue;
03055             }
03056 
03057             if (behaviour == BCP_REC_FETCH_DATA) {
03058                 if ((_bcp_get_col_data(dbproc, bindcol)) != SUCCEED) {
03059                     tdsdump_log(TDS_DBG_INFO1, "bcp_get_colData (column %d) failed\n", i + 1);
03060                     return FAIL;
03061                 }
03062                 tdsdump_log(TDS_DBG_INFO1, "gotten column %d length %d null %d\n",
03063                             i + 1, bindcol->bcp_column_data->datalen, bindcol->bcp_column_data->null_column);
03064             }
03065             tdsdump_log(TDS_DBG_INFO1, "column %d length %d null %d\n",
03066                         i + 1, bindcol->bcp_column_data->datalen, bindcol->bcp_column_data->null_column);
03067     
03068             if (bindcol->bcp_column_data->null_column) {
03069                 if (bindcol->column_nullable) {
03070                     switch (bindcol->on_server.column_type) {
03071                     case XSYBCHAR:
03072                     case XSYBVARCHAR:
03073                     case XSYBBINARY:
03074                     case XSYBVARBINARY:
03075                     case XSYBNCHAR:
03076                     case XSYBNVARCHAR:
03077                         memcpy(record, CHARBIN_NULL, 2);
03078                         record +=2;
03079                         new_record_size +=2;
03080                         break;
03081                     default:
03082                         *record = GEN_NULL;
03083                         record++;
03084                         new_record_size ++;
03085                         break;
03086                     }
03087                 } else {
03088                     dbperror(dbproc, SYBEBCNN, 0);
03089                     return FAIL;
03090                 }
03091             } else {
03092 
03093                 switch (bindcol->column_varint_size) {
03094                 case 4:
03095                     if (is_blob_type(bindcol->column_type)) {
03096                         *record = textptr_size; record++;
03097                         memcpy(record, textptr, 16); record += 16;
03098                         memcpy(record, timestamp, 8); record += 8;
03099                         new_record_size += 25;
03100                     }
03101                     varint_4 = bindcol->bcp_column_data->datalen;
03102 #if WORDS_BIGENDIAN
03103                     tds_swap_datatype(SYBINT4, (unsigned char *)&varint_4);
03104 #endif
03105                     memcpy(record, &varint_4, 4); record += 4; new_record_size +=4;
03106                     break;
03107                 case 2:
03108                     varint_2 = bindcol->bcp_column_data->datalen;
03109 #if WORDS_BIGENDIAN
03110                     tds_swap_datatype(SYBINT2, (unsigned char *)&varint_2);
03111 #endif
03112                     memcpy(record, &varint_2, 2); record += 2; new_record_size +=2;
03113                     break;
03114                 case 1:
03115                     varint_1 = bindcol->bcp_column_data->datalen;
03116                     if (is_numeric_type(bindcol->column_type)) {
03117                         varint_1 = tds_numeric_bytes_per_prec[bindcol->column_prec];
03118                         tdsdump_log(TDS_DBG_INFO1, "numeric type prec = %d varint_1 = %d\n", bindcol->column_prec, varint_1);
03119                     }
03120                     else {
03121                         varint_1 = bindcol->bcp_column_data->datalen;
03122                         tdsdump_log(TDS_DBG_INFO1, "varint_1 = %d\n", varint_1);
03123                     }
03124                     *record = varint_1; record++; new_record_size++;
03125                     break;
03126                 case 0:
03127                     break;
03128                 }
03129 
03130                 tdsdump_log(TDS_DBG_INFO1, "new_record_size = %d datalen = %d \n",
03131                             new_record_size, bindcol->bcp_column_data->datalen);
03132 
03133 #if WORDS_BIGENDIAN
03134                 tds_swap_datatype(tds_get_conversion_type(bindcol->column_type, bindcol->bcp_column_data->datalen),
03135                                     bindcol->bcp_column_data->data);
03136 #endif
03137                 tdsdump_log(TDS_DBG_INFO1, "new_record_size = %d datalen = %d \n",
03138                             new_record_size, bindcol->bcp_column_data->datalen);
03139 
03140 
03141                 if (is_numeric_type(bindcol->column_type)) {
03142                     TDS_NUMERIC *num = (TDS_NUMERIC *) bindcol->bcp_column_data->data;
03143                     int size;
03144                     tdsdump_log(TDS_DBG_INFO1, "numeric type prec = %d\n", num->precision);
03145                     if (IS_TDS7_PLUS(tds))
03146                         tds_swap_numeric(num);
03147                     size = tds_numeric_bytes_per_prec[num->precision];
03148                     memcpy(record, num->array, size);
03149                     record += size;
03150                     new_record_size += size;
03151                 } else {
03152                     tdsdump_log(TDS_DBG_INFO1, "new_record_size = %d datalen = %d \n",
03153                                 new_record_size, bindcol->bcp_column_data->datalen);
03154                     memcpy(record, bindcol->bcp_column_data->data, bindcol->bcp_column_data->datalen);
03155                     record += bindcol->bcp_column_data->datalen;
03156                     new_record_size += bindcol->bcp_column_data->datalen;
03157                 }
03158 
03159             }
03160             tdsdump_log(TDS_DBG_INFO1, "old_record_size = %d new size = %d \n",
03161                     old_record_size, new_record_size);
03162         }
03163 
03164         tds_put_byte(tds, TDS_ROW_TOKEN);   /* 0xd1 */
03165         tds_put_n(tds, dbproc->bcpinfo->bindinfo->current_row, new_record_size);
03166     }  /* IS_TDS7_PLUS */
03167     else {
03168             memset(record, '\0', old_record_size);  /* zero the rowbuffer */
03169 
03170             /* offset 0 = number of var columns */
03171             /* offset 1 = row number.  zeroed (datasever assigns) */
03172             row_pos = 2;
03173 
03174             if ((row_pos = _bcp_add_fixed_columns(dbproc, behaviour, record, row_pos)) == FAIL)
03175                 return FAIL;
03176 
03177             row_sz_pos = row_pos;
03178 
03179             /* potential variable columns to write */
03180 
03181             if (dbproc->bcpinfo->var_cols) {
03182                 if ((row_pos = _bcp_add_variable_columns(dbproc, behaviour, record, row_pos, &var_cols_written)) == FAIL)
03183                     return FAIL;
03184             }
03185 
03186             row_size = row_pos;
03187 
03188             if (var_cols_written) {
03189                 memcpy(&record[row_sz_pos], &row_size, sizeof(row_size));
03190                 record[0] = var_cols_written;
03191             }
03192 
03193             tdsdump_log(TDS_DBG_INFO1, "old_record_size = %d new size = %d \n",
03194                     old_record_size, row_size);
03195 
03196             tds_put_smallint(tds, row_size);
03197             tds_put_n(tds, record, row_size);
03198 
03199             /* row is done, now handle any text/image data */
03200 
03201             blob_cols = 0;
03202 
03203             for (i = 0; i < dbproc->bcpinfo->bindinfo->num_cols; i++) {
03204                 bindcol = dbproc->bcpinfo->bindinfo->columns[i];
03205                 if (is_blob_type(bindcol->column_type)) {
03206                     if (behaviour == BCP_REC_FETCH_DATA) {
03207                         if ((_bcp_get_col_data(dbproc, bindcol)) != SUCCEED) {
03208                             return FAIL;
03209                         }
03210                     }
03211                     /* unknown but zero */
03212                     tds_put_smallint(tds, 0);
03213                     tds_put_byte(tds, bindcol->column_type);
03214                     tds_put_byte(tds, 0xff - blob_cols);
03215                     /*
03216                      * offset of txptr we stashed during variable
03217                      * column processing
03218                      */
03219                     tds_put_smallint(tds, bindcol->column_textpos);
03220                     tds_put_int(tds, bindcol->bcp_column_data->datalen);
03221                     tds_put_n(tds, bindcol->bcp_column_data->data, bindcol->bcp_column_data->datalen);
03222                     blob_cols++;
03223 
03224                 }
03225             }
03226             return SUCCEED;
03227     }
03228 
03229     return SUCCEED;
03230 }
03231 
03232 /*
03233  * For a bcp in from program variables, get the data from
03234  * the host variable
03235  */
03236 /**
03237  * \ingroup dblib_bcp_internal
03238  * \brief
03239  * \param dbproc contains all information needed by db-lib to manage communications with the server.
03240  * \param bindcol
03241  *
03242  * \return SUCCEED or FAIL.
03243  * \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()
03244  */
03245 static RETCODE
03246 _bcp_get_col_data(DBPROCESS * dbproc, TDSCOLUMN *bindcol)
03247 {
03248     TDS_TINYINT ti;
03249     TDS_SMALLINT si;
03250     TDS_INT li;
03251     TDS_INT desttype;
03252     int collen;
03253     int data_is_null;
03254     int bytes_read;
03255     int converted_data_size;
03256 
03257     BYTE *dataptr;
03258 
03259 
03260     dataptr = (BYTE *) bindcol->column_varaddr;
03261 
03262     data_is_null = 0;
03263     collen = 0;
03264 
03265     /* If a prefix length specified, read the correct  amount of data. */
03266 
03267     if (bindcol->bcp_prefix_len > 0) {
03268 
03269         switch (bindcol->bcp_prefix_len) {
03270         case 1:
03271             memcpy(&ti, dataptr, 1);
03272             dataptr += 1;
03273             collen = ti;
03274             break;
03275         case 2:
03276             memcpy(&si, dataptr, 2);
03277             dataptr += 2;
03278             collen = si;
03279             break;
03280         case 4:
03281             memcpy(&li, dataptr, 4);
03282             dataptr += 4;
03283             collen = li;
03284             break;
03285         }
03286         if (collen == 0)
03287             data_is_null = 1;
03288 
03289     }
03290 
03291     /* if (Max) column length specified take that into consideration. */
03292 
03293     if (!data_is_null && bindcol->column_bindlen >= 0) {
03294         if (bindcol->column_bindlen == 0)
03295             data_is_null = 1;
03296         else {
03297             if (collen)
03298                 collen = (bindcol->column_bindlen < collen) ? bindcol->column_bindlen : collen;
03299             else
03300                 collen = bindcol->column_bindlen;
03301         }
03302     }
03303 
03304     /* Fixed Length data - this overrides anything else specified */
03305 
03306     if (is_fixed_type(bindcol->column_bindtype)) {
03307         collen = tds_get_size_by_type(bindcol->column_bindtype);
03308     }
03309 
03310     /* read the data, finally */
03311 
03312     if (bindcol->bcp_term_len > 0) {    /* terminated field */
03313         bytes_read = _bcp_get_term_var(dataptr, (BYTE *)bindcol->bcp_terminator, bindcol->bcp_term_len);
03314 
03315         if (collen)
03316             collen = (bytes_read < collen) ? bytes_read : collen;
03317         else
03318             collen = bytes_read;
03319 
03320         if (collen == 0)
03321             data_is_null = 1;
03322     }
03323 
03324     if (data_is_null) {
03325         bindcol->bcp_column_data->datalen = 0;
03326         bindcol->bcp_column_data->null_column = 1;
03327     } else {
03328         desttype = tds_get_conversion_type(bindcol->column_type, bindcol->column_size);
03329 
03330         if ((converted_data_size =
03331              dbconvert(dbproc, bindcol->column_bindtype,
03332                    (BYTE *) dataptr, collen,
03333                    desttype, bindcol->bcp_column_data->data, bindcol->column_size)) == -1) {
03334             return (FAIL);
03335         }
03336 
03337         bindcol->bcp_column_data->datalen = converted_data_size;
03338         bindcol->bcp_column_data->null_column = 0;
03339     }
03340 
03341     return SUCCEED;
03342 }
03343 
03344 /**
03345  * Get the data for bcp-in from program variables, where the program data
03346  * have been identified as character terminated,
03347  * This is a low-level, internal function.  Call it correctly.
03348  */
03349 /**
03350  * \ingroup dblib_bcp_internal
03351  * \brief
03352  * \param pdata
03353  * \param term
03354  * \param term_len
03355  *
03356  * \return SUCCEED or FAIL.
03357  * \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()
03358  */
03359 static RETCODE
03360 _bcp_get_term_var(BYTE * pdata, BYTE * term, int term_len)
03361 {
03362     int bufpos;
03363 
03364     assert(term_len > 0);
03365 
03366     /* if bufpos becomes negative, we probably failed to find the terminator */
03367     for (bufpos = 0; bufpos >= 0 && memcmp(pdata, term, term_len) != 0; pdata++) {
03368         bufpos++;
03369     }
03370     
03371     assert(bufpos > 0);
03372     return bufpos;
03373 }
03374 
03375 /**
03376  * \ingroup dblib_bcp_internal
03377  * \brief
03378  * \param istr
03379  * \param ilen
03380  *
03381  * \return modified length
03382  * \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()
03383  */
03384 static int
03385 rtrim(char *istr, int ilen)
03386 {
03387     char *t;
03388 
03389     for (t = istr + ilen; --t > istr && *t == ' '; )
03390         *t = '\0';
03391     return t - istr + 1;
03392 }
03393 
03394 /**
03395  * \ingroup dblib_bcp_internal
03396  * \brief
03397  * \param dbproc contains all information needed by db-lib to manage communications with the server.
03398  *
03399  * \return SUCCEED or FAIL.
03400  * \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()
03401  */
03402 static void
03403 _bcp_free_columns(DBPROCESS * dbproc)
03404 {
03405     int i;
03406 
03407     assert(dbproc && dbproc->hostfileinfo);
03408     if (dbproc->hostfileinfo->host_columns) {
03409         for (i = 0; i < dbproc->hostfileinfo->host_colcount; i++) {
03410             if (dbproc->hostfileinfo->host_columns[i]->terminator)
03411                 TDS_ZERO_FREE(dbproc->hostfileinfo->host_columns[i]->terminator);
03412             tds_free_bcp_column_data(dbproc->hostfileinfo->host_columns[i]->bcp_column_data);
03413             TDS_ZERO_FREE(dbproc->hostfileinfo->host_columns[i]);
03414         }
03415         TDS_ZERO_FREE(dbproc->hostfileinfo->host_columns);
03416         dbproc->hostfileinfo->host_colcount = 0;
03417     }
03418 }
03419 
03420 /**
03421  * \ingroup dblib_bcp_internal
03422  * \brief
03423  * \param dbproc contains all information needed by db-lib to manage communications with the server.
03424  *
03425  * \return SUCCEED or FAIL.
03426  * \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()
03427  */
03428 static RETCODE
03429 _bcp_free_storage(DBPROCESS * dbproc)
03430 {
03431     if (dbproc->hostfileinfo) {
03432         if (dbproc->hostfileinfo->hostfile)
03433             TDS_ZERO_FREE(dbproc->hostfileinfo->hostfile);
03434     
03435         if (dbproc->hostfileinfo->errorfile)
03436             TDS_ZERO_FREE(dbproc->hostfileinfo->errorfile);
03437 
03438         /* free up storage that holds details of hostfile columns */
03439 
03440         _bcp_free_columns(dbproc);
03441         TDS_ZERO_FREE(dbproc->hostfileinfo);
03442     }
03443 
03444 
03445     if (dbproc->bcpinfo) {
03446         if (dbproc->bcpinfo->tablename)
03447             TDS_ZERO_FREE(dbproc->bcpinfo->tablename);
03448 
03449         if (dbproc->bcpinfo->insert_stmt)
03450             TDS_ZERO_FREE(dbproc->bcpinfo->insert_stmt);
03451 
03452         if (dbproc->bcpinfo->bindinfo) {
03453             /* bcp use current_row in another way, this can cause invalid free for blobs */
03454             if (dbproc->bcpinfo->bindinfo->current_row)
03455                 TDS_ZERO_FREE(dbproc->bcpinfo->bindinfo->current_row);
03456             tds_free_results(dbproc->bcpinfo->bindinfo);
03457             dbproc->bcpinfo->bindinfo = NULL;
03458         }
03459 
03460         TDS_ZERO_FREE(dbproc->bcpinfo);
03461     }
03462 
03463     return (SUCCEED);
03464 
03465 }
03466 
03467 
03468 

Generated on Wed Dec 9 04:15:41 2009 for NCBI C++ ToolKit by  doxygen 1.4.6
Modified on Wed Dec 09 08:17:56 2009 by modify_doxy.py rev. 173732