I used libdbi with the freetds driver from Linux to connect to a sybase 
server on Solaris.

My database had a table with a column which was VARCHAR(20)
One of the rows had exactly 20 characters.

In this case libdbi returns an empty result.
I found 2 problems:
* dbd_freetds.c doesn't allocate enought to store the a null terminator.
* freetds ignores a field when it has exactly 20 characters.

I think I fixed both. I used valgrind to find the memory allocation usage.

diff --git a/drivers/freetds/dbd_freetds.c b/drivers/freetds/dbd_freetds.c
index e7df09a..5b5e13e 100644
--- a/drivers/freetds/dbd_freetds.c
+++ b/drivers/freetds/dbd_freetds.c
@@ -977,8 +977,9 @@ dbi_row_t *_dbd_freetds_buffers_binding(dbi_conn_t * 
conn, dbi_result_t * result
         /*
          * Result is more that 8 bytes -
          * allocate additional memory
+         * 1 extra byte for \0
          */
-        addr = row->field_values[idx].d_string = (char *) 
malloc(row->field_sizes[idx]);
+        addr = row->field_values[idx].d_string = (char *) 
malloc(row->field_sizes[idx] + 1);
         break;
     default:
         /* Prepare union to data copy */
-- 

--------------------

I posted the following to the freetds mailing list:

I used freetds from Linux to connect to a sybase server on Solaris.

My database had a table with a column which was VARCHAR(20)
One of the rows had exactly 20 characters.
With a simple SELECT it hit this piece of code which returns CS_FAIL 
without logging anything:

 538                 case CS_FMT_NULLTERM:
 539                     if (src_len == destlen) {
 540                         ret = CS_FAIL;    /* not enough room for 
data + a null terminator - error */
 541                     } else {
 542                         memcpy(dest, srcdata, src_len);
 543                         dest[src_len] = '\0';
 544                         if (resultlen != NULL)
 545                             *resultlen = src_len + 1;
 546                         ret = CS_SUCCEED;
 547                     }
 548                     break;

and the similar:

 765            case CS_FMT_NULLTERM:
 766                 tdsdump_log(TDS_DBG_FUNC, "cs_convert() 
FMT_NULLTERM\n");
 767                 if (len == destlen) {
 768                     tdsdump_log(TDS_DBG_FUNC, "not enough room for 
data + a null terminator - error\n");
 769                     ret = CS_FAIL;    /* not enough room for data + 
a null terminator - error */
 770                 } else {
 771                     memcpy(dest, cres.c, len);
 772                     dest[len] = 0;
 773                     if (resultlen != NULL)
 774                         *resultlen = len + 1;
 775                     ret = CS_SUCCEED;
 776                 }
 777                 break;

I included a patch below.
I'm not sure if the data structure which holds the length of the field 
needs updating.
If I allocate 1 byte extra for the null terminator my query works.
I tried this with Debian testing.

Eddy


diff --git a/src/ctlib/cs.c b/src/ctlib/cs.c
index de6bbda..7fc0595 100644
--- a/src/ctlib/cs.c
+++ b/src/ctlib/cs.c
@@ -389,15 +389,12 @@ CS_RETCODE ret;
                switch (destfmt->format) {

                case CS_FMT_NULLTERM:
-                    if (src_len == destlen) {
-                        ret = CS_FAIL;    /* not enough room for data + 
a null terminator - error */
-                    } else {
-                        memcpy(dest, srcdata, src_len);
-                        dest[src_len] = '\0';
-                        if (resultlen != (CS_INT *) NULL)
-                            *resultlen = src_len + 1;
-                        ret = CS_SUCCEED;
-                    }
+                    memcpy(dest, srcdata, src_len);
+                    /* client code should allocate enough room for data 
+ a null terminator */
+                    dest[src_len] = '\0';
+                    if (resultlen != (CS_INT *) NULL)
+                        *resultlen = src_len + 1;
+                    ret = CS_SUCCEED;
                    break;

                case CS_FMT_PADBLANK:
@@ -615,16 +612,12 @@ CS_RETCODE ret;

            case CS_FMT_NULLTERM:
                tdsdump_log(TDS_DBG_FUNC, "cs_convert() FMT_NULLTERM\n");
-                if (len == destlen) {
-                    tdsdump_log(TDS_DBG_FUNC, "not enough room for data 
+ a null terminator - error\n");
-                    ret = CS_FAIL;    /* not enough room for data + a 
null terminator - error */
-                } else {
-                    memcpy(dest, cres.c, len);
-                    dest[len] = 0;
-                    if (resultlen != (CS_INT *) NULL)
-                        *resultlen = len + 1;
-                    ret = CS_SUCCEED;
-                }
+                /* client code should allocate enough room for data + a 
null terminator */
+                memcpy(dest, cres.c, len);
+                dest[len] = '\0';
+                if (resultlen != (CS_INT *) NULL)
+                    *resultlen = len + 1;
+                ret = CS_SUCCEED;
                break;

            case CS_FMT_PADBLANK:
-- 

-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://sourceforge.net/services/buy/index.php
_______________________________________________
Libdbi-drivers-devel mailing list
Libdbi-drivers-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libdbi-drivers-devel

Reply via email to