/** * \ingroup odbc_bcp * \brief Write data in host variables to the table. * * \param dbc ODBC database connection object * * \remarks Call bcp_bind() first to describe the variables to be used. * Use bcp_batch() to commit sets of rows. * After sending the last row call bcp_done(). * \sa odbc_bcp_batch(), odbc_bcp_bind(), odbc_bcp_colptr(), odbc_bcp_done(), * odbc_bcp_init() */ void odbc_bcp_sendrow(TDS_DBC *dbc) { TDSSOCKET *tds; tdsdump_log(TDS_DBG_FUNC, "bcp_sendrow(%p)\n", dbc); if (dbc->bcpinfo == NULL) ODBCBCP_ERROR_RETURN("HY010"); tds = dbc->tds_socket; if (dbc->bcpinfo->direction != BCP_DIRECTION_IN) ODBCBCP_ERROR_RETURN("HY010"); /* * The first time sendrow is called after bcp_init, * there is a certain amount of initialisation to be done. */ if (dbc->bcpinfo->xfer_init == 0) { /* The start_copy function retrieves details of the table's columns */ if (TDS_FAILED(tds_bcp_start_copy_in(tds, dbc->bcpinfo))) ODBCBCP_ERROR_RETURN("HY000"); dbc->bcpinfo->xfer_init = 1; } dbc->bcpinfo->parent = dbc; if (TDS_FAILED(tds_bcp_send_record(dbc->tds_socket, dbc->bcpinfo, _bcp_get_col_data, NULL, 0))) ODBCBCP_ERROR_RETURN("HY000"); }
static void unfinished_query_test(TDSSOCKET *tds) { int char_len; char *buf, *p; int i, len; union { TDS_USMALLINT si; TDS_UINT i; TDS_INT8 i8; char buf[8]; } conv; if (IS_TDS72_PLUS(tds->conn)) return; tds_init_write_buf(tds); /* try to build an invalid (unfinished) query split in two packets */ char_len = IS_TDS7_PLUS(tds->conn) ? 2 : 1; buf = calloc(1, tds->out_buf_max + 200); memset(buf, '-', tds->out_buf_max + 200); strcpy(buf + (tds->out_buf_max - 8) / char_len - strlen(select_query) + 1, select_query); memset(strchr(buf, 0), 0, 16); /* convert if needed */ len = strlen(buf); for (i = len; --i >= 0; ) { char c = buf[i]; buf[i * char_len + 0] = c; if (IS_TDS7_PLUS(tds->conn)) buf[i * char_len + 1] = 0; } len *= char_len; /* send the query using tds_put_int8, non allineati */ tds->out_flag = TDS_QUERY; if (tds_set_state(tds, TDS_WRITING) != TDS_WRITING) exit(1); p = buf; memcpy(conv.buf, p, 2); tds_put_smallint(tds, conv.si); p += 2; for (; p < buf + len; p += 8) { CHECK_TDS_EXTRA(tds); memcpy(conv.buf, p, 8); tds_put_int8(tds, conv.i8); } tds_flush_packet(tds); tds_set_state(tds, TDS_PENDING); /* check result was fine */ if (TDS_FAILED(tds_process_simple_query(tds))) { fprintf(stderr, "Error in prepared query\n"); exit(1); } free(buf); }
static boolean reinit_results(TDSSOCKET * tds, size_t num_cols, const struct metadata_t meta[]) { TDSRESULTINFO *info; int i; assert(tds); assert(num_cols); assert(meta); tds_free_all_results(tds); tds->rows_affected = TDS_NO_COUNT; if ((info = alloc_results(num_cols)) == NULL) return false; tds_set_current_results(tds, info); if (tds->cur_cursor) { tds_free_results(tds->cur_cursor->res_info); tds->cur_cursor->res_info = info; tdsdump_log(TDS_DBG_INFO1, "set current_results to cursor->res_info\n"); } else { tds->res_info = info; tdsdump_log(TDS_DBG_INFO1, "set current_results (%u column%s) to tds->res_info\n", (unsigned) num_cols, (num_cols==1? "":"s")); } tdsdump_log(TDS_DBG_INFO1, "setting up %u columns\n", (unsigned) num_cols); for (i = 0; i < num_cols; i++) { set_result_column(tds, info->columns[i], meta[i].name, &meta[i].col); info->columns[i]->bcp_terminator = (char*) meta[i].pacross; /* overload available pointer */ } if (num_cols > 0) { static char dashes[31] = "------------------------------"; tdsdump_log(TDS_DBG_INFO1, " %-20s %-15s %-15s %-7s\n", "name", "size/wsize", "type/wtype", "utype"); tdsdump_log(TDS_DBG_INFO1, " %-20s %15s %15s %7s\n", dashes+10, dashes+30-15, dashes+30-15, dashes+30-7); } for (i = 0; i < num_cols; i++) { TDSCOLUMN *curcol = info->columns[i]; tdsdump_log(TDS_DBG_INFO1, " %-20s %7d/%-7d %7d/%-7d %7d\n", tds_dstr_cstr(&curcol->column_name), curcol->column_size, curcol->on_server.column_size, curcol->column_type, curcol->on_server.column_type, curcol->column_usertype); } #if 1 /* all done now allocate a row for tds_process_row to use */ if (TDS_FAILED(tds_alloc_row(info))) return false; #endif return true; }
/** * \ingroup odbc_bcp * \brief Prepare for bulk copy operation on a table * * \param dbc ODBC database connection object * \param tblname the name of the table receiving or providing the data. * \param hfile the data file opposite the table, if any. NB: The current * implementation does not support file I/O so this must be NULL * \param errfile the "error file" captures messages and, if errors are * encountered. NB: The current implementation does not support * file I/O so this must be NULL * \param direction one of * - \b DB_IN writing to the table * - \b DB_OUT writing to the host file (Not currently supported) * . * \remarks bcp_init() sets the host file data format and acquires the table metadata. * It is called before the other bulk copy functions. * * The ODBC BCP functionality should be accessed via the inline functions in * odbcss.h. * * After calling this function, call bcp_bind() to associate your data with * the appropriate table column. * * \sa SQL_COPT_SS_BCP, odbc_bcp_bind(), odbc_bcp_done(), odbc_bcp_exec() */ void odbc_bcp_init(TDS_DBC *dbc, const ODBC_CHAR *tblname, const ODBC_CHAR *hfile, const ODBC_CHAR *errfile, int direction _WIDE) { /* TODO convert unicode for printing */ tdsdump_log(TDS_DBG_FUNC, "bcp_init(%p, %s, %s, %s, %d)\n", dbc, tblname, hfile, errfile, direction); if (!tblname) ODBCBCP_ERROR_RETURN("HY009"); /* Free previously allocated storage in dbproc & initialise flags, etc. */ odbc_bcp_free_storage(dbc); /* * Validate other parameters */ if (dbc->tds_socket->conn->tds_version < 0x500) ODBCBCP_ERROR_RETURN("HYC00"); if (direction != BCP_DIRECTION_IN || hfile || errfile) ODBCBCP_ERROR_RETURN("HYC00"); /* Allocate storage */ dbc->bcpinfo = tds_alloc_bcpinfo(); if (dbc->bcpinfo == NULL) ODBCBCP_ERROR_RETURN("HY001"); if (!odbc_dstr_copy(dbc, &dbc->bcpinfo->tablename, SQL_NTS, tblname)) { odbc_bcp_free_storage(dbc); ODBCBCP_ERROR_RETURN("HY001"); } if (tds_dstr_len(&dbc->bcpinfo->tablename) > 92 && !IS_TDS7_PLUS(dbc->tds_socket->conn)) { /* 30.30.30 */ odbc_bcp_free_storage(dbc); ODBCBCP_ERROR_RETURN("HYC00"); } dbc->bcpinfo->direction = direction; dbc->bcpinfo->xfer_init = 0; dbc->bcpinfo->bind_count = 0; if (TDS_FAILED(tds_bcp_init(dbc->tds_socket, dbc->bcpinfo))) { /* TODO return proper error */ /* Attempt to use Bulk Copy with a non-existent Server table (might be why ...) */ ODBCBCP_ERROR_RETURN("HY000"); } }
/* * pool_mbr_login open a single pool login, to be call at init time or * to reconnect. */ static TDSSOCKET * pool_mbr_login(TDS_POOL * pool) { TDSCONTEXT *context; TDSLOGIN *login; TDSSOCKET *tds; TDSLOGIN *connection; char hostname[MAXHOSTNAMELEN]; login = tds_alloc_login(1); if (gethostname(hostname, MAXHOSTNAMELEN) < 0) strlcpy(hostname, "tdspool", MAXHOSTNAMELEN); if (!tds_set_passwd(login, pool->password) || !tds_set_user(login, pool->user) || !tds_set_app(login, "tdspool") || !tds_set_host(login, hostname) || !tds_set_library(login, "TDS-Library") || !tds_set_server(login, pool->server) || !tds_set_client_charset(login, "iso_1") || !tds_set_language(login, "us_english")) { tds_free_login(login); return NULL; } if (pool->database && strlen(pool->database)) { if (!tds_dstr_copy(&login->database, pool->database)) { tds_free_login(login); return NULL; } } context = tds_alloc_context(NULL); tds = tds_alloc_socket(context, 512); connection = tds_read_config_info(tds, login, context->locale); if (!connection || TDS_FAILED(tds_connect_and_login(tds, connection))) { tds_free_socket(tds); tds_free_login(connection); /* what to do? */ fprintf(stderr, "Could not open connection to server %s\n", pool->server); return NULL; } tds_free_login(connection); if (pool->database && strlen(pool->database)) { if (strcasecmp(tds->conn->env.database, pool->database) != 0) { fprintf(stderr, "changing database failed\n"); return NULL; } } return tds; }
/** * \ingroup odbc_bcp * \brief Commit a set of rows to the table. * * \param dbc ODBC database connection object * \remarks If not called, bcp_done() will cause the rows to be saved. * \return Count of rows saved, or -1 on error. * \sa odbc_bcp_bind(), odbc_bcp_done(), odbc_bcp_sendrow() */ int odbc_bcp_batch(TDS_DBC *dbc) { int rows_copied = 0; tdsdump_log(TDS_DBG_FUNC, "bcp_batch(%p)\n", dbc); if (dbc->bcpinfo == NULL) ODBCBCP_ERROR_DBINT("HY010"); if (TDS_FAILED(tds_bcp_done(dbc->tds_socket, &rows_copied))) ODBCBCP_ERROR_DBINT("HY000"); tds_bcp_start(dbc->tds_socket, dbc->bcpinfo); return rows_copied; }
/** * \ingroup odbc_bcp * \brief Conclude the transfer of data from program variables. * * \param dbc ODBC database connection object * \remarks Do not overlook this function. According to Sybase, failure to call bcp_done() * "will result in unpredictable errors". * \return As with bcp_batch(), the count of rows saved, or -1 on error. * \sa bcp_batch(), bcp_bind(), bcp_moretext(), bcp_sendrow() */ int odbc_bcp_done(TDS_DBC *dbc) { int rows_copied; tdsdump_log(TDS_DBG_FUNC, "bcp_done(%p)\n", dbc); if (!(dbc->bcpinfo)) ODBCBCP_ERROR_DBINT("HY010"); if (TDS_FAILED(tds_bcp_done(dbc->tds_socket, &rows_copied))) ODBCBCP_ERROR_DBINT("HY000"); odbc_bcp_free_storage(dbc); return rows_copied; }
/** * Help to build query to be sent to server. * Append column declaration to the query. * Only for TDS 7.0+. * \tds * \param[out] clause output string * \param bcpcol column to append * \param first true if column is the first * \return TDS_SUCCESS or TDS_FAIL. */ static TDSRET tds7_build_bulk_insert_stmt(TDSSOCKET * tds, TDSPBCB * clause, TDSCOLUMN * bcpcol, int first) { char column_type[40]; tdsdump_log(TDS_DBG_FUNC, "tds7_build_bulk_insert_stmt(%p, %p, %p, %d)\n", tds, clause, bcpcol, first); if (TDS_FAILED(tds_get_column_declaration(tds, bcpcol, column_type))) { tdserror(tds_get_ctx(tds), tds, TDSEBPROBADTYP, errno); tdsdump_log(TDS_DBG_FUNC, "error: cannot build bulk insert statement. unrecognized server datatype %d\n", bcpcol->on_server.column_type); return TDS_FAIL; } if (clause->cb < strlen(clause->pb) + tds_quote_id(tds, NULL, tds_dstr_cstr(&bcpcol->column_name), tds_dstr_len(&bcpcol->column_name)) + strlen(column_type) + ((first) ? 2u : 4u)) { char *temp = (char*) malloc(2 * clause->cb); if (!temp) { tdserror(tds_get_ctx(tds), tds, TDSEMEM, errno); return TDS_FAIL; } strcpy(temp, clause->pb); if (clause->from_malloc) free(clause->pb); clause->from_malloc = 1; clause->pb = temp; clause->cb *= 2; } if (!first) strcat(clause->pb, ", "); tds_quote_id(tds, strchr(clause->pb, 0), tds_dstr_cstr(&bcpcol->column_name), tds_dstr_len(&bcpcol->column_name)); strcat(clause->pb, " "); strcat(clause->pb, column_type); return TDS_SUCCESS; }
/* TDSHOST env var, [email protected] 01/21/02 */ static void tds_config_env_tdshost(TDSLOGIN * login) { const char *tdshost; char tmp[128]; struct tds_addrinfo *addrs; if (!(tdshost = getenv("TDSHOST"))) return; if (TDS_FAILED(tds_lookup_host_set(tdshost, &login->ip_addrs))) { tdsdump_log(TDS_DBG_WARN, "Name resolution failed for '%s' from $TDSHOST.\n", tdshost); return; } tds_dstr_copy(&login->server_host_name, tdshost); for (addrs = login->ip_addrs; addrs != NULL; addrs = addrs->ai_next) { tdsdump_log(TDS_DBG_INFO1, "Setting IP Address to %s (%s) from $TDSHOST.\n", tds_addrinfo2str(addrs, tmp, sizeof(tmp)), tdshost); } }
static TDSRET tds_gss_handle_next(TDSSOCKET * tds, struct tds_authentication * auth, size_t len) { TDSRET res; gss_buffer_desc recv_tok; if (((struct tds_gss_auth *) auth)->last_stat != GSS_S_CONTINUE_NEEDED) return TDS_FAIL; if (auth->packet) { OM_uint32 min_stat; gss_buffer_desc send_tok; send_tok.value = (void *) auth->packet; send_tok.length = auth->packet_len; gss_release_buffer(&min_stat, &send_tok); auth->packet = NULL; } recv_tok.length = len; recv_tok.value = (char* ) malloc(len); if (!recv_tok.value) return TDS_FAIL; tds_get_n(tds, recv_tok.value, len); res = tds_gss_continue(tds, (struct tds_gss_auth *) auth, &recv_tok); free(recv_tok.value); if (TDS_FAILED(res)) return res; if (auth->packet_len) { tds->out_flag = TDS7_AUTH; tds_put_n(tds, auth->packet, auth->packet_len); return tds_flush_packet(tds); } return TDS_SUCCESS; }
/** * Add fixed size columns to the row * \param bcpinfo BCP information * \param get_col_data function to call to retrieve data to be sent * \param ignored function to call if we try to send NULL if not allowed (not used) * \param offset passed to get_col_data and null_error to specify the row to get * \param rowbuffer row buffer to write to * \param start row buffer last end position * \returns new row length or -1 on error. */ static int tds_bcp_add_fixed_columns(TDSBCPINFO *bcpinfo, tds_bcp_get_col_data get_col_data, tds_bcp_null_error null_error, int offset, unsigned char * rowbuffer, int start) { TDS_NUMERIC *num; int row_pos = start; TDSCOLUMN *bcpcol; int cpbytes; int i, j; int bitleft = 0, bitpos; assert(bcpinfo); assert(rowbuffer); tdsdump_log(TDS_DBG_FUNC, "tds_bcp_add_fixed_columns(%p, %p, ignored, %d, %p, %d)\n", bcpinfo, get_col_data, offset, rowbuffer, start); for (i = 0; i < bcpinfo->bindinfo->num_cols; i++) { bcpcol = bcpinfo->bindinfo->columns[i]; if (is_nullable_type(bcpcol->on_server.column_type) || bcpcol->column_nullable) continue; tdsdump_log(TDS_DBG_FUNC, "tds_bcp_add_fixed_columns column %d is a fixed column\n", i + 1); if (TDS_FAILED(get_col_data(bcpinfo, bcpcol, offset))) { tdsdump_log(TDS_DBG_INFO1, "get_col_data (column %d) failed\n", i + 1); return -1; } if (bcpcol->bcp_column_data->is_null && null_error) { /* No value or default value available and NULL not allowed. */ null_error(bcpinfo, i, offset); return -1; } if (is_numeric_type(bcpcol->column_type)) { num = (TDS_NUMERIC *) bcpcol->bcp_column_data->data; cpbytes = tds_numeric_bytes_per_prec[num->precision]; memcpy(&rowbuffer[row_pos], num->array, cpbytes); } else if (bcpcol->column_type == SYBBIT) { /* all bit are collapsed together */ if (!bitleft) { bitpos = row_pos++; bitleft = 8; rowbuffer[bitpos] = 0; } if (bcpcol->bcp_column_data->data[0]) rowbuffer[bitpos] |= 256 >> bitleft; --bitleft; continue; } else { cpbytes = bcpcol->bcp_column_data->datalen > bcpcol->column_size ? bcpcol->column_size : bcpcol->bcp_column_data->datalen; memcpy(&rowbuffer[row_pos], bcpcol->bcp_column_data->data, cpbytes); /* CHAR data may need padding out to the database length with blanks */ /* TODO check binary !!! */ if (bcpcol->column_type == SYBCHAR && cpbytes < bcpcol->column_size) { for (j = cpbytes; j < bcpcol->column_size; j++) rowbuffer[row_pos + j] = ' '; } } row_pos += bcpcol->column_size; }
/* * pool_mbr_login open a single pool login, to be call at init time or * to reconnect. */ static TDSSOCKET * pool_mbr_login(TDS_POOL * pool) { TDSCONTEXT *context; TDSLOGIN *login; TDSSOCKET *tds; TDSLOGIN *connection; TDSRET rc; char *query; char hostname[MAXHOSTNAMELEN]; login = tds_alloc_login(1); #if HAVE_GETHOSTNAME if (gethostname(hostname, MAXHOSTNAMELEN) < 0) #endif strlcpy(hostname, "tdspool", MAXHOSTNAMELEN); if (!tds_set_passwd(login, pool->password) || !tds_set_user(login, pool->user) || !tds_set_app(login, "tdspool") || !tds_set_host(login, hostname) || !tds_set_library(login, "TDS-Library") || !tds_set_server(login, pool->server) || !tds_set_client_charset(login, "iso_1") || !tds_set_language(login, "us_english")) { tds_free_login(login); return NULL; } context = tds_alloc_context(NULL); tds = tds_alloc_socket(context, 512); connection = tds_read_config_info(tds, login, context->locale); if (!connection || TDS_FAILED(tds_connect_and_login(tds, connection))) { tds_free_socket(tds); tds_free_login(connection); /* what to do? */ fprintf(stderr, "Could not open connection to server %s\n", pool->server); return NULL; } tds_free_login(connection); /* * FIXME -- tds_connect_and_login no longer preallocates the in_buf need to * do something like what tds_read_packet does */ tds->in_buf = (unsigned char *) calloc(BLOCKSIZ, 1); if (pool->database && strlen(pool->database)) { query = (char *) malloc(strlen(pool->database) + 5); sprintf(query, "use %s", pool->database); rc = tds_submit_query(tds, query); free(query); if (TDS_FAILED(rc)) { fprintf(stderr, "changing database failed\n"); return NULL; } if (TDS_FAILED(tds_process_simple_query(tds))) return NULL; } return tds; }
bool pool_user_send_login_ack(TDS_POOL * pool, TDS_POOL_USER * puser) { char msg[256]; char block[32]; TDSSOCKET *tds = puser->sock.tds, *mtds = puser->assigned_member->sock.tds; TDSLOGIN *login = puser->login; const char *database; const char *server = mtds->conn->server ? mtds->conn->server : "JDBC"; bool dbname_mismatch, odbc_mismatch; pool->user_logins++; /* copy a bit of information, resize socket with block */ tds->conn->tds_version = mtds->conn->tds_version; tds->conn->product_version = mtds->conn->product_version; memcpy(tds->conn->collation, mtds->conn->collation, sizeof(tds->conn->collation)); tds->conn->tds71rev1 = mtds->conn->tds71rev1; free(tds->conn->product_name); tds->conn->product_name = strdup(mtds->conn->product_name); tds_realloc_socket(tds, mtds->conn->env.block_size); tds->conn->env.block_size = mtds->conn->env.block_size; tds->conn->client_spid = mtds->conn->spid; /* if database is different use USE statement */ database = pool->database; dbname_mismatch = !tds_dstr_isempty(&login->database) && strcasecmp(tds_dstr_cstr(&login->database), database) != 0; odbc_mismatch = (login->option_flag2 & TDS_ODBC_ON) == 0; if (dbname_mismatch || odbc_mismatch) { char *str; int len = 128 + tds_quote_id(mtds, NULL, tds_dstr_cstr(&login->database),-1); TDSRET ret; if ((str = (char *) malloc(len)) == NULL) return false; str[0] = 0; /* swicth to dblib options */ if (odbc_mismatch) strcat(str, "SET ANSI_DEFAULTS OFF\nSET CONCAT_NULL_YIELDS_NULL OFF\n"); if (dbname_mismatch) { strcat(str, "USE "); tds_quote_id(mtds, strchr(str, 0), tds_dstr_cstr(&login->database), -1); } ret = tds_submit_query(mtds, str); free(str); if (TDS_FAILED(ret) || TDS_FAILED(tds_process_simple_query(mtds))) return false; if (dbname_mismatch) database = tds_dstr_cstr(&login->database); else database = mtds->conn->env.database; } // 7.0 // env database // database change message (with server name correct) // env language // language change message // env 0x3 charset ("iso_1") // env 0x5 lcid ("1033") // env 0x6 ("196609" ?? 0x30001) // loginack // env 0x4 packet size // done // // 7.1/7.2/7.3 // env database // database change message (with server name correct) // env 0x7 collation // env language // language change message // loginack // env 0x4 packet size // done tds->out_flag = TDS_REPLY; tds_env_change(tds, TDS_ENV_DATABASE, "master", database); sprintf(msg, "Changed database context to '%s'.", database); tds_send_msg(tds, 5701, 2, 0, msg, server, NULL, 1); if (!login->suppress_language) { tds_env_change(tds, TDS_ENV_LANG, NULL, "us_english"); tds_send_msg(tds, 5703, 1, 0, "Changed language setting to 'us_english'.", server, NULL, 1); } if (IS_TDS71_PLUS(tds->conn)) { tds_put_byte(tds, TDS_ENVCHANGE_TOKEN); tds_put_smallint(tds, 8); tds_put_byte(tds, TDS_ENV_SQLCOLLATION); tds_put_byte(tds, 5); tds_put_n(tds, tds->conn->collation, 5); tds_put_byte(tds, 0); } tds_send_login_ack(tds, mtds->conn->product_name); sprintf(block, "%d", tds->conn->env.block_size); tds_env_change(tds, TDS_ENV_PACKSIZE, block, block); /* tds_send_capabilities_token(tds); */ tds_send_done_token(tds, 0, 0); /* send it! */ tds_flush_packet(tds); tds_free_login(login); puser->login = NULL; return true; }
/* * pool_user_create * accepts a client connection and adds it to the users list and returns it */ TDS_POOL_USER * pool_user_create(TDS_POOL * pool, TDS_SYS_SOCKET s) { TDS_POOL_USER *puser; TDS_SYS_SOCKET fd; TDSSOCKET *tds; LOGIN_EVENT *ev; tdsdump_log(TDS_DBG_NETWORK, "accepting connection\n"); if (TDS_IS_SOCKET_INVALID(fd = tds_accept(s, NULL, NULL))) { char *errstr = sock_strerror(errno); tdsdump_log(TDS_DBG_ERROR, "error calling assert :%s\n", errstr); sock_strerror_free(errstr); return NULL; } if (tds_socket_set_nonblocking(fd) != 0) { CLOSESOCKET(fd); return NULL; } puser = pool_user_find_new(pool); if (!puser) { CLOSESOCKET(fd); return NULL; } tds = tds_alloc_socket(pool->ctx, BLOCKSIZ); if (!tds) { CLOSESOCKET(fd); return NULL; } ev = (LOGIN_EVENT *) calloc(1, sizeof(*ev)); if (!ev || TDS_FAILED(tds_iconv_open(tds->conn, "UTF-8", 0))) { free(ev); tds_free_socket(tds); CLOSESOCKET(fd); return NULL; } /* FIX ME - little endian emulation should be config file driven */ tds->conn->emul_little_endian = 1; tds_set_s(tds, fd); tds->state = TDS_IDLE; tds->out_flag = TDS_LOGIN; puser->sock.tds = tds; puser->user_state = TDS_SRV_QUERY; puser->sock.poll_recv = false; puser->sock.poll_send = false; /* launch login asyncronously */ ev->puser = puser; ev->pool = pool; if (tds_thread_create_detached(login_proc, ev) != 0) { pool_free_user(pool, puser); fprintf(stderr, "error creating thread\n"); return NULL; } return puser; }
/** * Build a GSSAPI packet to send to server * @param tds A pointer to the TDSSOCKET structure managing a client/server operation. * @param packet GSSAPI packet build from function * @return size of packet */ TDSAUTHENTICATION * tds_gss_get_auth(TDSSOCKET * tds) { /* * TODO * There are some differences between this implementation and MS on * - MS use SPNEGO with 3 mechnisms (MS KRB5, KRB5, NTLMSSP) * - MS seems to use MUTUAL flag * - name type is "Service and Instance (2)" and not "Principal (1)" * check for memory leaks * check for errors in many functions * a bit more verbose * dinamically load library ?? */ gss_buffer_desc send_tok; OM_uint32 maj_stat, min_stat; /* same as GSS_KRB5_NT_PRINCIPAL_NAME but do not require .so library */ static gss_OID_desc nt_principal = { 10, (void*) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01" }; const char *server_name; /* Storage for getaddrinfo calls */ struct addrinfo *addrs = NULL; struct tds_gss_auth *auth = (struct tds_gss_auth *) calloc(1, sizeof(struct tds_gss_auth)); if (!auth || !tds->login) return NULL; auth->tds_auth.free = tds_gss_free; auth->tds_auth.handle_next = tds_gss_handle_next; auth->gss_context = GSS_C_NO_CONTEXT; auth->last_stat = GSS_S_COMPLETE; server_name = tds_dstr_cstr(&tds->login->server_host_name); if (strchr(server_name, '.') == NULL) { struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_flags = AI_V4MAPPED|AI_ADDRCONFIG|AI_CANONNAME|AI_FQDN; if (!getaddrinfo(server_name, NULL, &hints, &addrs) && addrs->ai_canonname && strchr(addrs->ai_canonname, '.') != NULL) server_name = addrs->ai_canonname; } if (!tds_dstr_isempty(&tds->login->server_spn)) { auth->sname = strdup(tds_dstr_cstr(&tds->login->server_spn)); } else if (tds_dstr_isempty(&tds->login->server_realm_name)) { if (asprintf(&auth->sname, "MSSQLSvc/%s:%d", server_name, tds->login->port) < 0) auth->sname = NULL; } else { if (asprintf(&auth->sname, "MSSQLSvc/%s:%d@%s", server_name, tds->login->port, tds_dstr_cstr(&tds->login->server_realm_name)) < 0) auth->sname = NULL; } if (addrs) freeaddrinfo(addrs); if (auth->sname == NULL) { tds_gss_free(tds->conn, (TDSAUTHENTICATION *) auth); return NULL; } tdsdump_log(TDS_DBG_NETWORK, "using kerberos name %s\n", auth->sname); /* * Import the name into target_name. Use send_tok to save * local variable space. */ send_tok.value = auth->sname; send_tok.length = strlen(auth->sname); maj_stat = gss_import_name(&min_stat, &send_tok, &nt_principal, &auth->target_name); switch (maj_stat) { case GSS_S_COMPLETE: tdsdump_log(TDS_DBG_NETWORK, "gss_import_name: GSS_S_COMPLETE: gss_import_name completed successfully.\n"); if (TDS_FAILED(tds_gss_continue(tds, auth, GSS_C_NO_BUFFER))) { tds_gss_free(tds->conn, (TDSAUTHENTICATION *) auth); return NULL; } break; case GSS_S_BAD_NAMETYPE: tdsdump_log(TDS_DBG_NETWORK, "gss_import_name: GSS_S_BAD_NAMETYPE: The input_name_type was unrecognized.\n"); break; case GSS_S_BAD_NAME: tdsdump_log(TDS_DBG_NETWORK, "gss_import_name: GSS_S_BAD_NAME: The input_name parameter could not be interpreted as a name of the specified type.\n"); break; case GSS_S_BAD_MECH: tdsdump_log(TDS_DBG_NETWORK, "gss_import_name: GSS_S_BAD_MECH: The input name-type was GSS_C_NT_EXPORT_NAME, but the mechanism contained within the input-name is not supported.\n"); break; default: tdsdump_log(TDS_DBG_NETWORK, "gss_import_name: unexpected error %d.\n", maj_stat); break; } if (GSS_ERROR(maj_stat)) { tds_gss_free(tds->conn, (TDSAUTHENTICATION *) auth); return NULL; } return (TDSAUTHENTICATION *) auth; }
static int do_query(TDSSOCKET * tds, char *buf, int opt_flags) { int rows = 0; TDSRET rc; int i; TDSCOLUMN *col; int ctype; CONV_RESULT dres; unsigned char *src; TDS_INT srclen; TDS_INT resulttype; struct timeval start, stop; int print_rows = 1; char message[128]; rc = tds_submit_query(tds, buf); if (TDS_FAILED(rc)) { fprintf(stderr, "tds_submit_query() failed\n"); return 1; } while ((rc = tds_process_tokens(tds, &resulttype, NULL, TDS_TOKEN_RESULTS)) == TDS_SUCCESS) { const int stop_mask = TDS_STOPAT_ROWFMT|TDS_RETURN_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE; if (opt_flags & OPT_TIMER) { gettimeofday(&start, NULL); print_rows = 0; } switch (resulttype) { case TDS_ROWFMT_RESULT: if ((!(opt_flags & OPT_NOHEADER)) && tds->current_results) { for (i = 0; i < tds->current_results->num_cols; i++) { if (i) fputs(opt_col_term, stdout); fputs(tds_dstr_cstr(&tds->current_results->columns[i]->column_name), stdout); } fputs(opt_row_term, stdout); } break; case TDS_COMPUTE_RESULT: case TDS_ROW_RESULT: rows = 0; while ((rc = tds_process_tokens(tds, &resulttype, NULL, stop_mask)) == TDS_SUCCESS) { if (resulttype != TDS_ROW_RESULT && resulttype != TDS_COMPUTE_RESULT) break; rows++; if (!tds->current_results) continue; for (i = 0; i < tds->current_results->num_cols; i++) { col = tds->current_results->columns[i]; if (col->column_cur_size < 0) { if (print_rows) { if (i) fputs(opt_col_term, stdout); fputs("NULL", stdout); } continue; } ctype = tds_get_conversion_type(col->column_type, col->column_size); src = col->column_data; if (is_blob_col(col) && col->column_type != SYBVARIANT) src = (unsigned char *) ((TDSBLOB *) src)->textvalue; srclen = col->column_cur_size; if (tds_convert(tds_get_ctx(tds), ctype, (TDS_CHAR *) src, srclen, SYBVARCHAR, &dres) < 0) continue; if (print_rows) { if (i) fputs(opt_col_term, stdout); fputs(dres.c, stdout); } free(dres.c); } if (print_rows) fputs(opt_row_term, stdout); } if (!QUIET) fprintf(stdout, "(%d row%s affected)\n", rows, rows == 1 ? "" : "s"); break; case TDS_STATUS_RESULT: if (!QUIET) printf("(return status = %d)\n", tds->ret_status); break; default: break; } if (opt_flags & OPT_VERSION) { char version[64]; int line = 0; line = tds_version(tds->conn, version); if (line) { TDSMESSAGE msg; memset(&msg, 0, sizeof(TDSMESSAGE)); msg.server = "tsql"; sprintf(message, "using TDS version %s", version); msg.message = message; tsql_handle_message(tds_get_ctx(tds), tds, &msg); } } if (opt_flags & OPT_TIMER) { TDSMESSAGE msg; gettimeofday(&stop, NULL); sprintf(message, "Total time for processing %d rows: %ld msecs\n", rows, (long) ((stop.tv_sec - start.tv_sec) * 1000) + ((stop.tv_usec - start.tv_usec) / 1000)); memset(&msg, 0, sizeof(TDSMESSAGE)); msg.server = "tsql"; msg.message = message; tsql_handle_message(tds_get_ctx(tds), tds, &msg); } } return 0; }
/** * Read connection information from given DSN * @param DSN DSN name * @param login where to store connection info * @return 1 if success 0 otherwhise */ int odbc_get_dsn_info(TDS_ERRS *errs, const char *DSN, TDSLOGIN * login) { char tmp[FILENAME_MAX]; int freetds_conf_less = 1; /* use old servername */ if (myGetPrivateProfileString(DSN, odbc_param_Servername, tmp) > 0) { freetds_conf_less = 0; if (!tds_dstr_copy(&login->server_name, tmp)) { odbc_errs_add(errs, "HY001", NULL); return 0; } tds_read_conf_file(login, tmp); if (myGetPrivateProfileString(DSN, odbc_param_Server, tmp) > 0) { odbc_errs_add(errs, "HY000", "You cannot specify both SERVERNAME and SERVER"); return 0; } if (myGetPrivateProfileString(DSN, odbc_param_Address, tmp) > 0) { odbc_errs_add(errs, "HY000", "You cannot specify both SERVERNAME and ADDRESS"); return 0; } } /* search for server (compatible with ms one) */ if (freetds_conf_less) { int address_specified = 0; if (myGetPrivateProfileString(DSN, odbc_param_Address, tmp) > 0) { address_specified = 1; /* TODO parse like MS */ if (TDS_FAILED(tds_lookup_host_set(tmp, &login->ip_addrs))) { odbc_errs_add(errs, "HY000", "Error parsing ADDRESS attribute"); return 0; } } if (myGetPrivateProfileString(DSN, odbc_param_Server, tmp) > 0) { if (!tds_dstr_copy(&login->server_name, tmp)) { odbc_errs_add(errs, "HY001", NULL); return 0; } if (!address_specified) { if (!parse_server(errs, tmp, login)) return 0; } } } if (myGetPrivateProfileString(DSN, odbc_param_Port, tmp) > 0) tds_parse_conf_section(TDS_STR_PORT, tmp, login); if (myGetPrivateProfileString(DSN, odbc_param_TDS_Version, tmp) > 0) tds_parse_conf_section(TDS_STR_VERSION, tmp, login); if (myGetPrivateProfileString(DSN, odbc_param_Language, tmp) > 0) tds_parse_conf_section(TDS_STR_LANGUAGE, tmp, login); if (tds_dstr_isempty(&login->database) && myGetPrivateProfileString(DSN, odbc_param_Database, tmp) > 0) if (!tds_dstr_copy(&login->database, tmp)) { odbc_errs_add(errs, "HY001", NULL); return 0; } if (myGetPrivateProfileString(DSN, odbc_param_TextSize, tmp) > 0) tds_parse_conf_section(TDS_STR_TEXTSZ, tmp, login); if (myGetPrivateProfileString(DSN, odbc_param_PacketSize, tmp) > 0) tds_parse_conf_section(TDS_STR_BLKSZ, tmp, login); if (myGetPrivateProfileString(DSN, odbc_param_ClientCharset, tmp) > 0) tds_parse_conf_section(TDS_STR_CLCHARSET, tmp, login); if (myGetPrivateProfileString(DSN, odbc_param_DumpFile, tmp) > 0) tds_parse_conf_section(TDS_STR_DUMPFILE, tmp, login); if (myGetPrivateProfileString(DSN, odbc_param_DumpFileAppend, tmp) > 0) tds_parse_conf_section(TDS_STR_APPENDMODE, tmp, login); if (myGetPrivateProfileString(DSN, odbc_param_DebugFlags, tmp) > 0) tds_parse_conf_section(TDS_STR_DEBUGFLAGS, tmp, login); if (myGetPrivateProfileString(DSN, odbc_param_Encryption, tmp) > 0) tds_parse_conf_section(TDS_STR_ENCRYPTION, tmp, login); if (myGetPrivateProfileString(DSN, odbc_param_UseNTLMv2, tmp) > 0) tds_parse_conf_section(TDS_STR_USENTLMV2, tmp, login); if (myGetPrivateProfileString(DSN, odbc_param_REALM, tmp) > 0) tds_parse_conf_section(TDS_STR_REALM, tmp, login); if (myGetPrivateProfileString(DSN, odbc_param_ServerSPN, tmp) > 0) tds_parse_conf_section(TDS_STR_SPN, tmp, login); if (myGetPrivateProfileString(DSN, odbc_param_Trusted_Connection, tmp) > 0 && tds_config_boolean(odbc_param_Trusted_Connection, tmp, login)) { tds_dstr_empty(&login->user_name); tds_dstr_empty(&login->password); } if (myGetPrivateProfileString(DSN, odbc_param_MARS_Connection, tmp) > 0 && tds_config_boolean(odbc_param_MARS_Connection, tmp, login)) { login->mars = 1; } if (myGetPrivateProfileString(DSN, odbc_param_AttachDbFilename, tmp) > 0) tds_parse_conf_section(TDS_STR_DBFILENAME, tmp, login); return 1; }
/** * Send one row of data to server * \tds * \param bcpinfo BCP information * \param get_col_data function to call to retrieve data to be sent * \param ignored function to call if we try to send NULL if not allowed (not used) * \param offset passed to get_col_data and null_error to specify the row to get * \return TDS_SUCCESS or TDS_FAIL. */ TDSRET tds_bcp_send_record(TDSSOCKET *tds, TDSBCPINFO *bcpinfo, tds_bcp_get_col_data get_col_data, tds_bcp_null_error null_error, int offset) { TDSCOLUMN *bindcol; int i, start_col = bcpinfo->next_col; TDSRET rc; tdsdump_log(TDS_DBG_FUNC, "tds_bcp_send_bcp_record(%p, %p, %p, %p, %d)\n", tds, bcpinfo, get_col_data, null_error, offset); if (tds->out_flag != TDS_BULK || tds_set_state(tds, TDS_WRITING) != TDS_WRITING) return TDS_FAIL; if (start_col > 0) { bindcol = bcpinfo->bindinfo->columns[start_col - 1]; *bindcol->column_lenbind = MIN((TDS_INT) bindcol->column_bindlen - bcpinfo->text_sent, *bindcol->column_lenbind); tds_put_n(tds, bindcol->column_varaddr, *bindcol->column_lenbind); bcpinfo->text_sent += *bindcol->column_lenbind; if ((TDS_UINT) bcpinfo->text_sent < bindcol->column_bindlen) { return TDS_SUCCESS; /* That's all for now. */ } else if (!IS_TDS7_PLUS(tds->conn)) { bcpinfo->blob_cols++; } bcpinfo->next_col = 0; bcpinfo->text_sent = 0; } if (IS_TDS7_PLUS(tds->conn)) { if (start_col == 0) { tds_put_byte(tds, TDS_ROW_TOKEN); /* 0xd1 */ } for (i = start_col; i < bcpinfo->bindinfo->num_cols; i++) { TDS_INT save_size; unsigned char *save_data; TDSBLOB blob; int /* bool */ has_text = 0; bindcol = bcpinfo->bindinfo->columns[i]; /* * Don't send the (meta)data for timestamp columns or * identity columns unless indentity_insert is enabled. */ if ((!bcpinfo->identity_insert_on && bindcol->column_identity) || bindcol->column_timestamp || !tds_bcp_is_bound(bcpinfo, bindcol)) { continue; } rc = get_col_data(bcpinfo, bindcol, offset); if (rc == TDS_FAIL) { tdsdump_log(TDS_DBG_INFO1, "get_col_data (column %d) failed\n", i + 1); goto cleanup; } else if (rc != TDS_SUCCESS) { /* CS_BLK_HAS_TEXT? */ has_text = 1; } tdsdump_log(TDS_DBG_INFO1, "gotten column %d length %d null %d\n", i + 1, bindcol->bcp_column_data->datalen, bindcol->bcp_column_data->is_null); save_size = bindcol->column_cur_size; save_data = bindcol->column_data; assert(bindcol->column_data == NULL); if (bindcol->bcp_column_data->is_null) { if ( !bindcol->column_nullable && !is_nullable_type(bindcol->on_server.column_type) ) { return TDS_FAIL; } bindcol->column_cur_size = -1; } else if (has_text) { bindcol->column_cur_size = bindcol->bcp_column_data->datalen; } else if (is_blob_col(bindcol)) { bindcol->column_cur_size = bindcol->bcp_column_data->datalen; memset(&blob, 0, sizeof(blob)); blob.textvalue = (TDS_CHAR *) bindcol->bcp_column_data->data; bindcol->column_data = (unsigned char *) &blob; } else { bindcol->column_cur_size = bindcol->bcp_column_data->datalen; bindcol->column_data = bindcol->bcp_column_data->data; } rc = bindcol->funcs->put_data(tds, bindcol, 1); bindcol->column_cur_size = save_size; bindcol->column_data = save_data; if (TDS_FAILED(rc)) goto cleanup; else if (has_text) { bcpinfo->next_col = i + 1; /* bcpinfo->text_sent = 0; */ break; } } } /* IS_TDS7_PLUS */ else { if (start_col == 0) { int row_pos; int row_sz_pos; int var_cols_written = 0; TDS_INT old_record_size = bcpinfo->bindinfo->row_size; unsigned char *record = bcpinfo->bindinfo->current_row; memset(record, '\0', old_record_size); /* zero the rowbuffer */ /* * offset 0 = number of var columns * offset 1 = row number. zeroed (datasever assigns) */ row_pos = 2; rc = TDS_FAIL; if ((row_pos = tds_bcp_add_fixed_columns(bcpinfo, get_col_data, null_error, offset, record, row_pos)) < 0) goto cleanup; row_sz_pos = row_pos; /* potential variable columns to write */ if ((row_pos = tds_bcp_add_variable_columns(bcpinfo, get_col_data, null_error, offset, record, row_pos, &var_cols_written)) < 0) goto cleanup; if (var_cols_written) { TDS_PUT_UA2(&record[row_sz_pos], row_pos); record[0] = var_cols_written; } tdsdump_log(TDS_DBG_INFO1, "old_record_size = %d new size = %d \n", old_record_size, row_pos); tds_put_smallint(tds, row_pos); tds_put_n(tds, record, row_pos); /* row is done, now handle any text/image data */ bcpinfo->blob_cols = 0; } for (i = start_col; i < bcpinfo->bindinfo->num_cols; i++) { bindcol = bcpinfo->bindinfo->columns[i]; if (is_blob_type(bindcol->column_type)) { /* Elide trailing NULLs */ if (bindcol->bcp_column_data->is_null) { int j; for (j = i + 1; j < bcpinfo->bindinfo->num_cols; ++j) { TDSCOLUMN *bindcol2 = bcpinfo->bindinfo->columns[j]; if (is_blob_type(bindcol2->column_type) && !bindcol2->bcp_column_data->is_null) { break; } } if (j == bcpinfo->bindinfo->num_cols) { i = j; break; } } rc = get_col_data(bcpinfo, bindcol, offset); if (rc == TDS_FAIL) goto cleanup; /* unknown but zero */ tds_put_smallint(tds, 0); tds_put_byte(tds, (unsigned char) bindcol->column_type); tds_put_byte(tds, 0xff - bcpinfo->blob_cols); /* * offset of txptr we stashed during variable * column processing */ tds_put_smallint(tds, bindcol->column_textpos); tds_put_int(tds, bindcol->bcp_column_data->datalen); if (rc != TDS_SUCCESS) { /* CS_BLK_HAS_TEXT? */ bcpinfo->next_col = i + 1; /* bcpinfo->text_sent = 0; */ break; } tds_put_n(tds, bindcol->bcp_column_data->data, bindcol->bcp_column_data->datalen); bcpinfo->blob_cols++; } } } if (i == bcpinfo->bindinfo->num_cols) { tds_set_state(tds, TDS_SENDING); bcpinfo->next_col = 0; } return TDS_SUCCESS; cleanup: tds_set_state(tds, TDS_SENDING); return rc; }
/* Also used to scan ODBC.INI entries */ void tds_parse_conf_section(const char *option, const char *value, void *param) { TDSLOGIN *login = (TDSLOGIN *) param; void *s = param; tdsdump_log(TDS_DBG_INFO1, "\t%s = '%s'\n", option, value); if (!strcmp(option, TDS_STR_VERSION)) { tds_config_verstr(value, login); } else if (!strcmp(option, TDS_STR_BLKSZ)) { int val = atoi(value); if (val >= 512 && val < 65536) login->block_size = val; } else if (!strcmp(option, TDS_STR_SWAPDT)) { /* this option is deprecated, just check value for compatibility */ tds_config_boolean(option, value, login); } else if (!strcmp(option, TDS_GSSAPI_DELEGATION)) { /* gssapi flag addition */ login->gssapi_use_delegation = tds_config_boolean(option, value, login); } else if (!strcmp(option, TDS_STR_DUMPFILE)) { s = tds_dstr_copy(&login->dump_file, value); } else if (!strcmp(option, TDS_STR_DEBUGFLAGS)) { char *end; long flags; flags = strtol(value, &end, 0); if (*value != '\0' && *end == '\0' && flags != LONG_MIN && flags != LONG_MAX) login->debug_flags = flags; } else if (!strcmp(option, TDS_STR_TIMEOUT) || !strcmp(option, TDS_STR_QUERY_TIMEOUT)) { if (atoi(value)) login->query_timeout = atoi(value); } else if (!strcmp(option, TDS_STR_CONNTIMEOUT)) { if (atoi(value)) login->connect_timeout = atoi(value); } else if (!strcmp(option, TDS_STR_HOST)) { char tmp[128]; struct addrinfo *addrs; if (TDS_FAILED(tds_lookup_host_set(value, &login->ip_addrs))) { tdsdump_log(TDS_DBG_WARN, "Found host entry %s however name resolution failed. \n", value); return; } tdsdump_log(TDS_DBG_INFO1, "Found host entry %s \n", value); s = tds_dstr_copy(&login->server_host_name, value); for (addrs = login->ip_addrs; addrs != NULL; addrs = addrs->ai_next) tdsdump_log(TDS_DBG_INFO1, "IP addr is %s.\n", tds_addrinfo2str(addrs, tmp, sizeof(tmp))); } else if (!strcmp(option, TDS_STR_PORT)) { if (atoi(value)) login->port = atoi(value); } else if (!strcmp(option, TDS_STR_EMUL_LE)) { login->emul_little_endian = tds_config_boolean(option, value, login); } else if (!strcmp(option, TDS_STR_TEXTSZ)) { if (atoi(value)) login->text_size = atoi(value); } else if (!strcmp(option, TDS_STR_CHARSET)) { s = tds_dstr_copy(&login->server_charset, value); tdsdump_log(TDS_DBG_INFO1, "%s is %s.\n", option, tds_dstr_cstr(&login->server_charset)); } else if (!strcmp(option, TDS_STR_CLCHARSET)) { s = tds_dstr_copy(&login->client_charset, value); tdsdump_log(TDS_DBG_INFO1, "tds_parse_conf_section: %s is %s.\n", option, tds_dstr_cstr(&login->client_charset)); } else if (!strcmp(option, TDS_STR_USE_UTF_16)) { login->use_utf16 = tds_config_boolean(option, value, login); } else if (!strcmp(option, TDS_STR_LANGUAGE)) { s = tds_dstr_copy(&login->language, value); } else if (!strcmp(option, TDS_STR_APPENDMODE)) { tds_g_append_mode = tds_config_boolean(option, value, login); } else if (!strcmp(option, TDS_STR_INSTANCE)) { s = tds_dstr_copy(&login->instance_name, value); } else if (!strcmp(option, TDS_STR_ENCRYPTION)) { tds_config_encryption(value, login); } else if (!strcmp(option, TDS_STR_ASA_DATABASE)) { s = tds_dstr_copy(&login->server_name, value); } else if (!strcmp(option, TDS_STR_USENTLMV2)) { login->use_ntlmv2 = tds_config_boolean(option, value, login); } else if (!strcmp(option, TDS_STR_USELANMAN)) { login->use_lanman = tds_config_boolean(option, value, login); } else if (!strcmp(option, TDS_STR_REALM)) { s = tds_dstr_copy(&login->server_realm_name, value); } else if (!strcmp(option, TDS_STR_SPN)) { s = tds_dstr_copy(&login->server_spn, value); } else if (!strcmp(option, TDS_STR_CAFILE)) { s = tds_dstr_copy(&login->cafile, value); } else if (!strcmp(option, TDS_STR_CRLFILE)) { s = tds_dstr_copy(&login->crlfile, value); } else if (!strcmp(option, TDS_STR_CHECKSSLHOSTNAME)) { login->check_ssl_hostname = tds_config_boolean(option, value, login); } else if (!strcmp(option, TDS_STR_DBFILENAME)) { s = tds_dstr_copy(&login->db_filename, value); } else if (!strcmp(option, TDS_STR_DATABASE)) { s = tds_dstr_copy(&login->database, value); } else if (!strcmp(option, TDS_STR_READONLY_INTENT)) { login->readonly_intent = tds_config_boolean(option, value, login); tdsdump_log(TDS_DBG_FUNC, "Setting ReadOnly Intent to '%s'.\n", value); } else { tdsdump_log(TDS_DBG_INFO1, "UNRECOGNIZED option '%s' ... ignoring.\n", option); } if (!s) login->valid_configuration = 0; }
/** * Initialize BCP information. * Query structure of the table to server. * \tds * \param bcpinfo BCP information to initialize. Structure should be allocate * and table name and direction should be already set. */ TDSRET tds_bcp_init(TDSSOCKET *tds, TDSBCPINFO *bcpinfo) { TDSRESULTINFO *resinfo; TDSRESULTINFO *bindinfo = NULL; TDSCOLUMN *curcol; TDS_INT result_type; int i; TDSRET rc; const char *fmt; /* FIXME don't leave state in processing state */ /* TODO quote tablename if needed */ if (bcpinfo->direction != TDS_BCP_QUERYOUT) fmt = "SET FMTONLY ON select * from %s SET FMTONLY OFF"; else fmt = "SET FMTONLY ON %s SET FMTONLY OFF"; if (TDS_FAILED(rc=tds_submit_queryf(tds, fmt, bcpinfo->tablename))) /* TODO return an error ?? */ /* Attempt to use Bulk Copy with a non-existent Server table (might be why ...) */ return rc; /* TODO possibly stop at ROWFMT and copy before going to idle */ /* TODO check what happen if table is not present, cleanup on error */ while ((rc = tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS)) == TDS_SUCCESS) continue; if (TDS_FAILED(rc)) return rc; /* copy the results info from the TDS socket */ if (!tds->res_info) return TDS_FAIL; resinfo = tds->res_info; if ((bindinfo = tds_alloc_results(resinfo->num_cols)) == NULL) { rc = TDS_FAIL; goto cleanup; } bindinfo->row_size = resinfo->row_size; /* Copy the column metadata */ rc = TDS_FAIL; for (i = 0; i < bindinfo->num_cols; i++) { curcol = bindinfo->columns[i]; /* * TODO use memcpy ?? * curcol and resinfo->columns[i] are both TDSCOLUMN. * Why not "curcol = resinfo->columns[i];"? Because the rest of TDSCOLUMN (below column_timestamp) * isn't being used. Perhaps this "upper" part of TDSCOLUMN should be a substructure. * Or, see if the "lower" part is unused (and zeroed out) at this point, and just do one assignment. */ curcol->funcs = resinfo->columns[i]->funcs; curcol->column_type = resinfo->columns[i]->column_type; curcol->column_usertype = resinfo->columns[i]->column_usertype; curcol->column_flags = resinfo->columns[i]->column_flags; if (curcol->column_varint_size == 0) curcol->column_cur_size = resinfo->columns[i]->column_cur_size; else curcol->column_cur_size = -1; curcol->column_size = resinfo->columns[i]->column_size; curcol->column_varint_size = resinfo->columns[i]->column_varint_size; curcol->column_prec = resinfo->columns[i]->column_prec; curcol->column_scale = resinfo->columns[i]->column_scale; curcol->on_server.column_type = resinfo->columns[i]->on_server.column_type; curcol->on_server.column_size = resinfo->columns[i]->on_server.column_size; curcol->char_conv = resinfo->columns[i]->char_conv; if (!tds_dstr_dup(&curcol->column_name, &resinfo->columns[i]->column_name)) goto cleanup; if (!tds_dstr_dup(&curcol->table_column_name, &resinfo->columns[i]->table_column_name)) goto cleanup; curcol->column_nullable = resinfo->columns[i]->column_nullable; curcol->column_identity = resinfo->columns[i]->column_identity; curcol->column_timestamp = resinfo->columns[i]->column_timestamp; memcpy(curcol->column_collation, resinfo->columns[i]->column_collation, 5); if (is_numeric_type(curcol->column_type)) { curcol->bcp_column_data = tds_alloc_bcp_column_data(sizeof(TDS_NUMERIC)); ((TDS_NUMERIC *) curcol->bcp_column_data->data)->precision = curcol->column_prec; ((TDS_NUMERIC *) curcol->bcp_column_data->data)->scale = curcol->column_scale; } else if (bcpinfo->bind_count != 0 /* ctlib */ && is_blob_col(curcol)) { curcol->bcp_column_data = tds_alloc_bcp_column_data(0); } else { curcol->bcp_column_data = tds_alloc_bcp_column_data(MAX(curcol->column_size,curcol->on_server.column_size)); } if (!curcol->bcp_column_data) goto cleanup; } if (!IS_TDS7_PLUS(tds->conn)) { bindinfo->current_row = (unsigned char*) malloc(bindinfo->row_size); if (!bindinfo->current_row) goto cleanup; bindinfo->row_free = tds_bcp_row_free; } if (bcpinfo->identity_insert_on) { rc = tds_submit_queryf(tds, "set identity_insert %s on", bcpinfo->tablename); if (TDS_FAILED(rc)) goto cleanup; /* TODO use tds_process_simple_query */ while ((rc = tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS)) == TDS_SUCCESS) { } if (rc != TDS_NO_MORE_RESULTS) goto cleanup; } bcpinfo->bindinfo = bindinfo; bcpinfo->bind_count = 0; return TDS_SUCCESS; cleanup: tds_free_results(bindinfo); return rc; }