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 + -
显示快捷键?