⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rpc.c

📁 在Linux/Unix下面访问WINDOWS SQLSERVER 的ODBC驱动程序
💻 C
字号:
/* 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>#ifdef HAVE_UNISTD_H#include <unistd.h>#endif /* HAVE_UNISTD_H */#ifdef HAVE_STDLIB_H#include <stdlib.h>#endif /* HAVE_STDLIB_H */#ifdef HAVE_STRING_H#include <string.h>#endif /* HAVE_STRING_H */#if HAVE_ERRNO_H# include <errno.h>#endif /* HAVE_ERRNO_H */#include <assert.h>#include "tds.h"#include "tdsconvert.h"#include "sybfront.h"#include "sybdb.h"#include "dblib.h"#include "replacements.h"#ifdef DMALLOC#include <dmalloc.h>#endifTDS_RCSID(var, "$Id: rpc.c,v 1.64 2007/12/06 18:32:34 freddy77 Exp $");static void rpc_clear(DBREMOTE_PROC * rpc);static void param_clear(DBREMOTE_PROC_PARAM * pparam);static TDSPARAMINFO *param_info_alloc(TDSSOCKET * tds, DBREMOTE_PROC * rpc);/** * \ingroup dblib_rpc * \brief Initialize a remote procedure call.  * * \param dbproc contains all information needed by db-lib to manage communications with the server. * \param rpcname name of the stored procedure to be run.   * \param options Only supported option would be DBRPCRECOMPILE,  * which causes the stored procedure to be recompiled before executing. * \remark The RPC functions are the only way to get back OUTPUT parameter data with db-lib  * from modern Microsoft servers.   * \retval SUCCEED normal. * \retval FAIL on error * \sa dbrpcparam(), dbrpcsend() */RETCODEdbrpcinit(DBPROCESS * dbproc, char *rpcname, DBSMALLINT options){	DBREMOTE_PROC **rpc;	int dbrpcrecompile = 0;	tdsdump_log(TDS_DBG_FUNC, "dbrpcinit(%p, %s, %d)\n", dbproc, rpcname, options);	CHECK_DBPROC();	DBPERROR_RETURN(IS_TDSDEAD(dbproc->tds_socket), SYBEDDNE);	CHECK_NULP(rpcname, "dbrpcinit", 2, FAIL);	if (options & DBRPCRESET) {		rpc_clear(dbproc->rpc);		dbproc->rpc = NULL;		return SUCCEED;	}	/* any bits we want from the options argument */	dbrpcrecompile = options & DBRPCRECOMPILE;	options &= ~DBRPCRECOMPILE;	/* turn that one off, now that we've extracted it */	/* all other options except DBRPCRECOMPILE are invalid */	DBPERROR_RETURN3(options, SYBEIPV, (int) options, "options", "dbrpcinit");	/* to allocate, first find a free node */	for (rpc = &dbproc->rpc; *rpc != NULL; rpc = &(*rpc)->next) {		/* check existing nodes for name match (there shouldn't be one) */		if (!(*rpc)->name)			return FAIL;		if (strcmp((*rpc)->name, rpcname) == 0)			return FAIL /* dbrpcsend should free pointer */ ;	}	/* rpc now contains the address of the dbproc's first empty (null) DBREMOTE_PROC* */	/* allocate */	*rpc = (DBREMOTE_PROC *) malloc(sizeof(DBREMOTE_PROC));	if (*rpc == NULL)		return FAIL;	memset(*rpc, 0, sizeof(DBREMOTE_PROC));	(*rpc)->name = strdup(rpcname);	if ((*rpc)->name == NULL) {		free(*rpc);		*rpc = NULL;		return FAIL;	}	/* store */	(*rpc)->options = options & DBRPCRECOMPILE;	(*rpc)->param_list = NULL;	/* completed */	tdsdump_log(TDS_DBG_INFO1, "dbrpcinit() added rpcname \"%s\"\n", rpcname);	return SUCCEED;}/** * \ingroup dblib_rpc * \brief Add a parameter to a remote procedure call. * * Call between dbrpcinit() and dbrpcsend() * \param dbproc contains all information needed by db-lib to manage communications with the server. * \param paramname literal name of the parameter, according to the stored procedure (starts with '@').  Optional.   *        If not used, parameters will be passed in order instead of by name.  * \param status must be DBRPCRETURN, if this parameter is a return parameter, else 0.  * \param type datatype of the value parameter e.g., SYBINT4, SYBCHAR. * \param maxlen Maximum output size of the parameter's value to be returned by the stored procedure, usually the size of your host variable.  *        Fixed-length datatypes take -1 (NULL or not).   *        Non-OUTPUT parameters also use -1.   *	   Use 0 to send a NULL value for a variable length datatype.   * \param datalen For variable-length datatypes, the byte size of the data to be sent, exclusive of any null terminator.  *        For fixed-length datatypes use -1.  To send a NULL value, use 0.   * \param value Address of your host variable.   * \retval SUCCEED normal. * \retval FAIL on error * \sa dbrpcinit(), dbrpcsend() */RETCODEdbrpcparam(DBPROCESS * dbproc, char *paramname, BYTE status, int type, DBINT maxlen, DBINT datalen, BYTE * value){	char *name = NULL;	DBREMOTE_PROC *rpc;	DBREMOTE_PROC_PARAM **pparam;	DBREMOTE_PROC_PARAM *param;	tdsdump_log(TDS_DBG_FUNC, "dbrpcparam(%p, %s, 0x%x, %d, %d, %d, %p)\n", 				   dbproc, paramname, status, type, maxlen, datalen, value);	CHECK_DBPROC();	DBPERROR_RETURN(IS_TDSDEAD(dbproc->tds_socket), SYBEDDNE);	CHECK_PARAMETER(dbproc->rpc, SYBERPCS, FAIL);	/* validate datalen parameter */	if (is_fixed_type(type)) {		if (datalen != 0)			datalen = -1; 	} else {	/* Sybooks: "Passing datalen as -1 for any of these [non-fixed] datatypes results 			 * in the DBPROCESS referenced by dbproc being marked as "dead," or unusable."			 */		DBPERROR_RETURN(datalen < 0, SYBERPIL);	}	/* "value parameter for dbprcparam() can be NULL, only if the datalen parameter is 0." */	DBPERROR_RETURN(value == NULL && datalen != 0, SYBERPNULL);		/* nullable types most provide a data length */	DBPERROR_RETURN(is_nullable_type(type) && datalen < 0, SYBERPUL);	/* validate maxlen parameter */	if (status & DBRPCRETURN) {		if (is_fixed_type(type)) {			maxlen = -1;		} else {			if (maxlen == -1)				maxlen = 255;		}	} else {		/*		 * Well, maxlen should be used only for output parameter however it seems		 * that ms implementation wrongly require this 0 for NULL variable		 * input parameters, so fix it		 */		DBPERROR_RETURN3(maxlen != -1 && maxlen != 0, SYBEIPV, (int) maxlen, "maxlen", "dbrpcparam");		maxlen = -1;	}		/* end validation */	/* allocate */	param = (DBREMOTE_PROC_PARAM *) malloc(sizeof(DBREMOTE_PROC_PARAM));	if (param == NULL) {		dbperror(dbproc, SYBEMEM, 0);		return FAIL;	}	if (paramname) {		name = strdup(paramname);		if (name == NULL) {			free(param);			dbperror(dbproc, SYBEMEM, 0);			return FAIL;		}	}	/* initialize */	param->next = NULL;	/* NULL signifies end of linked list */	param->name = name;	param->status = status;	param->type = type;	param->maxlen = maxlen;	param->datalen = datalen;	/*	 * If datalen = 0, value parameter is ignored.	 * This is one way to specify a NULL input parameter. 	 */	if (datalen == 0)		param->value = NULL;	else		param->value = value;	/*	 * Add a parameter to the current rpc.  	 * 	 * Traverse the dbproc's procedure list to find the current rpc, 	 * then traverse the parameter linked list until its end,	 * then tack on our parameter's address.  	 */	for (rpc = dbproc->rpc; rpc->next != NULL; rpc = rpc->next)	/* find "current" procedure */		;	for (pparam = &rpc->param_list; *pparam != NULL; pparam = &(*pparam)->next);	/* pparam now contains the address of the end of the rpc's parameter list */	*pparam = param;	/* add to the end of the list */	tdsdump_log(TDS_DBG_INFO1, "dbrpcparam() added parameter \"%s\"\n", (paramname) ? paramname : "");	return SUCCEED;}/** * \ingroup dblib_rpc * \brief Execute the procedure and free associated memory * * \param dbproc contains all information needed by db-lib to manage communications with the server. * \retval SUCCEED normal. * \retval FAIL on error * \sa dbrpcinit(), dbrpcparam() */RETCODEdbrpcsend(DBPROCESS * dbproc){	DBREMOTE_PROC *rpc;	tdsdump_log(TDS_DBG_FUNC, "dbrpcsend(%p)\n", dbproc);	CHECK_DBPROC();	DBPERROR_RETURN(IS_TDSDEAD(dbproc->tds_socket), SYBEDDNE);	CHECK_PARAMETER(dbproc->rpc, SYBERPCS, FAIL);	/* dbrpcinit should allocate pointer */	/* sanity */	if (dbproc->rpc->name == NULL) {	/* can't be ready without a name */		tdsdump_log(TDS_DBG_INFO1, "returning FAIL: name is NULL\n");		return FAIL;	}	dbproc->dbresults_state = _DB_RES_INIT;	for (rpc = dbproc->rpc; rpc != NULL; rpc = rpc->next) {		int erc;		TDSPARAMINFO *pparam_info = NULL;		/*		 * liam@inodes.org: allow stored procedures to have no paramaters 		 */		if (rpc->param_list != NULL) {			pparam_info = param_info_alloc(dbproc->tds_socket, rpc);			if (!pparam_info)				return FAIL;		}		erc = tds_submit_rpc(dbproc->tds_socket, dbproc->rpc->name, pparam_info);		tds_free_param_results(pparam_info);		if (erc == TDS_FAIL) {			tdsdump_log(TDS_DBG_INFO1, "returning FAIL: tds_submit_rpc() failed\n");			return FAIL;		}	}	/* free up the memory */	rpc_clear(dbproc->rpc);	dbproc->rpc = NULL;	tdsdump_log(TDS_DBG_FUNC, "dbrpcsend() returning SUCCEED\n");	return SUCCEED;}/**  * Tell the TDSPARAMINFO structure where the data go.  This is a kind of "bind" operation. */static const unsigned char *param_row_alloc(TDSPARAMINFO * params, TDSCOLUMN * curcol, int param_num, void *value, int size){	const void *row = tds_alloc_param_data(curcol);	tdsdump_log(TDS_DBG_INFO1, "parameter size = %d, data = %p, row_size = %d\n",				   size, curcol->column_data, params->row_size);	if (!row)		return NULL;	if (size > 0 && value) {		tdsdump_log(TDS_DBG_FUNC, "copying %d bytes of data to parameter #%d\n", size, param_num);		if (!is_blob_type(curcol->column_type)) {			memcpy(curcol->column_data, value, size);		} else {			TDSBLOB *blob = (TDSBLOB *) curcol->column_data;			blob->textvalue = malloc(size);			tdsdump_log(TDS_DBG_FUNC, "blob parameter supported, size %d textvalue pointer is %p\n", 						  size, blob->textvalue);			if (!blob->textvalue)				return NULL;			memcpy(blob->textvalue, value, size);		}	}	else {		tdsdump_log(TDS_DBG_FUNC, "setting parameter #%d to NULL\n", param_num);		curcol->column_cur_size = -1;	}	return row;}/**  * Allocate memory and copy the rpc information into a TDSPARAMINFO structure. */static TDSPARAMINFO *param_info_alloc(TDSSOCKET * tds, DBREMOTE_PROC * rpc){	int i;	DBREMOTE_PROC_PARAM *p;	TDSCOLUMN *pcol;	TDSPARAMINFO *params = NULL, *new_params;	BYTE *temp_value;	int  temp_datalen;	int  temp_type;	int  param_is_null;	/* sanity */	if (rpc == NULL)		return NULL;	/* see v 1.10 2002/11/23 for first broken attempt */	for (i = 0, p = rpc->param_list; p != NULL; p = p->next, i++) {		const unsigned char *prow;		if (!(new_params = tds_alloc_param_result(params))) {			tds_free_param_results(params);			tdsdump_log(TDS_DBG_ERROR, "out of rpc memory!");			return NULL;		}		params = new_params;		/*		 * Determine whether an input parameter is NULL or not.		 */		param_is_null = 0;		temp_type = p->type;		temp_value = p->value;		temp_datalen = p->datalen;		if (p->datalen == 0)			param_is_null = 1; 		tdsdump_log(TDS_DBG_INFO1, "parm_info_alloc(): parameter null-ness = %d\n", param_is_null);		if (param_is_null || (p->status & DBRPCRETURN)) {			if (param_is_null) {				temp_datalen = 0;				temp_value = NULL;			} else if (is_fixed_type(temp_type)) {				temp_datalen = tds_get_size_by_type(temp_type);			}			temp_type = tds_get_null_type(temp_type);		} else if (is_fixed_type(temp_type)) {			temp_datalen = tds_get_size_by_type(temp_type);		}		pcol = params->columns[i];		/* meta data */		if (p->name) {			tds_strlcpy(pcol->column_name, p->name, sizeof(pcol->column_name));			pcol->column_namelen = strlen(pcol->column_name);		}		tds_set_param_type(tds, pcol, temp_type);		if (p->maxlen > 0)			pcol->column_size = p->maxlen;		else {			if (is_fixed_type(p->type)) {				pcol->column_size = tds_get_size_by_type(p->type);			} else {				pcol->column_size = p->datalen;			}		}		pcol->on_server.column_size = pcol->column_size;		pcol->column_output = p->status;		pcol->column_cur_size = temp_datalen;		prow = param_row_alloc(params, pcol, i, temp_value, temp_datalen);		if (!prow) {			tds_free_param_results(params);			tdsdump_log(TDS_DBG_ERROR, "out of memory for rpc row!");			return NULL;		}	}	return params;}/** * erase the procedure list */static voidrpc_clear(DBREMOTE_PROC * rpc){	DBREMOTE_PROC * next;	while (rpc) {		next = rpc->next;		param_clear(rpc->param_list);		free(rpc->name);		free(rpc);		rpc = next;	}}/** * erase the parameter list */static voidparam_clear(DBREMOTE_PROC_PARAM * pparam){	DBREMOTE_PROC_PARAM * next;	while (pparam) {		next = pparam->next;		free(pparam->name);		/* free self */		free(pparam);		pparam = next;	}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -