mem.c

来自「在Linux/Unix下面访问WINDOWS SQLSERVER 的ODBC驱动」· C语言 代码 · 共 1,446 行 · 第 1/3 页

C
1,446
字号
/* FreeTDS - Library of routines accessing Sybase and Microsoft databases * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005  Brian Bruns * Copyright (C) 2005 Frediano Ziglio * * 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 */#if HAVE_STDLIB_H#include <stdlib.h>#endif /* HAVE_STDLIB_H */#if HAVE_STRING_H#include <string.h>#endif /* HAVE_STRING_H */#if HAVE_UNISTD_H#include <unistd.h>#endif /* HAVE_UNISTD_H */#include <assert.h>#include "tds.h"#include "tdsiconv.h"#include "tds_checks.h"#include "tdsstring.h"#include "replacements.h"#include "enum_cap.h"#ifdef DMALLOC#include <dmalloc.h>#endifTDS_RCSID(var, "$Id: mem.c,v 1.175 2007/12/31 10:06:50 freddy77 Exp $");static void tds_free_env(TDSSOCKET * tds);static void tds_free_compute_results(TDSSOCKET * tds);static void tds_free_compute_result(TDSCOMPUTEINFO * comp_info);#undef TEST_MALLOC#define TEST_MALLOC(dest,type) \	{if (!(dest = (type*)calloc(1, sizeof(type)))) goto Cleanup;}#undef TEST_CALLOC#define TEST_CALLOC(dest,type,n) \	{if (!(dest = (type*)calloc((n), sizeof(type)))) goto Cleanup;}#define tds_alloc_column() ((TDSCOLUMN*) calloc(1, sizeof(TDSCOLUMN)))/** * \ingroup libtds * \defgroup mem Memory allocation * Allocate or free resources. Allocation can fail only on out of memory.  * In such case they return NULL and leave the state as before call. * Mainly function names are in the form tds_alloc_XX or tds_free_XXX. * tds_alloc_XXX functions allocate structures and return pointer to allocated * data while tds_free_XXX take structure pointers and free them. Some functions * require additional parameters to initialize structure correctly. * The main exception are structures that use reference counting. These structures * have tds_alloc_XXX functions but instead of tds_free_XXX use tds_release_XXX. *//** * \addtogroup mem * @{ *//** * \fn TDSDYNAMIC *tds_alloc_dynamic(TDSSOCKET *tds, const char *id) * \brief Allocate a dynamic statement. * \param tds the connection within which to allocate the statement. * \param id a character label identifying the statement. * \return a pointer to the allocated structure (NULL on failure). * * tds_alloc_dynamic is used to implement placeholder code under TDS 5.0 */TDSDYNAMIC *tds_alloc_dynamic(TDSSOCKET * tds, const char *id){	TDSDYNAMIC *dyn, *curr;	/* check to see if id already exists (shouldn't) */	for (curr = tds->dyns; curr != NULL; curr = curr->next)		if (!strcmp(curr->id, id)) {			/* id already exists! just return it */			return curr;		}	dyn = (TDSDYNAMIC *) calloc(1, sizeof(TDSDYNAMIC));	if (!dyn)		return NULL;	/* insert into list */	dyn->next = tds->dyns;	tds->dyns = dyn;	tds_strlcpy(dyn->id, id, TDS_MAX_DYNID_LEN);	return dyn;}/** * \fn void tds_free_input_params(TDSDYNAMIC *dyn) * \brief Frees all allocated input parameters of a dynamic statement. * \param dyn the dynamic statement whose input parameter are to be freed * * tds_free_input_params frees all parameters for the give dynamic statement */voidtds_free_input_params(TDSDYNAMIC * dyn){	TDSPARAMINFO *info;	info = dyn->params;	if (info) {		tds_free_param_results(info);		dyn->params = NULL;	}}/** * \fn void tds_free_dynamic(TDSSOCKET *tds, TDSDYNAMIC *dyn) * \brief Frees dynamic statement and remove from TDS * \param tds state information for the socket and the TDS protocol * \param dyn dynamic statement to be freed. */voidtds_free_dynamic(TDSSOCKET * tds, TDSDYNAMIC * dyn){	TDSDYNAMIC **pcurr;	/* avoid pointer to garbage */	if (tds->cur_dyn == dyn)		tds->cur_dyn = NULL;	if (tds->current_results == dyn->res_info)		tds->current_results = NULL;	/* free from tds */	for (pcurr = &tds->dyns; *pcurr != NULL; pcurr = &(*pcurr)->next)		if (dyn == *pcurr) {			*pcurr = dyn->next;			break;		}	tds_free_results(dyn->res_info);	tds_free_input_params(dyn);	free(dyn->query);	free(dyn);}/** * \fn TDSPARAMINFO *tds_alloc_param_result(TDSPARAMINFO *old_param) * \brief Adds a output parameter to TDSPARAMINFO. * \param old_param a pointer to the TDSPARAMINFO structure containing the  * current set of output parameter, or NULL if none exists. * \return a pointer to the new TDSPARAMINFO structure. * * tds_alloc_param_result() works a bit differently than the other alloc result * functions.  Output parameters come in individually with no total number  * given in advance, so we simply call this func every time with get a * TDS_PARAM_TOKEN and let it realloc the columns struct one bigger.  * tds_free_all_results() usually cleans up after us. */TDSPARAMINFO *tds_alloc_param_result(TDSPARAMINFO * old_param){	TDSPARAMINFO *param_info;	TDSCOLUMN *colinfo;	TDSCOLUMN **cols;	colinfo = tds_alloc_column();	if (!colinfo)		return NULL;	if (!old_param || !old_param->num_cols) {		cols = (TDSCOLUMN **) malloc(sizeof(TDSCOLUMN *));	} else {		cols = (TDSCOLUMN **) realloc(old_param->columns, sizeof(TDSCOLUMN *) * (old_param->num_cols + 1));	}	if (!cols)		goto Cleanup;	if (!old_param) {		param_info = (TDSPARAMINFO *) calloc(1, sizeof(TDSPARAMINFO));		if (!param_info) {			free(cols);			goto Cleanup;		}		param_info->ref_count = 1;	} else {		param_info = old_param;	}	param_info->columns = cols;	param_info->columns[param_info->num_cols++] = colinfo;	return param_info;      Cleanup:	free(colinfo);	return NULL;}/** * Delete latest parameter */voidtds_free_param_result(TDSPARAMINFO * param_info){	TDSCOLUMN *col;	if (!param_info || param_info->num_cols <= 0)		return;	col = param_info->columns[--param_info->num_cols];	if (col->column_data && col->column_data_free)		col->column_data_free(col);	if (param_info->num_cols == 0 && param_info->columns)		TDS_ZERO_FREE(param_info->columns);	/*	 * NOTE some informations should be freed too but when this function 	 * is called are not used. I hope to remove the need for this	 * function ASAP	 * A better way is to support different way to allocate and get	 * parameters	 * -- freddy77	 */	free(col->table_column_name);	free(col);}static void_tds_param_free(TDSCOLUMN *col){	if (!col->column_data)		return;	if (is_blob_type(col->column_type)) {		TDSBLOB *blob = (TDSBLOB *) col->column_data;		free(blob->textvalue);	}	TDS_ZERO_FREE(col->column_data);}/** * Allocate data for a parameter. * @param curparam parameter to retrieve size information * @return NULL on failure or new data */void *tds_alloc_param_data(TDSCOLUMN * curparam){	TDS_INT data_size;	void *data;	CHECK_COLUMN_EXTRA(curparam);	if (is_numeric_type(curparam->column_type)) {		data_size = sizeof(TDS_NUMERIC);	} else if (is_blob_type(curparam->column_type)) {		data_size = sizeof(TDSBLOB);	} else {		data_size = curparam->column_size;	}	/* allocate data */	if (curparam->column_data && curparam->column_data_free)		curparam->column_data_free(curparam);	curparam->column_data_free = _tds_param_free;	data = malloc(data_size);	curparam->column_data = data;	if (!data)		return NULL;	/* if is a blob reset buffer */	if (is_blob_type(curparam->column_type))		memset(data, 0, sizeof(TDSBLOB));	return data;}/** * Allocate memory for storing compute info * return NULL on out of memory */static TDSCOMPUTEINFO *tds_alloc_compute_result(int num_cols, int by_cols){	int col;	TDSCOMPUTEINFO *info;	TEST_MALLOC(info, TDSCOMPUTEINFO);	info->ref_count = 1;	TEST_CALLOC(info->columns, TDSCOLUMN *, num_cols);	tdsdump_log(TDS_DBG_INFO1, "alloc_compute_result. point 1\n");	info->num_cols = num_cols;	for (col = 0; col < num_cols; col++)		if (!(info->columns[col] = tds_alloc_column()))			goto Cleanup;	tdsdump_log(TDS_DBG_INFO1, "alloc_compute_result. point 2\n");	if (by_cols) {		TEST_CALLOC(info->bycolumns, TDS_SMALLINT, by_cols);		tdsdump_log(TDS_DBG_INFO1, "alloc_compute_result. point 3\n");		info->by_cols = by_cols;	}	return info;      Cleanup:	tds_free_compute_result(info);	return NULL;}TDSCOMPUTEINFO **tds_alloc_compute_results(TDSSOCKET * tds, int num_cols, int by_cols){	int n;	TDSCOMPUTEINFO **comp_info;	TDSCOMPUTEINFO *cur_comp_info;	tdsdump_log(TDS_DBG_INFO1, "alloc_compute_result. num_cols = %d bycols = %d\n", num_cols, by_cols);	tdsdump_log(TDS_DBG_INFO1, "alloc_compute_result. num_comp_info = %d\n", tds->num_comp_info);	cur_comp_info = tds_alloc_compute_result(num_cols, by_cols);	if (!cur_comp_info)		return NULL;	n = tds->num_comp_info;	if (n == 0)		comp_info = (TDSCOMPUTEINFO **) malloc(sizeof(TDSCOMPUTEINFO *));	else		comp_info = (TDSCOMPUTEINFO **) realloc(tds->comp_info, sizeof(TDSCOMPUTEINFO *) * (n + 1));	if (!comp_info) {		tds_free_compute_result(cur_comp_info);		return NULL;	}	tds->comp_info = comp_info;	comp_info[n] = cur_comp_info;	tds->num_comp_info = n + 1;	tdsdump_log(TDS_DBG_INFO1, "alloc_compute_result. num_comp_info = %d\n", tds->num_comp_info);	return comp_info;}TDSRESULTINFO *tds_alloc_results(int num_cols){	TDSRESULTINFO *res_info;	int col;	TEST_MALLOC(res_info, TDSRESULTINFO);	res_info->ref_count = 1;	TEST_CALLOC(res_info->columns, TDSCOLUMN *, num_cols);	for (col = 0; col < num_cols; col++)		if (!(res_info->columns[col] = tds_alloc_column()))			goto Cleanup;	res_info->num_cols = num_cols;	res_info->row_size = 0;	return res_info;      Cleanup:	tds_free_results(res_info);	return NULL;}static void_tds_row_free(TDSRESULTINFO *res_info, unsigned char *row){	int i;	const TDSCOLUMN *col;	if (!res_info || !row)		return;	for (i = 0; i < res_info->num_cols; ++i) {		col = res_info->columns[i];				if (is_blob_type(col->column_type)) {			TDSBLOB *blob = (TDSBLOB *) &row[col->column_data - res_info->current_row];			if (blob->textvalue)				TDS_ZERO_FREE(blob->textvalue);		}	}	free(row);}/** * Allocate space for row store * return NULL on out of memory */inttds_alloc_row(TDSRESULTINFO * res_info){	int i, num_cols = res_info->num_cols;	unsigned char *ptr;	TDSCOLUMN *col;	TDS_UINT row_size;	/* compute row size */	row_size = 0;	for (i = 0; i < num_cols; ++i) {		col = res_info->columns[i];		col->column_data_free = NULL;		if (is_numeric_type(col->column_type)) {			row_size += sizeof(TDS_NUMERIC);		} else if (is_blob_type(col->column_type)) {			row_size += sizeof(TDSBLOB);		} else {			row_size += col->column_size;		}		row_size += (TDS_ALIGN_SIZE - 1);		row_size -= row_size % TDS_ALIGN_SIZE;	}	res_info->row_size = row_size;	ptr = (unsigned char *) malloc(res_info->row_size);	res_info->current_row = ptr;	if (!ptr)		return TDS_FAIL;	res_info->row_free = _tds_row_free;	/* fill column_data */	row_size = 0;	for (i = 0; i < num_cols; ++i) {		col = res_info->columns[i];		col->column_data = ptr + row_size;		if (is_numeric_type(col->column_type)) {			row_size += sizeof(TDS_NUMERIC);		} else if (is_blob_type(col->column_type)) {			row_size += sizeof(TDSBLOB);		} else {			row_size += col->column_size;		}		row_size += (TDS_ALIGN_SIZE - 1);		row_size -= row_size % TDS_ALIGN_SIZE;	}	memset(ptr, '\0', res_info->row_size);	return TDS_SUCCEED;}inttds_alloc_compute_row(TDSCOMPUTEINFO * res_info){	return tds_alloc_row(res_info);}voidtds_free_param_results(TDSPARAMINFO * param_info){	tds_free_results(param_info);}static void

⌨️ 快捷键说明

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