Date: Thursday, March 30, 2006 @ 21:23:52
  Author: marc
    Path: /cvsroot/carob/odbsequoia

Modified: odbcinst.ini (1.2 -> 1.3) src/connect.cpp (1.21 -> 1.22)
          src/env.cpp (1.10 -> 1.11) src/env.hpp (1.5 -> 1.6) src/inst.hpp
          (1.6 -> 1.7)

Now letting empty ODBC.INI values go through carob (and fail with a more 
detailed error)
Implemented FakeODBC2 in odbcinst.ini, fixes ODBSEQ-20
Documented cryptic SQLGetPrivateProfileString() in inst.hpp


-----------------+
 odbcinst.ini    |    1 +
 src/connect.cpp |   33 +++++++++++++++++----------------
 src/env.cpp     |   24 +++++++++++++++++++++---
 src/env.hpp     |    4 +++-
 src/inst.hpp    |   39 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 81 insertions(+), 20 deletions(-)


Index: odbsequoia/odbcinst.ini
diff -u odbsequoia/odbcinst.ini:1.2 odbsequoia/odbcinst.ini:1.3
--- odbsequoia/odbcinst.ini:1.2 Thu Mar 23 00:32:29 2006
+++ odbsequoia/odbcinst.ini     Thu Mar 30 21:23:52 2006
@@ -4,3 +4,4 @@
 Debug = 1
 CommLog = 1
 FileUsage = 1
+#FakeODBC2 = false (default = true)
Index: odbsequoia/src/connect.cpp
diff -u odbsequoia/src/connect.cpp:1.21 odbsequoia/src/connect.cpp:1.22
--- odbsequoia/src/connect.cpp:1.21     Thu Mar 30 18:53:31 2006
+++ odbsequoia/src/connect.cpp  Thu Mar 30 21:23:52 2006
@@ -30,8 +30,6 @@
 #include "StringCodecs.hpp"
 #include "Common.hpp" // setLogLevel()
 
-#include <odbcinst.h>
-
 #include <cstdlib> // for atoi()
 
 
@@ -88,10 +86,6 @@
     LPCSTR cdsn = narrow_dsn.c_str();
 #endif
 
-    // The trick: providing a zero-length default value is like
-    // providing NO default value. Now we can throw an SQL_ERROR
-    // when we require the user to provide a value.
-
     // TODO: call SQLInstallerError() to throw better diags
     // BTW how could we fail when providing a default value?
     
@@ -99,36 +93,43 @@
 
     // Slurp DSN information from odbc.ini into ConnectionParameters
 
+    // Behaviour of SQLGetPrivateProfileString is complex and weird,
+    // check comments in inst.hpp
+
+    // For most keys, if the user sets an empty string then zero is
+    // returned and we let carob connection fail later on. We should
+    // be stricter and throw a good diag.
+
     /* Server host name/IP address */
-    if (0 >= SQLGetPrivateProfileString(cdsn, SERVER_INI, "localhost",
+    if (0 > SQLGetPrivateProfileString(cdsn, SERVER_INI, "localhost",
                                         temp, MAX_VALUE_LEN, ODBC_INI))
-        return SQL_ERROR; // TODO: diags. On the other hand it can hardly fail.
+        return SQL_ERROR;
     std::wstring serverhost = fromString(std::string(temp));
 
     /* Port number */
-    if (0 >= SQLGetPrivateProfileString(cdsn, PORT_INI, "25322",
+    if (0 > SQLGetPrivateProfileString(cdsn, PORT_INI, "25322",
                                         temp, MAX_VALUE_LEN, ODBC_INI))
-        return SQL_ERROR; // TODO: diags. On the other hand it can hardly fail.
+        return SQL_ERROR;
     in_port_t port = atoi(temp);
 
-    /* Virtual Database name (mandatory, no default) */
+    /* Virtual Database name (mandatory, be stricter here) */
     if (0 >= SQLGetPrivateProfileString(cdsn, DATABASE_INI, "",
                                         temp, MAX_VALUE_LEN, ODBC_INI))
         throw ODBSeqException(L"08001", L"'" WIDENMACRO(DATABASE_INI) L"'"
-                              L" parameter not found in .ini file");
+                              L" key not found or empty in " 
WIDENMACRO(ODBC_INI) L" file");
     std::wstring vdbname = fromString(std::string(temp));
 
     /* Prefix for diagnostics/exceptions/warnings coming from the backend */
-    if (0 >= SQLGetPrivateProfileString(cdsn, BACKEND_IDS_INI, 
DEFAULT_BACKEND_IDS_INI,
+    if (0 > SQLGetPrivateProfileString(cdsn, BACKEND_IDS_INI, 
DEFAULT_BACKEND_IDS_INI,
                                         temp, MAX_VALUE_LEN, ODBC_INI))
         return SQL_ERROR; // TODO: diags. On the other hand it can hardly fail.
     this->backend_diagids = fromString(std::string(temp));
 
-    /* Log level (mainly for carob) */
-    if (0 >= SQLGetPrivateProfileString(cdsn, LOG_LEVEL_INI, "DEFAULTLOGLEVEL",
+    /* Log level (mainly for carob) TODO: move this to inst.ini/Env ctor */
+    if (0 > SQLGetPrivateProfileString(cdsn, LOG_LEVEL_INI, 
"DEFAULTCAROBLOGLEVEL",
                                         temp, MAX_VALUE_LEN, ODBC_INI))
         return SQL_ERROR; // TODO: diags. On the other hand it can hardly fail.
-    if (0 != std::string(temp).compare("DEFAULTLOGLEVEL"))
+    if (0 != std::string(temp).compare("DEFAULTCAROBLOGLEVEL"))
         try {
             setLogLevel(StringLogLevel(temp));
         } catch (const std::string& errmsg) { // unknown log level!
Index: odbsequoia/src/env.cpp
diff -u odbsequoia/src/env.cpp:1.10 odbsequoia/src/env.cpp:1.11
--- odbsequoia/src/env.cpp:1.10 Thu Mar 30 18:53:31 2006
+++ odbsequoia/src/env.cpp      Thu Mar 30 21:23:52 2006
@@ -23,6 +23,7 @@
 
 #include "connect.hpp"
 #include "odbc_exception.hpp"
+#include "inst.hpp"
 
 #include "Common.hpp" // for the logger
 
@@ -34,6 +35,26 @@
 
 using namespace ODBSeqNS;
 
+ODBCEnv::ODBCEnv() : ODBCItem(*this) // I have no father
+{
+#define MAX_VALUE_LEN 30
+    char temp[MAX_VALUE_LEN];
+
+    /* Fake ODBC version 2 */
+    if (0 > SQLGetPrivateProfileString(MYDRIVER_NAME_INST_INI, 
FAKEODBC2_INST_INI, "true",
+                                       temp, MAX_VALUE_LEN, ODBCINST_INI))
+        // FIXME: catch above & return diags
+        // Problem: how to return diags without any object?
+        // But how could this fail anyway?
+        throw ODBSeqException(L"TODO",
+                              L"Invalid " WIDENMACRO(FAKEODBC2_INST_INI) L" 
value");
+
+    if (0 == std::string(temp).compare("false"))
+        fake_version2 = false;
+    else
+        fake_version2 = true;
+}
+
 namespace {
     const std::wstring SETENVATTR_FUNC = L"env.cpp:SQLSetEnvAttr";
 }
@@ -69,9 +90,6 @@
 
             std::wstring func_witharg(SETENVATTR_FUNC + L"(ODBC_VERSION, 2, 
)");
             
-            // TODO: move this constant to odbc.ini
-            bool fake_version2 = true;
-
             if (!fake_version2) {
                 std::wstring msg(L"faking ODBC version 2 is disabled");
                 CarobNS::logFatal(func_witharg, msg);
Index: odbsequoia/src/env.hpp
diff -u odbsequoia/src/env.hpp:1.5 odbsequoia/src/env.hpp:1.6
--- odbsequoia/src/env.hpp:1.5  Thu Mar 30 18:42:58 2006
+++ odbsequoia/src/env.hpp      Thu Mar 30 21:23:52 2006
@@ -35,12 +35,14 @@
 class ODBCEnv : public ODBCItem
 {
 public:
-    ODBCEnv() : ODBCItem(*this) { }; // I have no father
+    ODBCEnv();
     SQLRETURN
     ODBCEnv::AllocConnect(SQLHANDLE * OutputHandle);
 
     SQLRETURN
     ODBCEnv::set_env_attr(SQLINTEGER attribute, SQLPOINTER value, SQLINTEGER 
str_len);
+    
+    bool fake_version2;
 };
 
 }
Index: odbsequoia/src/inst.hpp
diff -u odbsequoia/src/inst.hpp:1.6 odbsequoia/src/inst.hpp:1.7
--- odbsequoia/src/inst.hpp:1.6 Thu Mar 30 17:23:53 2006
+++ odbsequoia/src/inst.hpp     Thu Mar 30 21:23:52 2006
@@ -22,6 +22,10 @@
 #ifndef ODBSEQ_INST
 #define ODBSEQ_INST
 
+
+#include <odbcinst.h>
+
+
 /* ODBC initialization files */
 #ifndef WIN32
 #define ODBC_INI "odbc.ini"
@@ -31,7 +35,42 @@
 #define ODBCINST_INI "ODBCINST.INI"
 #endif
 
+#define MYDRIVER_NAME_INST_INI "Sequoia"
+
+
+// unixODBC 2.2 SQLGetPrivateProfileString() tips:
+
+// - in ODBCINST.INI -
+
+// Here SQLGetPrivateProfileString(INST) returns strlen(value) + 1,
+// INCLUDING the terminating null, whatever the lpszDefault
+// arg. Corner cases:
+
+// < 0 on error (?)
+// 0   when key is missing (and lpszDefault is set)
+// 1   when value is missing (= empty string + terminating null)
+
+// The default value is set only when 0 is returned (so the user can
+// explicitely set an empty value if wanted).
+
+// - in ODBC.INI -
+
+// For more fun, the behaviour now differs: it returns strlen(value),
+// EXCLUDING the terminating null. And it returns strlen(lpszDefault)
+// when the key is missing.  So it's now absolutely impossible to make
+// the difference between a value explicity set in the file and the
+// case missing key && lpszDefault set. Empty string value is still not
+// an issue.
+
+
+// These key names are not case-sensitive with unixODBC 2.2.
+// However the associated values are returned case-untouched.
+// Others DMs?
+
+// ODBINST.INI constants
+#define FAKEODBC2_INST_INI "FakeODBC2"
 
+// ODBC.INI constants
 #define SERVER_INI "Servername"
 #define DATABASE_INI "Database"
 #define USERNAME_INI "UserName"

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

Reply via email to