Date: Monday, March 20, 2006 @ 22:18:18
  Author: marc
    Path: /cvsroot/carob/odbsequoia/src

Modified: descriptors_records.cpp (1.6 -> 1.7)

Implemented SQLFetch() to signed integers, floating-point types and strings 
(both CHAR and WCHAR).


-------------------------+
 descriptors_records.cpp |  168 ++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 162 insertions(+), 6 deletions(-)


Index: odbsequoia/src/descriptors_records.cpp
diff -u odbsequoia/src/descriptors_records.cpp:1.6 
odbsequoia/src/descriptors_records.cpp:1.7
--- odbsequoia/src/descriptors_records.cpp:1.6  Thu Mar  9 15:10:21 2006
+++ odbsequoia/src/descriptors_records.cpp      Mon Mar 20 22:18:18 2006
@@ -24,7 +24,11 @@
 
 #include "odbc_exception.hpp"
 
+
 #include "DriverResultSet.hpp"
+#include "StringCodecs.hpp" //for toString
+
+#include "util.hpp"
 
 using namespace ODBSeqNS;
 
@@ -44,6 +48,34 @@
 AppDescRecord::bind_col(SQLSMALLINT TargetType, SQLPOINTER TargetValuePtr,
                         SQLINTEGER BufferLength, SQLLEN * StrLen_or_Ind)
 {
+    switch (TargetType) {
+
+        // list of supported types so far
+    case (SQL_C_SHORT): //ODBC 2.0
+    case (SQL_C_SSHORT):
+    case (SQL_C_LONG): // ODBC 2.0
+    case (SQL_C_SLONG):
+    case (SQL_C_TINYINT): // ODBC 2.0
+    case (SQL_C_STINYINT):
+//    case (SQL_C_SBIGINT): see below
+
+    case (SQL_C_FLOAT):
+    case (SQL_C_DOUBLE):
+
+    case (SQL_C_WCHAR):
+    case (SQL_C_CHAR):
+        break;
+
+        // else unsupported type
+    default:
+        throw ODBSeqException (L"HYC00",
+                               L"internal error: unsupported conversion in 
SQLBindCol()");
+
+        // We are assuming someone trapped invalid arguments and
+        // throwed "HY003" before us.  "Someone" should be either DM
+        // or set_type()
+    }
+
     set_type(TargetType);
 
     octet_length = BufferLength;
@@ -58,6 +90,9 @@
 ODBSeqException *
 AppDescRecord::fetch_col(CarobNS::DriverResultSet& rs, int rs_col)
 {
+
+    ODBSeqException *warning(0);
+
     if (rs.isNull(rs_col))
     {
         if (0 == indicator_ptr)
@@ -66,18 +101,139 @@
                                   L"because indicator_ptr is null");
    
         * indicator_ptr = SQL_NULL_DATA;
-        return 0;
+        return warning;
     }
 
-    // case (type == SQL_C_INT)
-    * static_cast<int *>(data_ptr) = rs.getAsInt(rs_col);
-    if (octet_length_ptr != 0)
-        * octet_length_ptr = sizeof(int);
+    // TODO: split this switch into separate methods, one for each
+    // target type. Then replace this switch by pointers to these
+    // methods assigned earlier at SQLBindCol() time.  Do it for: (1)
+    // clarity (smaller functions); (2) performance
+
+    // TODO: for each target type, throw "07006" when the (source,
+    // target) types conversion is not allowed in the big SQL->C type
+    // conversion table ("Converting Data from SQL to C Data
+    // Types"). Check that carob does not do it already.
+    switch (concise_type) {
+
+
+        /*** Integer types ***/
+
+        // FIXME: currently not checking for bounds (22003). And no
+        // warnings on fractional truncation either, because carob does
+        // them, see CAROB-77.
+
+    case (SQL_C_SHORT): // ODBC 2.0
+    case (SQL_C_SSHORT):
+        * static_cast<SQLSMALLINT *>(data_ptr) = rs.getAsInt(rs_col);
+        if (octet_length_ptr != 0)
+            * octet_length_ptr = sizeof(SQLSMALLINT);
+        break;
+
+    case (SQL_C_LONG): // ODBC 2.0
+    case (SQL_C_SLONG):
+        // FIXME: here we assume sizeof(long) <= 64
+        * static_cast<SQLINTEGER *>(data_ptr) = rs.getAsInt64(rs_col);
+        if (octet_length_ptr != 0)
+            * octet_length_ptr = sizeof(SQLINTEGER);
+        break;
+
+        // Despite SQL Server's TINYINT being unsigned, ODBC'
+        // SQL_C_TINYINT is signed as we can see here:
+        // http://support.microsoft.com/kb/131382/en-us or in DB2
+        // documentation here:
+        // http://www.google.com/search?q=DB2+C+data+types+for+CLI+applications
+        // TODO: check Microsoft ODBC 2.0 Programmer's Reference and
+        // SDK Guide
+    case (SQL_C_TINYINT): // ODBC 2.0
+    case (SQL_C_STINYINT):
+        * static_cast<SQLSCHAR *>(data_ptr) = rs.getAsInt(rs_col);
+        if (octet_length_ptr != 0)
+            * octet_length_ptr = sizeof(SQLSCHAR);
+        break;
+
+    case (SQL_C_SBIGINT):
+        // * static_cast<SQLBIGINT *>(data_ptr) = rs.getAsInt64(rs_col);
+        * static_cast<int64_t *>(data_ptr) = rs.getAsInt64(rs_col);
+        // TODO: big portability mess here again: long long and
+        // uint64_t are from C99.  Reinterpret_casting 2x32bits struct
+        // SQLBIGINT may cause endianness issues? Should we try
+        // ODBCINT64?
+        if (octet_length_ptr != 0)
+            * octet_length_ptr = sizeof(int64_t);
+        break;
+
+
+        /*** Binary floating-point types ***/
+
+    case (SQL_C_FLOAT):
+        * static_cast<SQLREAL *>(data_ptr) = rs.getAsFloat(rs_col);
+        if (octet_length_ptr != 0)
+            * octet_length_ptr = sizeof(SQLREAL);
+        break;        
+
+    case (SQL_C_DOUBLE):
+        * static_cast<SQLDOUBLE *>(data_ptr) = rs.getAsDouble(rs_col);
+        if (octet_length_ptr != 0)
+            * octet_length_ptr = sizeof(SQLDOUBLE);
+        break;        
+
+
+        /*** String types ***/
+        // FIXME: UNTESTED: check for corner cases (like truncated null 
terminator)
+
+    case (SQL_C_WCHAR): {
+
+        const std::wstring wsres = rs.getAsString(rs_col);
+
+        if (octet_length_ptr != 0)
+            *octet_length_ptr = wsres.size() * sizeof(SQLWCHAR);
+
+        bool truncated = 
+            toSQLW (wsres, static_cast<SQLWCHAR *>(data_ptr),
+                    octet_length/(SQLINTEGER)sizeof(SQLWCHAR), 0);
+
+        if (truncated)
+            warning = new ODBSeqException(L"01004", L"string truncated");
+        break;
+    }
+
+    case (SQL_C_CHAR): {
+
+        std::string nsres = 
CarobNS::StaticCodecs::toString(rs.getAsString(rs_col));
+
+        if (octet_length_ptr != 0)
+            *octet_length_ptr = nsres.size();
+
+        if (octet_length == 0) {
+            warning = new ODBSeqException(L"01004", L"empty buffer");
+            break;
+        }
+
+        const std::string::size_type final_size =
+//          nsres.copy(static_cast<SQLCHAR *>(data_ptr), octet_length-1); // 
_unsigned_ char!
+            nsres.copy(static_cast<char *>   (data_ptr), octet_length-1);
+
+        // Now let's null-terminate the C string
+        * (static_cast<char *>(data_ptr) + final_size) = 0;
+
+        if (final_size != nsres.size())
+            warning = new ODBSeqException(L"01004", L"string truncated");
+
+        break;
+
+    }
+         /*** Unsupported types ***/
+    default:
+        // catching sooner is better (in bind_col() method above),
+        // but we are still allowed to throw HYC00 later here
+        throw ODBSeqException (L"HYC00",
+                               L"internal error: unsupported conversion in 
SQLFetch()");
+    }
 
     if (indicator_ptr != 0 && indicator_ptr != octet_length_ptr)
         *indicator_ptr = 0;
 
-    return 0;
+    return warning;
 }
 /*
  * Local Variables:

_______________________________________________
Carob-commits mailing list
[email protected]
https://forge.continuent.org/mailman/listinfo/carob-commits

Reply via email to