📄 blk.c
字号:
/* FreeTDS - Library of routines accessing Sybase and Microsoft databases * Copyright (C) 1998-2004, 2005 Brian Bruns, Bill Thompson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */#if HAVE_CONFIG_H#include <config.h>#endif#include <stdarg.h>#include <stdio.h>#if HAVE_STDLIB_H#include <stdlib.h>#endif /* HAVE_STDLIB_H */#if HAVE_STRING_H#include <string.h>#endif /* HAVE_STRING_H */#include "bkpublic.h"#include "ctpublic.h"#include "ctlib.h"#include "replacements.h"typedef struct _pbcb{ char *pb; unsigned int cb;} TDS_PBCB;TDS_RCSID(var, "$Id: blk.c,v 1.43 2007/12/31 10:06:49 freddy77 Exp $");static CS_RETCODE _blk_get_col_data(CS_BLKDESC *, TDSCOLUMN *, int );static int _blk_add_variable_columns(CS_BLKDESC * blkdesc, int offset, unsigned char * rowbuffer, int start, int *var_cols);static CS_RETCODE _blk_add_fixed_columns(CS_BLKDESC * blkdesc, int offset, unsigned char * rowbuffer, int start);static CS_RETCODE _blk_build_bcp_record(CS_BLKDESC *blkdesc, CS_INT offset);static CS_RETCODE _blk_send_colmetadata(CS_BLKDESC * blkdesc);static CS_RETCODE _blk_build_bulk_insert_stmt(TDS_PBCB * clause, TDSCOLUMN * bcpcol, int first);static CS_RETCODE _rowxfer_in_init(CS_BLKDESC * blkdesc);static CS_RETCODE _blk_rowxfer_in(CS_BLKDESC * blkdesc, CS_INT rows_to_xfer, CS_INT * rows_xferred);static CS_RETCODE _blk_rowxfer_out(CS_BLKDESC * blkdesc, CS_INT rows_to_xfer, CS_INT * rows_xferred);CS_RETCODEblk_alloc(CS_CONNECTION * connection, CS_INT version, CS_BLKDESC ** blk_pointer){ tdsdump_log(TDS_DBG_FUNC, "blk_alloc()\n"); *blk_pointer = (CS_BLKDESC *) malloc(sizeof(CS_BLKDESC)); memset(*blk_pointer, '\0', sizeof(CS_BLKDESC)); /* so we know who we belong to */ (*blk_pointer)->con = connection; return CS_SUCCEED;}CS_RETCODEblk_bind(CS_BLKDESC * blkdesc, CS_INT item, CS_DATAFMT * datafmt, CS_VOID * buffer, CS_INT * datalen, CS_SMALLINT * indicator){ TDSCOLUMN *colinfo; CS_CONNECTION *con; CS_INT bind_count; int i; tdsdump_log(TDS_DBG_FUNC, "blk_bind()\n"); if (!blkdesc) { return CS_FAIL; } con = blkdesc->con; if (item == CS_UNUSED) { /* clear all bindings */ if (datafmt == NULL && buffer == NULL && datalen == NULL && indicator == NULL ) { blkdesc->bind_count = CS_UNUSED; for (i = 0; i < blkdesc->bindinfo->num_cols; i++ ) { colinfo = blkdesc->bindinfo->columns[i]; colinfo->column_varaddr = NULL; colinfo->column_bindtype = 0; colinfo->column_bindfmt = 0; colinfo->column_bindlen = 0; colinfo->column_nullbind = NULL; colinfo->column_lenbind = NULL; } } return CS_SUCCEED; } /* check item value */ if (item < 1 || item > blkdesc->bindinfo->num_cols) { _ctclient_msg(con, "blk_bind", 2, 5, 1, 141, "%s, %d", "colnum", item); return CS_FAIL; } /* clear bindings for this column */ if (datafmt == NULL && buffer == NULL && datalen == NULL && indicator == NULL ) { colinfo = blkdesc->bindinfo->columns[item - 1]; colinfo->column_varaddr = NULL; colinfo->column_bindtype = 0; colinfo->column_bindfmt = 0; colinfo->column_bindlen = 0; colinfo->column_nullbind = NULL; colinfo->column_lenbind = NULL; return CS_SUCCEED; } /* * check whether the request is for array binding and ensure that user * supplies the same datafmt->count to the subsequent ct_bind calls */ bind_count = (datafmt->count == 0) ? 1 : datafmt->count; /* first bind for this result set */ if (blkdesc->bind_count == CS_UNUSED) { blkdesc->bind_count = bind_count; } else { /* all subsequent binds for this result set - the bind counts must be the same */ if (blkdesc->bind_count != bind_count) { _ctclient_msg(con, "blk_bind", 1, 1, 1, 137, "%d, %d", bind_count, blkdesc->bind_count); return CS_FAIL; } } /* bind the column_varaddr to the address of the buffer */ colinfo = blkdesc->bindinfo->columns[item - 1]; colinfo->column_varaddr = (char *) buffer; colinfo->column_bindtype = datafmt->datatype; colinfo->column_bindfmt = datafmt->format; colinfo->column_bindlen = datafmt->maxlength; if (indicator) { colinfo->column_nullbind = indicator; } if (datalen) { colinfo->column_lenbind = datalen; } return CS_SUCCEED;}CS_RETCODEblk_colval(SRV_PROC * srvproc, CS_BLKDESC * blkdescp, CS_BLK_ROW * rowp, CS_INT colnum, CS_VOID * valuep, CS_INT valuelen, CS_INT * outlenp){ tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_colval()\n"); return CS_FAIL;}CS_RETCODEblk_default(CS_BLKDESC * blkdesc, CS_INT colnum, CS_VOID * buffer, CS_INT buflen, CS_INT * outlen){ tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_default()\n"); return CS_FAIL;}CS_RETCODEblk_describe(CS_BLKDESC * blkdesc, CS_INT item, CS_DATAFMT * datafmt){ TDSCOLUMN *curcol; int len; tdsdump_log(TDS_DBG_FUNC, "blk_describe()\n"); if (item < 1 || item > blkdesc->bindinfo->num_cols) { _ctclient_msg(blkdesc->con, "blk_describe", 2, 5, 1, 141, "%s, %d", "colnum", item); return CS_FAIL; } curcol = blkdesc->bindinfo->columns[item - 1]; len = curcol->column_namelen; if (len >= CS_MAX_NAME) len = CS_MAX_NAME - 1; strncpy(datafmt->name, curcol->column_name, len); /* name is always null terminated */ datafmt->name[len] = 0; datafmt->namelen = len; /* need to turn the SYBxxx into a CS_xxx_TYPE */ datafmt->datatype = _ct_get_client_type(curcol->column_type, curcol->column_usertype, curcol->column_size); tdsdump_log(TDS_DBG_INFO1, "blk_describe() datafmt->datatype = %d server type %d\n", datafmt->datatype, curcol->column_type); /* FIXME is ok this value for numeric/decimal? */ datafmt->maxlength = curcol->column_size; datafmt->usertype = curcol->column_usertype; datafmt->precision = curcol->column_prec; datafmt->scale = curcol->column_scale; /* * There are other options that can be returned, but these are the * only two being noted via the TDS layer. */ datafmt->status = 0; if (curcol->column_nullable) datafmt->status |= CS_CANBENULL; if (curcol->column_identity) datafmt->status |= CS_IDENTITY; datafmt->count = 1; datafmt->locale = NULL; return CS_SUCCEED;}CS_RETCODEblk_done(CS_BLKDESC * blkdesc, CS_INT type, CS_INT * outrow){ TDSSOCKET *tds; tdsdump_log(TDS_DBG_FUNC, "blk_done()\n"); tds = blkdesc->con->tds_socket; switch (type) { case CS_BLK_BATCH: tds_flush_packet(tds); /* TODO correct ?? */ tds_set_state(tds, TDS_PENDING); if (tds_process_simple_query(tds) != TDS_SUCCEED) { _ctclient_msg(blkdesc->con, "blk_done", 2, 5, 1, 140, ""); return CS_FAIL; } if (outrow) *outrow = tds->rows_affected; tds_submit_query(tds, blkdesc->insert_stmt); if (tds_process_simple_query(tds) != TDS_SUCCEED) { _ctclient_msg(blkdesc->con, "blk_done", 2, 5, 1, 140, ""); return CS_FAIL; } tds->out_flag = TDS_BULK; if (IS_TDS7_PLUS(tds)) { _blk_send_colmetadata(blkdesc); } break; case CS_BLK_ALL: tds_flush_packet(tds); /* TODO correct ?? */ tds_set_state(tds, TDS_PENDING); if (tds_process_simple_query(tds) != TDS_SUCCEED) { _ctclient_msg(blkdesc->con, "blk_done", 2, 5, 1, 140, ""); return CS_FAIL; } if (outrow) *outrow = tds->rows_affected; /* free allocated storage in blkdesc & initialise flags, etc. */ if (blkdesc->tablename) TDS_ZERO_FREE(blkdesc->tablename); if (blkdesc->insert_stmt) TDS_ZERO_FREE(blkdesc->insert_stmt); if (blkdesc->bindinfo) { tds_free_results(blkdesc->bindinfo); blkdesc->bindinfo = NULL; } blkdesc->direction = 0; blkdesc->bind_count = CS_UNUSED; blkdesc->xfer_init = 0; blkdesc->var_cols = 0; break; } return CS_SUCCEED;}CS_RETCODEblk_drop(CS_BLKDESC * blkdesc){ if (!blkdesc) return CS_SUCCEED; free(blkdesc->tablename); free(blkdesc->insert_stmt); tds_free_results(blkdesc->bindinfo); free(blkdesc); return CS_SUCCEED;}CS_RETCODEblk_getrow(SRV_PROC * srvproc, CS_BLKDESC * blkdescp, CS_BLK_ROW * rowp){ tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_getrow()\n"); return CS_FAIL;}CS_RETCODEblk_gettext(SRV_PROC * srvproc, CS_BLKDESC * blkdescp, CS_BLK_ROW * rowp, CS_INT bufsize, CS_INT * outlenp){ tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_gettext()\n"); return CS_FAIL;}CS_RETCODEblk_init(CS_BLKDESC * blkdesc, CS_INT direction, CS_CHAR * tablename, CS_INT tnamelen){ TDSCOLUMN *curcol; TDSSOCKET *tds; TDSRESULTINFO *resinfo; TDSRESULTINFO *bindinfo; TDS_INT result_type; int i, rc; tdsdump_log(TDS_DBG_FUNC, "blk_init()\n"); if (!blkdesc) { return CS_FAIL; } if (direction != CS_BLK_IN && direction != CS_BLK_OUT ) { _ctclient_msg(blkdesc->con, "blk_init", 2, 6, 1, 138, ""); return CS_FAIL; } if (!tablename) { _ctclient_msg(blkdesc->con, "blk_init", 2, 6, 1, 139, ""); return CS_FAIL; } if (tnamelen == CS_NULLTERM) tnamelen = strlen(tablename); /* free allocated storage in blkdesc & initialise flags, etc. */ if (blkdesc->tablename) { tdsdump_log(TDS_DBG_FUNC, "blk_init() freeing tablename\n"); free(blkdesc->tablename); } if (blkdesc->insert_stmt) { tdsdump_log(TDS_DBG_FUNC, "blk_init() freeing insert_stmt\n"); TDS_ZERO_FREE(blkdesc->insert_stmt); } if (blkdesc->bindinfo) { tdsdump_log(TDS_DBG_FUNC, "blk_init() freeing results\n"); tds_free_results(blkdesc->bindinfo); blkdesc->bindinfo = NULL; } /* string can be no-nul terminated so copy with memcpy */ blkdesc->tablename = (char *) malloc(tnamelen + 1); /* FIXME malloc can fail */ memcpy(blkdesc->tablename, tablename, tnamelen); blkdesc->tablename[tnamelen] = 0; blkdesc->direction = direction; blkdesc->bind_count = CS_UNUSED; blkdesc->xfer_init = 0; blkdesc->var_cols = 0; tds = blkdesc->con->tds_socket; /* TODO quote tablename if needed */ if (tds_submit_queryf(tds, "select * from %s where 0 = 1", blkdesc->tablename) == TDS_FAIL) { _ctclient_msg(blkdesc->con, "blk_init", 2, 5, 1, 140, ""); return CS_FAIL; } while ((rc = tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS)) == TDS_SUCCEED) { } if (rc != TDS_NO_MORE_RESULTS) { _ctclient_msg(blkdesc->con, "blk_init", 2, 5, 1, 140, ""); return CS_FAIL; } /* copy the results info from the TDS socket into CS_BLKDESC structure */ if (!tds->res_info) { _ctclient_msg(blkdesc->con, "blk_init", 2, 5, 1, 140, ""); return CS_FAIL; } resinfo = tds->res_info; if ((bindinfo = tds_alloc_results(resinfo->num_cols)) == NULL) { _ctclient_msg(blkdesc->con, "blk_init", 2, 5, 1, 140, ""); return CS_FAIL; } bindinfo->row_size = resinfo->row_size; for (i = 0; i < bindinfo->num_cols; i++) { curcol = bindinfo->columns[i]; curcol->column_type = resinfo->columns[i]->column_type; curcol->column_usertype = resinfo->columns[i]->column_usertype; curcol->column_flags = resinfo->columns[i]->column_flags; 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->column_namelen = resinfo->columns[i]->column_namelen; 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; memcpy(curcol->column_name, resinfo->columns[i]->column_name, resinfo->columns[i]->column_namelen); if (curcol->table_column_name) TDS_ZERO_FREE(curcol->table_column_name); if (resinfo->columns[i]->table_column_name) curcol->table_column_name = strdup(resinfo->columns[i]->table_column_name); 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 { curcol->bcp_column_data = tds_alloc_bcp_column_data(curcol->on_server.column_size); } } /* TODO check */ tds_alloc_row(bindinfo); blkdesc->bindinfo = bindinfo; blkdesc->bind_count = CS_UNUSED; if (blkdesc->identity_insert_on) { if (tds_submit_queryf(tds, "set identity_insert %s on", blkdesc->tablename) == TDS_FAIL) { _ctclient_msg(blkdesc->con, "blk_init", 2, 5, 1, 140, ""); return CS_FAIL; } while ((rc = tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS)) == TDS_SUCCEED) { } if (rc != TDS_NO_MORE_RESULTS) { _ctclient_msg(blkdesc->con, "blk_init", 2, 5, 1, 140, ""); return CS_FAIL; } } return CS_SUCCEED;}CS_RETCODEblk_props(CS_BLKDESC * blkdesc, CS_INT action, CS_INT property, CS_VOID * buffer, CS_INT buflen, CS_INT * outlen){ int retval; int intval; switch (property) { case BLK_IDENTITY: switch (action) { case CS_SET: if (buffer) { memcpy(&intval, buffer, sizeof(intval)); if (intval == CS_TRUE) blkdesc->identity_insert_on = 1; if (intval == CS_FALSE) blkdesc->identity_insert_on = 0; } return CS_SUCCEED; break; case CS_GET: retval = blkdesc->identity_insert_on == 1 ? CS_TRUE : CS_FALSE ; if (buffer) { memcpy (buffer, &retval, sizeof(retval)); if (outlen) *outlen = sizeof(retval); } return CS_SUCCEED; break; default: _ctclient_msg(blkdesc->con, "blk_props", 2, 5, 1, 141, "%s, %d", "action", action); break; } break; default: _ctclient_msg(blkdesc->con, "blk_props", 2, 5, 1, 141, "%s, %d", "property", property); break; } return CS_FAIL;}CS_RETCODEblk_rowalloc(SRV_PROC * srvproc, CS_BLK_ROW ** row){ tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_rowalloc()\n"); return CS_FAIL;}CS_RETCODEblk_rowdrop(SRV_PROC * srvproc, CS_BLK_ROW * row){ tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_rowdrop()\n"); return CS_FAIL;}CS_RETCODEblk_rowxfer(CS_BLKDESC * blkdesc){ CS_INT row_count = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -