Skip to Content.
Sympa Menu

freetds - [freetds] [patch] dbsetnull() support

freetds AT lists.ibiblio.org

Subject: FreeTDS Development Group

List archive

Chronological Thread  
  • From: "MATSUMOTO, Tadashi" <pineroot AT yahoo.co.jp>
  • To: FreeTDS Development Group <freetds AT lists.ibiblio.org>
  • Subject: [freetds] [patch] dbsetnull() support
  • Date: Mon, 23 Apr 2007 20:11:05 +0900

Hi all,

I have implemented dbsetnull() on DB-Library of FreeTDS 0.64.
Could someone give me some advice about my patch?

The specification is as follows.
1. Dbsetnull() copies some values to null value preservation areas for each
bind datatype
added to the dbproc structure.
2. The internal function _set_null_value() returns the values.

For example,this implementation returns "n/a " as null in a following
CHARBIND case.
char *nullstr = "n/a";
dbsetnull(dbproc, CHARBIND, strlen(nullstr), (BYTE*)nullstr);
...
dbbind(dbproc, n, CHARBIND, 5, (BYTE*)result);

Compared with Syabase, this implementation has some restrictions as follows.
1. It doesn't support VARYBINBIND,BOUNDARYBIND and SENSITIVITYBIND of Sybase
2. It supports BITBIND which doesn't exist in Sybase dbsetnull manual.
3. It doesn't change dbconvert behavior.
"0x00" or "NULL value" will be returned according to a former
implementation.
4.
If the Bind variable area for string datatype is smaller than that of the
null value set in dbsetnull(),
the number of characters by Sybase Dblib is 1 fewer charactor than the
number of ones by this implementation.
(Sybase bug?)

Thanks.
--
MATSUMOTO, Tadashi


diff -r -u -1 -0 ../freetds-0.64.ORG/include/dblib.h ./include/dblib.h
--- ../freetds-0.64.ORG/include/dblib.h Wed Mar 7 14:32:36 2007
+++ ./include/dblib.h Mon Mar 19 14:21:09 2007
@@ -146,20 +146,41 @@
char dbcurdb[DBMAXNAME + 1];
char servcharset[DBMAXNAME + 1];
FILE *ftos;
DB_DBCHKINTR_FUNC dbchkintr;
DB_DBHNDLINTR_FUNC dbhndlintr;

/** boolean use ms behaviour */
int msdblib;

int ntimeouts;
+
+ /** default null values **/
+ DBTINYINT null_TINYBIND;
+ DBSMALLINT null_SMALLBIND;
+ DBINT null_INTBIND;
+ DBCHAR *p_null_CHARBIND;
+ DBINT len_null_CHARBIND;
+ DBCHAR *p_null_STRINGBIND;
+ DBCHAR *p_null_NTBSTRINGBIND;
+ DBVARYCHAR null_VARYCHARBIND;
+ DBBINARY *p_null_BINARYBIND;
+ DBINT len_null_BINARYBIND;
+ DBDATETIME null_DATETIMEBIND;
+ DBDATETIME4 null_SMALLDATETIMEBIND;
+ DBMONEY null_MONEYBIND;
+ DBMONEY4 null_SMALLMONEYBIND;
+ DBFLT8 null_FLT8BIND;
+ DBREAL null_REALBIND;
+ DBDECIMAL null_DECIMALBIND;
+ DBNUMERIC null_NUMERICBIND;
+ DBBIT null_BITBIND;
};

#define DBLIB_INFO_MSG_TYPE 0
#define DBLIB_ERROR_MSG_TYPE 1

/*
* internal prototypes
*/
int dbperror (DBPROCESS *dbproc, DBINT msgno, int errnum);
int _dblib_handle_info_message(const TDSCONTEXT * ctxptr, TDSSOCKET *
tdsptr, TDSMESSAGE* msgptr);
diff -r -u -1 -0 ../freetds-0.64.ORG/src/dblib/buffering.h
./src/dblib/buffering.h
--- ../freetds-0.64.ORG/src/dblib/buffering.h Wed Mar 7 14:32:22 2007
+++ ./src/dblib/buffering.h Fri Mar 23 17:43:05 2007
@@ -255,21 +255,22 @@

src = (row->row_data ? row->row_data :
row->resinfo->current_row) + curcol->column_offset;
srclen = curcol->column_cur_size;
if (is_blob_type(curcol->column_type)) {
src = (BYTE *) ((TDSBLOB *) src)->textvalue;
}
desttype = _db_get_server_type(curcol->column_bindtype);
srctype = tds_get_conversion_type(curcol->column_type,
curcol->column_size);

if (srclen < 0) {
- _set_null_value((BYTE *) curcol->column_varaddr,
desttype, curcol->column_bindlen);
+ _set_null_value(dbproc, curcol->column_bindtype,
+ curcol->column_varaddr,
curcol->column_bindlen);
} else {
copy_data_to_host_var(dbproc, srctype, src, srclen,
desttype,
(BYTE *)
curcol->column_varaddr, curcol->column_bindlen,

curcol->column_bindtype, curcol->column_nullbind);
}
}

/*
* This function always bumps current. Usually, it's called
* by dbnextrow(), so bumping current is a pretty obvious choice.
diff -r -u -1 -0 ../freetds-0.64.ORG/src/dblib/dblib.c ./src/dblib/dblib.c
--- ../freetds-0.64.ORG/src/dblib/dblib.c Wed Mar 7 14:32:23 2007
+++ ./src/dblib/dblib.c Mon Mar 26 15:38:14 2007
@@ -69,21 +69,22 @@
#endif

TDS_RCSID(var, "$Id: dblib.c,v 1.244.2.1 2006/01/31 08:45:20 freddy77 Exp
$");

static int _db_get_server_type(int bindtype);
static int _get_printable_size(TDSCOLUMN * colinfo);
static char *_dbprdate(char *timestr);
static int _dbnullable(DBPROCESS * dbproc, int column);
static char *tds_prdatatype(TDS_SERVER_TYPE datatype_token);

-static void _set_null_value(BYTE * varaddr, int datatype, int maxlen);
+static void _set_null_value(DBPROCESS *dbproc, int bindtype, BYTE * varaddr,
int dstlen);
+
static void copy_data_to_host_var(DBPROCESS *, int, const BYTE *, DBINT,
int, BYTE *, DBINT, int, DBSMALLINT *);

#define _DB_GETCOLINFO(fail) \
if (!dbproc || !dbproc->tds_socket ||
!(resinfo=dbproc->tds_socket->res_info)) \
return (fail); \
\
if (column < 1 || column > resinfo->num_cols) \
return (fail); \
colinfo = resinfo->columns[column - 1];

@@ -1081,20 +1082,29 @@
}

for (i = 0; i < DBNUMOPTIONS; i++) {
free_linked_dbopt(dbproc->dbopts[i].optnext);
dbstring_free(&(dbproc->dbopts[i].optparam));
}
free(dbproc->dbopts);

dbstring_free(&(dbproc->dboptcmd));

+ if (dbproc->p_null_CHARBIND)
+ free(dbproc->p_null_CHARBIND);
+ if (dbproc->p_null_STRINGBIND)
+ free(dbproc->p_null_STRINGBIND);
+ if (dbproc->p_null_NTBSTRINGBIND)
+ free(dbproc->p_null_NTBSTRINGBIND);
+ if (dbproc->p_null_BINARYBIND)
+ free(dbproc->p_null_BINARYBIND);
+
dbfreebuf(dbproc);
free(dbproc);

return;
}

/**
* \ingroup dblib_core
* \brief Close server connections and free all related structures.
*
@@ -2062,20 +2072,145 @@
{
TDSCOLUMN *colinfo;
TDSRESULTINFO *resinfo;

_DB_GETCOLINFO(FAIL);

colinfo->column_nullbind = (TDS_SMALLINT *)indicator;
return SUCCEED;
}

+RETCODE
+dbsetnull(DBPROCESS * dbproc, int bindtype, DBINT bindlen, BYTE *bindval)
+{
+ tdsdump_log(TDS_DBG_INFO1, "dbsetnull() bindtype = %d bindlen =
%d\n", bindtype, bindlen);
+
+ if (dbproc == NULL) {
+ dbperror(dbproc, SYBENULL, 0);
+ return FAIL;
+ }
+ if (bindval == NULL) {
+ dbperror(dbproc, SYBEABNV, 0);
+ return FAIL;
+ }
+
+ switch (bindtype) {
+ case TINYBIND:
+ memcpy((void*)&(dbproc->null_TINYBIND), (void*)bindval,
sizeof(dbproc->null_TINYBIND));
+ break;
+ case SMALLBIND:
+ memcpy((void*)&(dbproc->null_SMALLBIND), (void*)bindval,
sizeof(dbproc->null_SMALLBIND));
+ break;
+ case INTBIND:
+ memcpy((void*)&(dbproc->null_INTBIND), (void*)bindval,
sizeof(dbproc->null_INTBIND));
+ break;
+ case CHARBIND:
+ if (bindlen < 0) {
+ dbperror(dbproc, SYBEBBL, 0);
+ return FAIL;
+ }
+ if (dbproc->p_null_CHARBIND) {
+ free(dbproc->p_null_CHARBIND);
+ }
+ dbproc->len_null_CHARBIND = 0;
+ dbproc->p_null_CHARBIND = malloc(bindlen);
+ if (!dbproc->p_null_CHARBIND) {
+ dbperror(dbproc, SYBEMEM, errno);
+ return FAIL;
+ }
+ memcpy((void*)(dbproc->p_null_CHARBIND), (void*)bindval,
bindlen);
+ dbproc->len_null_CHARBIND = bindlen;
+ break;
+ case STRINGBIND:
+ if (dbproc->p_null_STRINGBIND) {
+ free(dbproc->p_null_STRINGBIND);
+ }
+ dbproc->p_null_STRINGBIND = strdup(bindval);
+ if (!dbproc->p_null_STRINGBIND) {
+ dbperror(dbproc, SYBEMEM, errno);
+ return FAIL;
+ }
+ break;
+ case NTBSTRINGBIND:
+ if (dbproc->p_null_NTBSTRINGBIND) {
+ free(dbproc->p_null_NTBSTRINGBIND);
+ }
+ dbproc->p_null_NTBSTRINGBIND = strdup(bindval);
+ if (!dbproc->p_null_NTBSTRINGBIND) {
+ dbperror(dbproc, SYBEMEM, errno);
+ return FAIL;
+ }
+ break;
+ case VARYCHARBIND:
+ if (bindlen < 0 || bindlen >
sizeof(dbproc->null_VARYCHARBIND.str)) {
+ dbperror(dbproc, SYBEBBL, 0);
+ return FAIL;
+ }
+ if (bindlen <= 0) {
+ dbproc->null_VARYCHARBIND.str[0] = '\0';
+ } else {
+ memcpy((void*)(dbproc->null_VARYCHARBIND.str),
(void*)bindval, bindlen);
+ }
+ dbproc->null_VARYCHARBIND.len = bindlen;
+ break;
+ case BINARYBIND:
+ if (bindlen < 0) {
+ dbperror(dbproc, SYBEBBL, 0);
+ return FAIL;
+ }
+ if (dbproc->p_null_BINARYBIND) {
+ free(dbproc->p_null_BINARYBIND);
+ }
+ dbproc->len_null_BINARYBIND = 0;
+ dbproc->p_null_BINARYBIND = malloc(bindlen);
+ if (!dbproc->p_null_BINARYBIND) {
+ dbperror(dbproc, SYBEMEM, errno);
+ return FAIL;
+ }
+ memcpy((void*)(dbproc->p_null_BINARYBIND), (void*)bindval,
bindlen);
+ dbproc->len_null_BINARYBIND = bindlen;
+ break;
+ case DATETIMEBIND:
+ memcpy((void*)&(dbproc->null_DATETIMEBIND), (void*)bindval,
sizeof(dbproc->null_DATETIMEBIND));
+ break;
+ case SMALLDATETIMEBIND:
+ memcpy((void*)&(dbproc->null_SMALLDATETIMEBIND),
(void*)bindval, sizeof(dbproc->null_SMALLDATETIMEBIND));
+ break;
+ case MONEYBIND:
+ memcpy((void*)&(dbproc->null_MONEYBIND), (void*)bindval,
sizeof(dbproc->null_MONEYBIND));
+ break;
+ case SMALLMONEYBIND:
+ memcpy((void*)&(dbproc->null_SMALLMONEYBIND), (void*)bindval,
sizeof(dbproc->null_SMALLMONEYBIND));
+ break;
+ case FLT8BIND:
+ memcpy((void*)&(dbproc->null_FLT8BIND), (void*)bindval,
sizeof(dbproc->null_FLT8BIND));
+ break;
+ case REALBIND:
+ memcpy((void*)&(dbproc->null_REALBIND), (void*)bindval,
sizeof(dbproc->null_REALBIND));
+ break;
+ case DECIMALBIND:
+ memcpy((void*)&(dbproc->null_DECIMALBIND), (void*)bindval,
sizeof(dbproc->null_DECIMALBIND));
+ break;
+ case NUMERICBIND:
+ memcpy((void*)&(dbproc->null_NUMERICBIND), (void*)bindval,
sizeof(dbproc->null_NUMERICBIND));
+ break;
+ case BITBIND:
+ memcpy((void*)&(dbproc->null_BITBIND), (void*)bindval,
sizeof(dbproc->null_BITBIND));
+ break;
+ default:
+ dbperror(dbproc, SYBEBTYP, 0);
+ return FAIL;
+ }
+
+ return SUCCEED;
+}
+
/**
* \ingroup dblib_core
* \brief Tie a null-indicator to a compute result column.
*
*
* When a row is fetched, the indicator variable tells the state of the
column's data.
*
* \param dbproc contains all information needed by db-lib to manage
communications with the server.
* \param computeid identifies which one of potientially many compute rows
is meant. The first compute
* clause has \a computeid == 1.
@@ -6069,56 +6204,169 @@
*
* \param dbproc contains all information needed by db-lib to manage
communications with the server.
* \sa dbcmd(), DBIORDESC(), DBIOWDESC(), dbnextrow(), dbpoll(), DBRBUF(),
dbresults(), dbsqlok(), dbsqlsend().
*/
int
dbiowdesc(DBPROCESS * dbproc)
{
return dbproc->tds_socket->s;
}

-static void
-_set_null_value(BYTE * varaddr, int datatype, int maxlen)
-{
- switch (datatype) {
- case SYBINT8:
- memset(varaddr, '\0', 8);
- break;
- case SYBINT4:
- memset(varaddr, '\0', 4);
- break;
- case SYBINT2:
- memset(varaddr, '\0', 2);
- break;
- case SYBINT1:
- memset(varaddr, '\0', 1);
- break;
- case SYBFLT8:
- memset(varaddr, '\0', 8);
- break;
- case SYBREAL:
- memset(varaddr, '\0', 4);
- break;
- case SYBDATETIME:
- memset(varaddr, '\0', 8);
- break;
- case SYBCHAR:
- if (varaddr)
- varaddr[0] = '\0';
- break;
- case SYBVARCHAR:
- if (varaddr)
- ((DBVARYCHAR *)varaddr)->len = 0;
- ((DBVARYCHAR *)varaddr)->str[0] = '\0';
- break;
- }
-}
+static void
+_set_null_value(DBPROCESS *dbproc, int bindtype, BYTE * varaddr, int dstlen)
+{
+ void *src;
+ DBINT srclen;
+ int nulltermlen = 0;
+ int padding = 0;
+ char padchar;
+ DBINT datalen;
+ DBINT padlen;
+ DBINT len;
+
+ switch(bindtype) {
+ case TINYBIND:
+ src = (void*)&dbproc->null_TINYBIND;
+ srclen = sizeof(dbproc->null_TINYBIND);
+ dstlen = srclen;
+ break;
+ case SMALLBIND:
+ src = (void*)&dbproc->null_SMALLBIND;
+ srclen = sizeof(dbproc->null_SMALLBIND);
+ dstlen = srclen;
+ break;
+ case INTBIND:
+ src = (void*)&dbproc->null_INTBIND;
+ srclen = sizeof(dbproc->null_INTBIND);
+ dstlen = srclen;
+ break;
+ case CHARBIND:
+ padding = 1;
+ padchar = ' ';
+ if (dbproc->p_null_CHARBIND) {
+ src = (void*)dbproc->p_null_CHARBIND;
+ srclen = dbproc->len_null_CHARBIND;
+ } else {
+ src = "";
+ srclen = 0;
+ }
+ break;
+ case STRINGBIND:
+ nulltermlen = 1;
+ padding = 1;
+ padchar = ' ';
+ if (dbproc->p_null_STRINGBIND) {
+ src = (void*)dbproc->p_null_STRINGBIND;
+ srclen = strlen(dbproc->p_null_STRINGBIND);
+ } else {
+ src = "";
+ srclen = 0;
+ }
+ break;
+ case NTBSTRINGBIND:
+ nulltermlen = 1;
+ if (dbproc->p_null_NTBSTRINGBIND) {
+ src = (void*)dbproc->p_null_NTBSTRINGBIND;
+ srclen = strlen(dbproc->p_null_NTBSTRINGBIND);
+ } else {
+ src = "";
+ srclen = 0;
+ }
+ break;
+ case VARYCHARBIND:
+ src = (void*)&dbproc->null_VARYCHARBIND;
+ srclen = sizeof(dbproc->null_VARYCHARBIND);
+ dstlen = srclen;
+ break;
+ case BINARYBIND:
+ padding = 1;
+ padchar = '\0';
+ if (dbproc->p_null_BINARYBIND) {
+ src = (void*)dbproc->p_null_BINARYBIND;
+ srclen = dbproc->len_null_BINARYBIND;
+ } else {
+ src = "";
+ srclen = 0;
+ }
+ break;
+ case DATETIMEBIND:
+ src = (void*)&dbproc->null_DATETIMEBIND;
+ srclen = sizeof(dbproc->null_DATETIMEBIND);
+ dstlen = srclen;
+ break;
+ case SMALLDATETIMEBIND:
+ src = (void*)&dbproc->null_SMALLDATETIMEBIND;
+ srclen = sizeof(dbproc->null_SMALLDATETIMEBIND);
+ dstlen = srclen;
+ break;
+ case MONEYBIND:
+ src = (void*)&dbproc->null_MONEYBIND;
+ srclen = sizeof(dbproc->null_MONEYBIND);
+ dstlen = srclen;
+ break;
+ case SMALLMONEYBIND:
+ src = (void*)&dbproc->null_SMALLMONEYBIND;
+ srclen = sizeof(dbproc->null_SMALLMONEYBIND);
+ dstlen = srclen;
+ break;
+ case FLT8BIND:
+ src = (void*)&dbproc->null_FLT8BIND;
+ srclen = sizeof(dbproc->null_FLT8BIND);
+ dstlen = srclen;
+ break;
+ case REALBIND:
+ src = (void*)&dbproc->null_REALBIND;
+ srclen = sizeof(dbproc->null_REALBIND);
+ dstlen = srclen;
+ break;
+ case DECIMALBIND:
+ src = (void*)&dbproc->null_DECIMALBIND;
+ srclen = sizeof(dbproc->null_DECIMALBIND);
+ dstlen = srclen;
+ break;
+ case NUMERICBIND:
+ src = (void*)&dbproc->null_NUMERICBIND;
+ srclen = sizeof(dbproc->null_NUMERICBIND);
+ dstlen = srclen;
+ break;
+ case BITBIND:
+ src = (void*)&dbproc->null_BITBIND;
+ srclen = sizeof(dbproc->null_BITBIND);
+ dstlen = srclen;
+ break;
+ }
+
+ if (varaddr && dstlen > 0) {
+ datalen = dstlen - nulltermlen;
+ if (datalen > srclen) {
+ datalen = srclen;
+ }
+ if (padding) {
+ padlen = dstlen - (datalen + nulltermlen);
+ } else {
+ padlen = 0;
+ }
+
+ memcpy(varaddr, src, datalen);
+ if (padlen > 0) {
+ memset(varaddr + datalen, padchar, padlen);
+ }
+ if (nulltermlen > 0) {
+ varaddr[datalen + padlen] = '\0';
+ }
+
+ if ( srclen + nulltermlen > dstlen ) {
+ /* Attempt to set variable to NULL resulted in
overflow */
+ dbperror(dbproc, SYBECNOV, 0);
+ }
+ }
+}

DBBOOL
dbisavail(DBPROCESS * dbproc)
{
return dbproc->avail_flag;
}

/** \internal
* \ingroup dblib_internal
* \brief Mark a \c DBPROCESS as "available".
@@ -6282,21 +6530,21 @@
int limited_dest_space = 0;

tdsdump_log(TDS_DBG_INFO1, "copy_data_to_host_var(%d [%s] len %d =>
%d [%s] len %d)\n",
srctype, tds_prdatatype(srctype), srclen, desttype,
tds_prdatatype(desttype), destlen);

if (dbproc) {
tds = dbproc->tds_socket;
}

if (src == NULL || (srclen == 0 && is_nullable_type(srctype))) {
- _set_null_value(dest, desttype, destlen);
+ _set_null_value(dbproc, bindtype, dest, destlen);
return;
}

if (destlen > 0) {
limited_dest_space = 1;
}

/* oft times we are asked to convert a data type to itself */

if ((srctype == desttype) ||



Archive powered by MHonArc 2.6.24.

Top of Page