?? ct.c
字號(hào):
/* FreeTDS - Library of routines accessing Sybase and Microsoft databases * Copyright (C) 1998, 1999, 2000, 2001 Brian Bruns * Copyright (C) 2002, 2003, 2004, 2005 James K. Lowden * * 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 /* HAVE_CONFIG_H */#include <stdarg.h>#include <stdio.h>#include <assert.h>#if HAVE_STDLIB_H#include <stdlib.h>#endif /* HAVE_STDLIB_H */#if HAVE_STRING_H#include <string.h>#endif /* HAVE_STRING_H */#include "ctpublic.h"#include "ctlib.h"#include "tdsstring.h"#include "replacements.h"TDS_RCSID(var, "$Id: ct.c,v 1.177 2007/12/21 15:23:24 freddy77 Exp $");static char * ct_describe_cmd_state(CS_INT state);/** * Read a row of data * @return 0 on success */static int _ct_fetch_cursor(CS_COMMAND * cmd, CS_INT type, CS_INT offset, CS_INT option, CS_INT * rows_read);int _ct_get_client_type(int datatype, int usertype, int size);static int _ct_fetchable_results(CS_COMMAND * cmd);static int _ct_process_return_status(TDSSOCKET * tds);static int _ct_fill_param(CS_INT cmd_type, CS_PARAM * param, CS_DATAFMT * datafmt, CS_VOID * data, CS_INT * datalen, CS_SMALLINT * indicator, CS_BYTE byvalue);void _ctclient_msg(CS_CONNECTION * con, const char *funcname, int layer, int origin, int severity, int number, const char *fmt, ...);int _ct_bind_data(CS_CONTEXT *ctx, TDSRESULTINFO * resinfo, TDSRESULTINFO *bindinfo, CS_INT offset);static void _ct_initialise_cmd(CS_COMMAND *cmd);static CS_RETCODE _ct_cancel_cleanup(CS_COMMAND * cmd);static CS_RETCODE _ct_cmd_drop(CS_COMMAND * cmd, CS_INT free_conn_ref);/* Added for CT_DIAG *//* Code changes starts here - CT_DIAG - 01 */static CS_INT ct_diag_storeclientmsg(CS_CONTEXT * context, CS_CONNECTION * conn, CS_CLIENTMSG * message);static CS_INT ct_diag_storeservermsg(CS_CONTEXT * context, CS_CONNECTION * conn, CS_SERVERMSG * message);static CS_INT ct_diag_countmsg(CS_CONTEXT * context, CS_INT type, CS_INT * count);static CS_INT ct_diag_getclientmsg(CS_CONTEXT * context, CS_INT idx, CS_CLIENTMSG * message);static CS_INT ct_diag_getservermsg(CS_CONTEXT * context, CS_INT idx, CS_SERVERMSG * message);/* Code changes ends here - CT_DIAG - 01 *//* Added code for RPC functionality -SUHA *//* RPC Code changes starts here */static void rpc_clear(CSREMOTE_PROC * rpc);static void param_clear(CSREMOTE_PROC_PARAM * pparam);static TDSPARAMINFO *paraminfoalloc(TDSSOCKET * tds, CS_PARAM * first_param);static CS_DYNAMIC * _ct_allocate_dynamic(CS_CONNECTION * con, char *id, int idlen);static CS_INT _ct_deallocate_dynamic(CS_CONNECTION * con, CS_DYNAMIC *dyn);static CS_DYNAMIC * _ct_locate_dynamic(CS_CONNECTION * con, char *id, int idlen);/* RPC Code changes ends here */static const char *_ct_get_layer(int layer){ switch (layer) { case 1: return "user api layer"; break; case 2: return "blk layer"; break; default: break; } return "unrecognized layer";}static const char *_ct_get_origin(int origin){ switch (origin) { case 1: return "external error"; break; case 2: return "internal CT-Library error"; break; case 4: return "common library error"; break; case 5: return "intl library error"; break; case 6: return "user error"; break; case 7: return "internal BLK-Library error"; break; default: break; } return "unrecognized origin";}static const char *_ct_get_user_api_layer_error(int error){ switch (error) { case 137: return "A bind count of %1! is not consistent with the count supplied for existing binds. The current bind count is %2!."; break; case 138: return "Use direction CS_BLK_IN or CS_BLK_OUT for a bulk copy operation."; break; case 139: return "The parameter tblname cannot be NULL."; break; case 140: return "Failed when processing results from server."; break; case 141: return "Parameter %1! has an illegal value of %2!"; break; case 142: return "No value or default value available and NULL not allowed. col = %1! row = %2! ."; break; case 143: return "parameter name(s) must be supplied for LANGUAGE command."; break; case 16843163: return "This routine cannot be called when the command structure is idle."; break; default: break; } return "unrecognized error";}static char *_ct_get_msgstr(const char *funcname, int layer, int origin, int severity, int number){ char *m; if (asprintf(&m, "%s: %s: %s: %s", funcname, _ct_get_layer(layer), _ct_get_origin(origin), _ct_get_user_api_layer_error(number) ) < 0) { return NULL; } return m;}void_ctclient_msg(CS_CONNECTION * con, const char *funcname, int layer, int origin, int severity, int number, const char *fmt, ...){ CS_CONTEXT *ctx = con->ctx; va_list ap; CS_CLIENTMSG cm; char *msgstr; va_start(ap, fmt); if (ctx->_clientmsg_cb) { cm.severity = severity; cm.msgnumber = (((layer << 24) & 0xFF000000) | ((origin << 16) & 0x00FF0000) | ((severity << 8) & 0x0000FF00) | ((number) & 0x000000FF)); msgstr = _ct_get_msgstr(funcname, layer, origin, severity, number); tds_vstrbuild(cm.msgstring, CS_MAX_MSG, &(cm.msgstringlen), msgstr, CS_NULLTERM, fmt, CS_NULLTERM, ap); cm.msgstring[cm.msgstringlen] = '\0'; free(msgstr); cm.osnumber = 0; cm.osstring[0] = '\0'; cm.osstringlen = 0; cm.status = 0; /* cm.sqlstate */ cm.sqlstatelen = 0; ctx->_clientmsg_cb(ctx, con, &cm); } va_end(ap);}static CS_RETCODEct_set_command_state(CS_COMMAND *cmd, CS_INT state) { tdsdump_log(TDS_DBG_FUNC, "setting command state from %s to %s\n", ct_describe_cmd_state(cmd->command_state), ct_describe_cmd_state(state)); cmd->command_state = state; return CS_SUCCEED;}static char *ct_describe_cmd_state(CS_INT state) { switch (state) { case _CS_COMMAND_IDLE: return "IDLE"; case _CS_COMMAND_BUILDING: return "BUILDING"; case _CS_COMMAND_READY: return "READY"; case _CS_COMMAND_SENT: return "SENT"; } return "???";}CS_RETCODEct_exit(CS_CONTEXT * ctx, CS_INT unused){ tdsdump_log(TDS_DBG_FUNC, "ct_exit()\n"); return CS_SUCCEED;}CS_RETCODEct_init(CS_CONTEXT * ctx, CS_INT version){ /* uncomment the next line to get pre-login trace */ /* tdsdump_open("/tmp/tds2.log"); */ tdsdump_log(TDS_DBG_FUNC, "ct_init()\n"); ctx->tds_ctx->msg_handler = _ct_handle_server_message; ctx->tds_ctx->err_handler = _ct_handle_client_message; return CS_SUCCEED;}CS_RETCODEct_con_alloc(CS_CONTEXT * ctx, CS_CONNECTION ** con){ TDSLOGIN *login; tdsdump_log(TDS_DBG_FUNC, "ct_con_alloc()\n"); login = tds_alloc_login(); if (!login) return CS_FAIL; *con = (CS_CONNECTION *) malloc(sizeof(CS_CONNECTION)); if (!*con) { tds_free_login(login); return CS_FAIL; } memset(*con, '\0', sizeof(CS_CONNECTION)); (*con)->tds_login = login; /* so we know who we belong to */ (*con)->ctx = ctx; /* set default values */ tds_set_library((*con)->tds_login, "CT-Library"); /* tds_set_client_charset((*con)->tds_login, "iso_1"); */ /* tds_set_packet((*con)->tds_login, TDS_DEF_BLKSZ); */ return CS_SUCCEED;}CS_RETCODEct_callback(CS_CONTEXT * ctx, CS_CONNECTION * con, CS_INT action, CS_INT type, CS_VOID * func){ int (*funcptr) (void *, void *, void *) = (int (*)(void *, void *, void *)) func; tdsdump_log(TDS_DBG_FUNC, "ct_callback() action = %s\n", CS_GET ? "CS_GET" : "CS_SET"); /* one of these has to be defined */ if (!ctx && !con) return CS_FAIL; if (action == CS_GET) { switch (type) { case CS_CLIENTMSG_CB: *(void **) func = (CS_VOID *) (con ? con->_clientmsg_cb : ctx->_clientmsg_cb); return CS_SUCCEED; case CS_SERVERMSG_CB: *(void **) func = (CS_VOID *) (con ? con->_servermsg_cb : ctx->_servermsg_cb); return CS_SUCCEED; default: fprintf(stderr, "Unknown callback %d\n", type); *(void **) func = NULL; return CS_SUCCEED; } } /* CS_SET */ switch (type) { case CS_CLIENTMSG_CB: if (con) con->_clientmsg_cb = (CS_CLIENTMSG_FUNC) funcptr; else ctx->_clientmsg_cb = (CS_CLIENTMSG_FUNC) funcptr; break; case CS_SERVERMSG_CB: if (con) con->_servermsg_cb = (CS_SERVERMSG_FUNC) funcptr; else ctx->_servermsg_cb = (CS_SERVERMSG_FUNC) funcptr; break; } return CS_SUCCEED;}CS_RETCODEct_con_props(CS_CONNECTION * con, CS_INT action, CS_INT property, CS_VOID * buffer, CS_INT buflen, CS_INT * out_len){ CS_INT intval = 0, maxcp; TDSSOCKET *tds; TDSLOGIN *tds_login; char *set_buffer = NULL; tdsdump_log(TDS_DBG_FUNC, "ct_con_props() action = %s property = %d\n", CS_GET ? "CS_GET" : "CS_SET", property); tds = con->tds_socket; tds_login = con->tds_login; if (action == CS_SET) { if (property == CS_USERNAME || property == CS_PASSWORD || property == CS_APPNAME || property == CS_HOSTNAME || property == CS_SERVERADDR) { if (buflen == CS_NULLTERM) { maxcp = strlen((char *) buffer); set_buffer = (char *) malloc(maxcp + 1); strcpy(set_buffer, (char *) buffer); } else if (buflen == CS_UNUSED) { return CS_SUCCEED; } else { set_buffer = (char *) malloc(buflen + 1); strncpy(set_buffer, (char *) buffer, buflen); set_buffer[buflen] = '\0'; } } /* * XXX "login" properties shouldn't be set after * login. I don't know if it should fail silently * or return an error. */ switch (property) { case CS_USERNAME: tds_set_user(tds_login, set_buffer); break; case CS_PASSWORD: tds_set_passwd(tds_login, set_buffer); break; case CS_APPNAME: tds_set_app(tds_login, set_buffer); break; case CS_HOSTNAME: tds_set_host(tds_login, set_buffer); break; case CS_PORT: tds_set_port(tds_login, *((int *) buffer)); break; case CS_SERVERADDR: { /* Format of this property: "[hostname] [port]" */ char *host, *port; int portno; host= strtok(set_buffer, " "); port= strtok(NULL, " "); if (!host || !port) return CS_FAIL; portno= (int)strtol(port, NULL, 10); tds_set_server_addr(tds_login, host); tds_set_port(tds_login, portno); break; } case CS_LOC_PROP: /* sybase docs say that this structure must be copied, not referenced */ if (!buffer) return CS_FAIL; if (con->locale) _cs_locale_free(con->locale); con->locale = _cs_locale_copy((CS_LOCALE *) buffer); if (!con->locale) return CS_FAIL; break; case CS_USERDATA: free(con->userdata); con->userdata = (void *) malloc(buflen + 1); tdsdump_log(TDS_DBG_INFO2, "setting userdata orig %p new %p\n", buffer, con->userdata); con->userdata_len = buflen; memcpy(con->userdata, buffer, buflen); break; case CS_BULK_LOGIN: memcpy(&intval, buffer, sizeof(intval)); if (intval) tds_set_bulk(tds_login, 1); else tds_set_bulk(tds_login, 0); break; case CS_PACKETSIZE: memcpy(&intval, buffer, sizeof(intval)); tds_set_packet(tds_login, (short) intval); break; case CS_TDS_VERSION: /* * FIXME * (a) We don't support all versions in tds/login.c - * I tried to pick reasonable versions. * (b) Might need support outside of tds/login.c * (c) It's a "negotiated" property so probably * needs tds_process_env_chg() support * (d) Minor - we don't check against context * which should limit the acceptable values */ if (*(int *) buffer == CS_TDS_40) { tds_set_version(tds_login, 4, 2); } else if (*(int *) buffer == CS_TDS_42) { tds_set_version(tds_login, 4, 2); } else if (*(int *) buffer == CS_TDS_46) { tds_set_version(tds_login, 4, 6); } else if (*(int *) buffer == CS_TDS_495) { tds_set_version(tds_login, 4, 6); } else if (*(int *) buffer == CS_TDS_50) { tds_set_version(tds_login, 5, 0); } else if (*(int *) buffer == CS_TDS_70) { tds_set_version(tds_login, 7, 0); } else { return CS_FAIL; } break; default: tdsdump_log(TDS_DBG_ERROR, "Unknown property %d\n", property); break; } free(set_buffer); } else if (action == CS_GET) { switch (property) { case CS_USERNAME: if (out_len) *out_len = tds_dstr_len(&tds_login->user_name); tds_strlcpy((char *) buffer, tds_dstr_cstr(&tds_login->user_name), buflen); break; case CS_PASSWORD: if (out_len) *out_len = tds_dstr_len(&tds_login->password); tds_strlcpy((char *) buffer, tds_dstr_cstr(&tds_login->password), buflen); break; case CS_APPNAME: if (out_len) *out_len = tds_dstr_len(&tds_login->app_name); tds_strlcpy((char *) buffer, tds_dstr_cstr(&tds_login->app_name), buflen); break; case CS_HOSTNAME: if (out_len) *out_len = tds_dstr_len(&tds_login->client_host_name); tds_strlcpy((char *) buffer, tds_dstr_cstr(&tds_login->client_host_name), buflen); break; case CS_SERVERNAME: if (out_len) *out_len = tds_dstr_len(&tds_login->server_name); tds_strlcpy((char *) buffer, tds_dstr_cstr(&tds_login->server_name), buflen); break; case CS_LOC_PROP: if (buflen != CS_UNUSED || !con->locale || !buffer) return CS_FAIL; if (!_cs_locale_copy_inplace((CS_LOCALE *) buffer, con->locale)) return CS_FAIL; break; case CS_USERDATA: tdsdump_log(TDS_DBG_INFO2, "fetching userdata %p\n", con->userdata); maxcp = con->userdata_len; if (out_len) *out_len = maxcp; if (maxcp > buflen) maxcp = buflen; memcpy(buffer, con->userdata, maxcp); break; case CS_CON_STATUS: if (!(IS_TDSDEAD(tds))) intval |= CS_CONSTAT_CONNECTED; else intval &= ~CS_CONSTAT_CONNECTED; if (tds && tds->state == TDS_DEAD) intval |= CS_CONSTAT_DEAD; else intval &= ~CS_CONSTAT_DEAD;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -