]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/db.cpp
respect the encoding of the text style and not only the global control font encoding...
[wxWidgets.git] / src / common / db.cpp
index 23897877c937fff0261ae873703d11012aa1b3c4..a43f461158e5473c0f0c64c5dc2ff55548314883 100644 (file)
@@ -1,5 +1,5 @@
 ///////////////////////////////////////////////////////////////////////////////
-// Name:        db.cpp
+// Name:        src/common/db.cpp
 // Purpose:     Implementation of the wxDb class.  The wxDb class represents a connection
 //              to an ODBC data source.  The wxDb class allows operations on the data
 //              source such as opening and closing the data source.
 // Licence:     wxWindows licence
 ///////////////////////////////////////////////////////////////////////////////
 
-/*
-// SYNOPSIS START
-// SYNOPSIS STOP
-*/
-#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
-    #pragma implementation "db.h"
-#endif
-
 #include "wx/wxprec.h"
 
 #ifdef __BORLANDC__
     #pragma hdrstop
 #endif
 
-#ifdef DBDEBUG_CONSOLE
-    #include "wx/ioswrap.h"
-#endif
+#if wxUSE_ODBC
 
 #ifndef WX_PRECOMP
-    #include "wx/string.h"
     #include "wx/object.h"
     #include "wx/list.h"
+    #include "wx/string.h"
     #include "wx/utils.h"
     #include "wx/log.h"
+    #include "wx/app.h"
 #endif
+
+#ifdef DBDEBUG_CONSOLE
+    #include "wx/ioswrap.h"
+#endif
+
 #include "wx/filefn.h"
 #include "wx/wxchar.h"
 
-#if wxUSE_ODBC
-
 #include <stdio.h>
 #include <string.h>
 #include <assert.h>
@@ -60,7 +54,6 @@
 #include "wx/db.h"
 
 // DLL options compatibility check:
-#include "wx/app.h"
 WX_CHECK_BUILD_OPTIONS("wxODBC")
 
 WXDLLIMPEXP_DATA_ODBC(wxDbList*) PtrBegDbList = 0;
@@ -204,37 +197,37 @@ void wxDbConnectInf::FreeHenv()
 
 void wxDbConnectInf::SetDsn(const wxString &dsn)
 {
-    wxASSERT(dsn.Length() < sizeof(Dsn));
+    wxASSERT(dsn.length() < WXSIZEOF(Dsn));
 
-    wxStrncpy(Dsn, dsn, sizeof(Dsn)-1);
-    Dsn[sizeof(Dsn)-1] = 0;  // Prevent buffer overrun
+    wxStrncpy(Dsn, dsn, WXSIZEOF(Dsn)-1);
+    Dsn[WXSIZEOF(Dsn)-1] = 0;  // Prevent buffer overrun
 }  // wxDbConnectInf::SetDsn()
 
 
 void wxDbConnectInf::SetUserID(const wxString &uid)
 {
-    wxASSERT(uid.Length() < sizeof(Uid));
-    wxStrncpy(Uid, uid, sizeof(Uid)-1);
-    Uid[sizeof(Uid)-1] = 0;  // Prevent buffer overrun
+    wxASSERT(uid.length() < WXSIZEOF(Uid));
+    wxStrncpy(Uid, uid, WXSIZEOF(Uid)-1);
+    Uid[WXSIZEOF(Uid)-1] = 0;  // Prevent buffer overrun
 }  // wxDbConnectInf::SetUserID()
 
 
 void wxDbConnectInf::SetPassword(const wxString &password)
 {
-    wxASSERT(password.Length() < sizeof(AuthStr));
+    wxASSERT(password.length() < WXSIZEOF(AuthStr));
 
-    wxStrncpy(AuthStr, password, sizeof(AuthStr)-1);
-    AuthStr[sizeof(AuthStr)-1] = 0;  // Prevent buffer overrun
+    wxStrncpy(AuthStr, password, WXSIZEOF(AuthStr)-1);
+    AuthStr[WXSIZEOF(AuthStr)-1] = 0;  // Prevent buffer overrun
 }  // wxDbConnectInf::SetPassword()
 
 void wxDbConnectInf::SetConnectionStr(const wxString &connectStr)
 {
-    wxASSERT(connectStr.Length() < sizeof(ConnectionStr));
+    wxASSERT(connectStr.length() < WXSIZEOF(ConnectionStr));
 
     useConnectionStr = wxStrlen(connectStr) > 0;
 
-    wxStrncpy(ConnectionStr, connectStr, sizeof(ConnectionStr)-1);
-    ConnectionStr[sizeof(ConnectionStr)-1] = 0;  // Prevent buffer overrun
+    wxStrncpy(ConnectionStr, connectStr, WXSIZEOF(ConnectionStr)-1);
+    ConnectionStr[WXSIZEOF(ConnectionStr)-1] = 0;  // Prevent buffer overrun
 }  // wxDbConnectInf::SetConnectionStr()
 
 
@@ -290,7 +283,7 @@ int wxDbColFor::Format(int Nation, int dbDataType, SWORD sqlDataType,
         if ((i_sqlDataType == SQL_VARCHAR)
 #if wxUSE_UNICODE
     #if defined(SQL_WCHAR)
-            || (i_sqlDataType == SQL_WCHAR) 
+            || (i_sqlDataType == SQL_WCHAR)
     #endif
     #if defined(SQL_WVARCHAR)
             || (i_sqlDataType == SQL_WVARCHAR)
@@ -535,6 +528,12 @@ void wxDb::initialize()
     typeInfBlob.CaseSensitive = 0;
     typeInfBlob.MaximumScale  = 0;
 
+    typeInfMemo.TypeName.Empty();
+    typeInfMemo.FsqlType      = 0;
+    typeInfMemo.Precision     = 0;
+    typeInfMemo.CaseSensitive = 0;
+    typeInfMemo.MaximumScale  = 0;
+
     // Error reporting is turned OFF by default
     silent = true;
 
@@ -653,6 +652,16 @@ bool wxDb::determineDataTypes(bool failOnDataTypeUnsupported)
         SQL_VARBINARY
     };
 
+    // These are the possible SQL types we check for use agains the datasource we are connected
+    // to for the purpose of determining which data type to use for the MEMO column types
+    // (a type which allow to store large strings; like VARCHAR just with a bigger precision)
+    //
+    // NOTE: The first type in this enumeration that is determined to be supported by the
+    //       datasource/driver is the one that will be used.
+    SWORD PossibleSqlMemoTypes[] = {
+        SQL_LONGVARCHAR,
+    };
+
 
     // Query the data source regarding data type information
 
@@ -759,6 +768,16 @@ bool wxDb::determineDataTypes(bool failOnDataTypeUnsupported)
     else if (failOnDataTypeUnsupported)
         return false;
 
+    // --------------- MEMO ---------------
+    for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlMemoTypes) &&
+                     !getDataTypeInfo(PossibleSqlMemoTypes[iIndex], typeInfMemo); ++iIndex)
+    {}
+
+    if (iIndex < WXSIZEOF(PossibleSqlMemoTypes))
+        typeInfMemo.FsqlType = PossibleSqlMemoTypes[iIndex];
+    else if (failOnDataTypeUnsupported)
+        return false;
+
     return true;
 }  // wxDb::determineDataTypes
 
@@ -793,6 +812,7 @@ bool wxDb::open(bool failOnDataTypeUnsupported)
     cout << wxT("FLOAT   DATA TYPE: ") << typeInfFloat.TypeName << endl;
     cout << wxT("DATE    DATA TYPE: ") << typeInfDate.TypeName << endl;
     cout << wxT("BLOB    DATA TYPE: ") << typeInfBlob.TypeName << endl;
+    cout << wxT("MEMO    DATA TYPE: ") << typeInfMemo.TypeName << endl;
     cout << endl;
 #endif
 
@@ -802,15 +822,15 @@ bool wxDb::open(bool failOnDataTypeUnsupported)
 
 bool wxDb::Open(const wxString& inConnectStr, bool failOnDataTypeUnsupported)
 {
-    wxASSERT(inConnectStr.Length());
+    wxASSERT(inConnectStr.length());
     return Open(inConnectStr, NULL, failOnDataTypeUnsupported);
 }
 
 bool wxDb::Open(const wxString& inConnectStr, SQLHWND parentWnd, bool failOnDataTypeUnsupported)
 {
-    dsn        = wxT("");
-    uid        = wxT("");
-    authStr    = wxT("");
+    dsn        = wxEmptyString;
+    uid        = wxEmptyString;
+    authStr    = wxEmptyString;
 
     RETCODE retcode;
 
@@ -837,8 +857,8 @@ bool wxDb::Open(const wxString& inConnectStr, SQLHWND parentWnd, bool failOnData
     inConnectionStr = inConnectStr;
 
     retcode = SQLDriverConnect(hdbc, parentWnd, (SQLTCHAR FAR *)inConnectionStr.c_str(),
-                        (SWORD)inConnectionStr.Length(), (SQLTCHAR FAR *)outConnectBuffer,
-                        sizeof(outConnectBuffer), &outConnectBufferLen, SQL_DRIVER_COMPLETE );
+                        (SWORD)inConnectionStr.length(), (SQLTCHAR FAR *)outConnectBuffer,
+                        WXSIZEOF(outConnectBuffer), &outConnectBufferLen, SQL_DRIVER_COMPLETE );
 
     if ((retcode != SQL_SUCCESS) &&
         (retcode != SQL_SUCCESS_WITH_INFO))
@@ -854,13 +874,13 @@ bool wxDb::Open(const wxString& inConnectStr, SQLHWND parentWnd, bool failOnData
 /********** wxDb::Open() **********/
 bool wxDb::Open(const wxString &Dsn, const wxString &Uid, const wxString &AuthStr, bool failOnDataTypeUnsupported)
 {
-    wxASSERT(Dsn.Length());
+    wxASSERT(!Dsn.empty());
     dsn        = Dsn;
     uid        = Uid;
     authStr    = AuthStr;
 
-    inConnectionStr = wxT("");
-    outConnectionStr = wxT("");
+    inConnectionStr = wxEmptyString;
+    outConnectionStr = wxEmptyString;
 
     RETCODE retcode;
 
@@ -900,7 +920,7 @@ bool wxDb::Open(wxDbConnectInf *dbConnectInf, bool failOnDataTypeUnsupported)
 
     // Use the connection string if one is present
     if (dbConnectInf->UseConnectionStr())
-        return Open(GetConnectionInStr(), failOnDataTypeUnsupported);
+        return Open(dbConnectInf->GetConnectionStr(), failOnDataTypeUnsupported);
     else
         return Open(dbConnectInf->GetDsn(), dbConnectInf->GetUserID(),
                     dbConnectInf->GetPassword(), failOnDataTypeUnsupported);
@@ -942,8 +962,8 @@ bool wxDb::Open(wxDb *copyDb)
         inConnectionStr = copyDb->GetConnectionInStr();
 
         retcode = SQLDriverConnect(hdbc, NULL, (SQLTCHAR FAR *)inConnectionStr.c_str(),
-                            (SWORD)inConnectionStr.Length(), (SQLTCHAR FAR *)outConnectBuffer,
-                            sizeof(outConnectBuffer), &outConnectBufferLen, SQL_DRIVER_COMPLETE);
+                            (SWORD)inConnectionStr.length(), (SQLTCHAR FAR *)outConnectBuffer,
+                            WXSIZEOF(outConnectBuffer), &outConnectBufferLen, SQL_DRIVER_COMPLETE);
 
         if ((retcode != SQL_SUCCESS) &&
             (retcode != SQL_SUCCESS_WITH_INFO))
@@ -1053,12 +1073,20 @@ bool wxDb::Open(wxDb *copyDb)
     typeInfBlob.CaseSensitive    = copyDb->typeInfBlob.CaseSensitive;
     typeInfBlob.MaximumScale     = copyDb->typeInfBlob.MaximumScale;
 
+    // Memo
+    typeInfMemo.FsqlType         = copyDb->typeInfMemo.FsqlType;
+    typeInfMemo.TypeName         = copyDb->typeInfMemo.TypeName;
+    typeInfMemo.Precision        = copyDb->typeInfMemo.Precision;
+    typeInfMemo.CaseSensitive    = copyDb->typeInfMemo.CaseSensitive;
+    typeInfMemo.MaximumScale     = copyDb->typeInfMemo.MaximumScale;
+
 #ifdef DBDEBUG_CONSOLE
     cout << wxT("VARCHAR DATA TYPE: ") << typeInfVarchar.TypeName << endl;
     cout << wxT("INTEGER DATA TYPE: ") << typeInfInteger.TypeName << endl;
     cout << wxT("FLOAT   DATA TYPE: ") << typeInfFloat.TypeName << endl;
     cout << wxT("DATE    DATA TYPE: ") << typeInfDate.TypeName << endl;
     cout << wxT("BLOB    DATA TYPE: ") << typeInfBlob.TypeName << endl;
+    cout << wxT("MEMO    DATA TYPE: ") << typeInfMemo.TypeName << endl;
     cout << endl;
 #endif
 
@@ -1611,7 +1639,7 @@ bool wxDb::getDataTypeInfo(SWORD fSqlType, wxDbSqlTypeInfo &structSQLTypeInfo)
  * wxDbSqlTypeInfo is a structure that is filled in with data type information,
  */
     RETCODE retcode;
-    SDWORD  cbRet;
+    SQLLEN  cbRet;
 
     // Get information about the data type specified
     if (SQLGetTypeInfo(hstmt, fSqlType) != SQL_SUCCESS)
@@ -1727,8 +1755,9 @@ void wxDb::Close(void)
         tiu = (wxTablesInUse *)pNode->GetData();
         if (tiu->pDb == this)
         {
-            s.Printf(wxT("(%-20s)     tableID:[%6lu]     pDb:[%p]"), tiu->tableName,tiu->tableID,tiu->pDb);
-            s2.Printf(wxT("Orphaned table found using pDb:[%p]"),this);
+            s.Printf(wxT("(%-20s)     tableID:[%6lu]     pDb:[%p]"),
+                     tiu->tableName, tiu->tableID, wx_static_cast(void*, tiu->pDb));
+            s2.Printf(wxT("Orphaned table found using pDb:[%p]"), wx_static_cast(void*, this));
             wxLogDebug(s.c_str(),s2.c_str());
         }
         pNode = pNode->GetNext();
@@ -1857,7 +1886,7 @@ void wxDb::DispNextError(void)
 /********** wxDb::logError() **********/
 void wxDb::logError(const wxString &errMsg, const wxString &SQLState)
 {
-    wxASSERT(errMsg.Length());
+    wxASSERT(errMsg.length());
 
     static int pLast = -1;
     int dbStatus;
@@ -1873,7 +1902,7 @@ void wxDb::logError(const wxString &errMsg, const wxString &SQLState)
     wxStrncpy(errorList[pLast], errMsg, DB_MAX_ERROR_MSG_LEN);
     errorList[pLast][DB_MAX_ERROR_MSG_LEN] = 0;
 
-    if (SQLState.Length())
+    if (SQLState.length())
         if ((dbStatus = TranslateSqlState(SQLState)) != DB_ERR_FUNCTION_SEQUENCE_ERROR)
             DB_STATUS = dbStatus;
 
@@ -2138,7 +2167,7 @@ bool wxDb::CreateView(const wxString &viewName, const wxString &colList,
     sqlStmt  = wxT("CREATE VIEW ");
     sqlStmt += viewName;
 
-    if (colList.Length())
+    if (colList.length())
     {
         sqlStmt += wxT(" (");
         sqlStmt += colList;
@@ -2249,7 +2278,7 @@ bool wxDb::ExecSql(const wxString &pSqlStmt, wxDbColInf** columns, short& numcol
     short colNum;
     wxChar name[DB_MAX_COLUMN_NAME_LEN+1];
     SWORD Sword;
-    SDWORD Sdword;
+    SQLLEN Sqllen;
     wxDbColInf* pColInf = new wxDbColInf[noCols];
 
     // Fill in column information (name, datatype)
@@ -2257,7 +2286,7 @@ bool wxDb::ExecSql(const wxString &pSqlStmt, wxDbColInf** columns, short& numcol
     {
         if (SQLColAttributes(hstmt, (UWORD)(colNum+1), SQL_COLUMN_NAME,
             name, sizeof(name),
-            &Sword, &Sdword) != SQL_SUCCESS)
+            &Sword, &Sqllen) != SQL_SUCCESS)
         {
             DispAllErrors(henv, hdbc, hstmt);
             delete[] pColInf;
@@ -2268,14 +2297,14 @@ bool wxDb::ExecSql(const wxString &pSqlStmt, wxDbColInf** columns, short& numcol
         pColInf[colNum].colName[DB_MAX_COLUMN_NAME_LEN] = 0;  // Prevent buffer overrun
 
         if (SQLColAttributes(hstmt, (UWORD)(colNum+1), SQL_COLUMN_TYPE,
-            NULL, 0, &Sword, &Sdword) != SQL_SUCCESS)
+            NULL, 0, &Sword, &Sqllen) != SQL_SUCCESS)
         {
             DispAllErrors(henv, hdbc, hstmt);
             delete[] pColInf;
             return false;
         }
 
-        switch (Sdword)
+        switch (Sqllen)
         {
 #if wxUSE_UNICODE
     #if defined(SQL_WCHAR)
@@ -2289,6 +2318,9 @@ bool wxDb::ExecSql(const wxString &pSqlStmt, wxDbColInf** columns, short& numcol
             case SQL_CHAR:
                 pColInf[colNum].dbDataType = DB_DATA_TYPE_VARCHAR;
                 break;
+            case SQL_LONGVARCHAR:
+                pColInf[colNum].dbDataType = DB_DATA_TYPE_MEMO;
+                break;
             case SQL_TINYINT:
             case SQL_SMALLINT:
             case SQL_INTEGER:
@@ -2312,7 +2344,7 @@ bool wxDb::ExecSql(const wxString &pSqlStmt, wxDbColInf** columns, short& numcol
 #ifdef __WXDEBUG__
             default:
                 wxString errMsg;
-                errMsg.Printf(wxT("SQL Data type %ld currently not supported by wxWidgets"), (long)Sdword);
+                errMsg.Printf(wxT("SQL Data type %ld currently not supported by wxWidgets"), (long)Sqllen);
                 wxLogDebug(errMsg,wxT("ODBC DEBUG MESSAGE"));
 #endif
         }
@@ -2337,7 +2369,7 @@ bool wxDb::GetNext(void)
 
 
 /********** wxDb::GetData()  **********/
-bool wxDb::GetData(UWORD colNo, SWORD cType, PTR pData, SDWORD maxLen, SDWORD FAR *cbReturned)
+bool wxDb::GetData(UWORD colNo, SWORD cType, PTR pData, SDWORD maxLen, SQLLEN FAR *cbReturned)
 {
     wxASSERT(pData);
     wxASSERT(cbReturned);
@@ -2367,7 +2399,7 @@ int wxDb::GetKeyFields(const wxString &tableName, wxDbColInf* colInf, UWORD noCo
     wxChar       szPkCol[DB_MAX_COLUMN_NAME_LEN+1];   /* Primary key column     */
     wxChar       szFkCol[DB_MAX_COLUMN_NAME_LEN+1];   /* Foreign key column     */
     SQLRETURN    retcode;
-    SDWORD       cb;
+    SQLLEN       cb;
     SWORD        i;
     wxString     tempStr;
     /*
@@ -2534,7 +2566,7 @@ wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const wxChar *userID)
     wxDbColInf *colInf = 0;
 
     RETCODE  retcode;
-    SDWORD   cb;
+    SQLLEN   cb;
 
     wxString TableName;
 
@@ -2693,7 +2725,7 @@ wxDbColInf *wxDb::GetColumns(const wxString &tableName, UWORD *numCols, const wx
     wxDbColInf *colInf = 0;
 
     RETCODE  retcode;
-    SDWORD   cb;
+    SQLLEN   cb;
 
     wxString TableName;
 
@@ -3072,6 +3104,9 @@ wxDbColInf *wxDb::GetColumns(const wxString &tableName, int *numCols, const wxCh
                         case SQL_CHAR:
                             colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR;
                         break;
+                        case SQL_LONGVARCHAR:
+                            colInf[colNo].dbDataType = DB_DATA_TYPE_MEMO;
+                            break;
                         case SQL_TINYINT:
                         case SQL_SMALLINT:
                         case SQL_INTEGER:
@@ -3306,7 +3341,7 @@ wxDbInf *wxDb::GetCatalog(const wxChar *userID)
     int      noTab = 0;     // Counter while filling table entries
     int      pass;
     RETCODE  retcode;
-    SDWORD   cb;
+    SQLLEN   cb;
     wxString tblNameSave;
 
     wxString UserID;
@@ -3414,10 +3449,10 @@ bool wxDb::Catalog(const wxChar *userID, const wxString &fileName)
  *       to avoid undesired unbinding of columns.
  */
 {
-    wxASSERT(fileName.Length());
+    wxASSERT(fileName.length());
 
     RETCODE   retcode;
-    SDWORD    cb;
+    SQLLEN    cb;
     wxChar    tblName[DB_MAX_TABLE_NAME_LEN+1];
     wxString  tblNameSave;
     wxChar    colName[DB_MAX_COLUMN_NAME_LEN+1];
@@ -3534,14 +3569,14 @@ bool wxDb::TableExists(const wxString &tableName, const wxChar *userID, const wx
  *        userID != ""    ... UserID set equal to 'userID'
  */
 {
-    wxASSERT(tableName.Length());
+    wxASSERT(tableName.length());
 
     wxString TableName;
 
     if (Dbms() == dbmsDBASE)
     {
         wxString dbName;
-        if (tablePath.Length())
+        if (tablePath.length())
             dbName.Printf(wxT("%s/%s.dbf"), tablePath.c_str(), tableName.c_str());
         else
             dbName.Printf(wxT("%s.dbf"), tableName.c_str());
@@ -3611,10 +3646,10 @@ bool wxDb::TableExists(const wxString &tableName, const wxChar *userID, const wx
 bool wxDb::TablePrivileges(const wxString &tableName, const wxString &priv, const wxChar *userID,
                             const wxChar *schema, const wxString &WXUNUSED(tablePath))
 {
-    wxASSERT(tableName.Length());
+    wxASSERT(tableName.length());
 
     wxDbTablePrivilegeInfo  result;
-    SDWORD  cbRetVal;
+    SQLLEN  cbRetVal;
     RETCODE retcode;
 
     // We probably need to be able to dynamically set this based on
@@ -3760,7 +3795,7 @@ const wxString wxDb::SQLColumnName(const wxChar *colName)
 bool wxDb::SetSqlLogging(wxDbSqlLogState state, const wxString &filename, bool append)
 {
     wxASSERT(state == sqlLogON  || state == sqlLogOFF);
-    wxASSERT(state == sqlLogOFF || filename.Length());
+    wxASSERT(state == sqlLogOFF || filename.length());
 
     if (state == sqlLogON)
     {
@@ -3790,7 +3825,7 @@ bool wxDb::SetSqlLogging(wxDbSqlLogState state, const wxString &filename, bool a
 /********** wxDb::WriteSqlLog() **********/
 bool wxDb::WriteSqlLog(const wxString &logMsg)
 {
-    wxASSERT(logMsg.Length());
+    wxASSERT(logMsg.length());
 
     if (fpSqlLog == 0 || sqlLogState == sqlLogOFF)
         return false;
@@ -3951,7 +3986,7 @@ wxDBMS wxDb::Dbms(void)
 
     baseName[3] = 0;
     if (!wxStricmp(baseName,wxT("DB2")))
-        return((wxDBMS)(dbmsType = dbmsDBASE));
+        return((wxDBMS)(dbmsType = dbmsDB2));
 
     return((wxDBMS)(dbmsType = dbmsUNIDENTIFIED));
 
@@ -3962,8 +3997,8 @@ bool wxDb::ModifyColumn(const wxString &tableName, const wxString &columnName,
                         int dataType, ULONG columnLength,
                         const wxString &optionalParam)
 {
-    wxASSERT(tableName.Length());
-    wxASSERT(columnName.Length());
+    wxASSERT(tableName.length());
+    wxASSERT(columnName.length());
     wxASSERT((dataType == DB_DATA_TYPE_VARCHAR && columnLength > 0) ||
              dataType != DB_DATA_TYPE_VARCHAR);
 
@@ -4041,7 +4076,7 @@ bool wxDb::ModifyColumn(const wxString &tableName, const wxString &columnName,
     }
 
     // for passing things like "NOT NULL"
-    if (optionalParam.Length())
+    if (optionalParam.length())
     {
         sqlStmt += wxT(" ");
         sqlStmt += optionalParam;