added option to bind UTF-8 string using DBBind
authorVictor Kirhenshtein <victor@netxms.org>
Wed, 17 Aug 2016 16:05:47 +0000 (19:05 +0300)
committerVictor Kirhenshtein <victor@netxms.org>
Wed, 17 Aug 2016 16:05:47 +0000 (19:05 +0300)
include/dbdrv.h
include/nms_util.h
src/db/dbdrv/db2/db2.cpp
src/db/dbdrv/informix/informix.cpp
src/db/dbdrv/mysql/mysql.cpp
src/db/dbdrv/odbc/odbc.cpp
src/db/dbdrv/oracle/oracle.cpp
src/db/dbdrv/pgsql/pgsql.cpp
src/db/dbdrv/sqlite/sqlite.cpp
src/db/libnxdb/session.cpp
src/libnetxms/unicode.cpp

index ef3264a..8443e38 100644 (file)
@@ -28,7 +28,7 @@
 /**
  * API version
  */
-#define DBDRV_API_VERSION           18
+#define DBDRV_API_VERSION           19
 
 
 //
@@ -90,18 +90,19 @@ typedef void * DBDRV_UNBUFFERED_RESULT;
 // C and SQL types for parameter binding
 //
 
-#define DB_CTYPE_STRING    0
-#define DB_CTYPE_INT32     1
-#define DB_CTYPE_UINT32    2
-#define DB_CTYPE_INT64     3
-#define DB_CTYPE_UINT64    4
-#define DB_CTYPE_DOUBLE    5
-
-#define DB_SQLTYPE_VARCHAR 0
-#define DB_SQLTYPE_INTEGER 1
-#define DB_SQLTYPE_BIGINT  2
-#define DB_SQLTYPE_DOUBLE  3
-#define DB_SQLTYPE_TEXT    4
+#define DB_CTYPE_STRING       0
+#define DB_CTYPE_INT32        1
+#define DB_CTYPE_UINT32       2
+#define DB_CTYPE_INT64        3
+#define DB_CTYPE_UINT64       4
+#define DB_CTYPE_DOUBLE       5
+#define DB_CTYPE_UTF8_STRING  6
+
+#define DB_SQLTYPE_VARCHAR    0
+#define DB_SQLTYPE_INTEGER    1
+#define DB_SQLTYPE_BIGINT     2
+#define DB_SQLTYPE_DOUBLE     3
+#define DB_SQLTYPE_TEXT       4
 
 /**
  * DBIsTableExist return codes
index 5ab7cb8..56ff1dc 100644 (file)
@@ -1727,8 +1727,10 @@ WCHAR LIBNETXMS_EXPORTABLE *ERR_error_string_W(int nError, WCHAR *pwszBuffer);
 size_t LIBNETXMS_EXPORTABLE ucs2_to_ucs4(const UCS2CHAR *src, int srcLen, WCHAR *dst, int dstLen);
 size_t LIBNETXMS_EXPORTABLE ucs4_to_ucs2(const WCHAR *src, int srcLen, UCS2CHAR *dst, int dstLen);
 size_t LIBNETXMS_EXPORTABLE ucs2_to_utf8(const UCS2CHAR *src, int srcLen, char *dst, int dstLen);
+size_t LIBNETXMS_EXPORTABLE utf8_to_ucs2(const char *src, int srcLen, UCS2CHAR *dst, int dstLen);
 UCS2CHAR LIBNETXMS_EXPORTABLE *UCS2StringFromUCS4String(const WCHAR *pwszString);
 WCHAR LIBNETXMS_EXPORTABLE *UCS4StringFromUCS2String(const UCS2CHAR *pszString);
+UCS2CHAR LIBNETXMS_EXPORTABLE *UCS2StringFromUTF8String(const char *utf8String);
 #endif
 
 size_t LIBNETXMS_EXPORTABLE utf8_to_mb(const char *src, int srcLen, char *dst, int dstLen);
index f75f753..40402aa 100644 (file)
@@ -361,23 +361,38 @@ extern "C" DBDRV_STATEMENT EXPORT DrvPrepare(DB2DRV_CONN *pConn, NETXMS_WCHAR *p
 extern "C" void EXPORT DrvBind(DB2DRV_STATEMENT *statement, int pos, int sqlType, int cType, void *buffer, int allocType)
 {
        static SQLSMALLINT odbcSqlType[] = { SQL_VARCHAR, SQL_INTEGER, SQL_BIGINT, SQL_DOUBLE, SQL_LONGVARCHAR };
-       static SQLSMALLINT odbcCType[] = { SQL_C_WCHAR, SQL_C_SLONG, SQL_C_ULONG, SQL_C_SBIGINT, SQL_C_UBIGINT, SQL_C_DOUBLE };
-       static DWORD bufferSize[] = { 0, sizeof(LONG), sizeof(DWORD), sizeof(INT64), sizeof(QWORD), sizeof(double) };
+       static SQLSMALLINT odbcCType[] = { SQL_C_WCHAR, SQL_C_SLONG, SQL_C_ULONG, SQL_C_SBIGINT, SQL_C_UBIGINT, SQL_C_DOUBLE, SQL_C_WCHAR };
+       static DWORD bufferSize[] = { 0, sizeof(LONG), sizeof(DWORD), sizeof(INT64), sizeof(QWORD), sizeof(double), 0 };
 
-       int length = (int)wcslen((WCHAR *)buffer) + 1;
+       int length = (cType == DB_CTYPE_STRING) ? (int)wcslen((WCHAR *)buffer) + 1 : 0;
 
        SQLPOINTER sqlBuffer;
        switch(allocType)
        {
                case DB_BIND_STATIC:
 #if defined(_WIN32) || defined(UNICODE_UCS2)
-                       sqlBuffer = buffer;
+         if (cType == DB_CTYPE_UTF8_STRING)
+         {
+            sqlBuffer = WideStringFromUTF8String((char *)buffer);
+            statement->buffers->add(sqlBuffer);
+            length = (int)strlen(char *)sqlBuffer) + 1;
+         }
+         else
+         {
+            sqlBuffer = buffer;
+         }
 #else
                        if (cType == DB_CTYPE_STRING)
                        {
                                sqlBuffer = UCS2StringFromUCS4String((WCHAR *)buffer);
                                statement->buffers->add(sqlBuffer);
                        }
+                       else if (cType == DB_CTYPE_UTF8_STRING)
+         {
+            sqlBuffer = UCS2StringFromUTF8String((char *)buffer);
+            statement->buffers->add(sqlBuffer);
+            length = (int)strlen(char *)sqlBuffer) + 1;
+         }
                        else
                        {
                                sqlBuffer = buffer;
@@ -386,13 +401,28 @@ extern "C" void EXPORT DrvBind(DB2DRV_STATEMENT *statement, int pos, int sqlType
                        break;
                case DB_BIND_DYNAMIC:
 #if defined(_WIN32) || defined(UNICODE_UCS2)
-                       sqlBuffer = buffer;
+         if (cType == DB_CTYPE_UTF8_STRING)
+         {
+            sqlBuffer = WideStringFromUTF8String((char *)buffer);
+            free(buffer);
+            length = (int)strlen(char *)sqlBuffer) + 1;
+         }
+         else
+         {
+            sqlBuffer = buffer;
+         }
 #else
                        if (cType == DB_CTYPE_STRING)
                        {
                                sqlBuffer = UCS2StringFromUCS4String((WCHAR *)buffer);
                                free(buffer);
                        }
+                       else if (cType == DB_CTYPE_UTF8_STRING)
+         {
+            sqlBuffer = UCS2StringFromUTF8String((char *)buffer);
+            free(buffer);
+            length = (int)strlen(char *)sqlBuffer) + 1;
+         }
                        else
                        {
                                sqlBuffer = buffer;
@@ -402,12 +432,25 @@ extern "C" void EXPORT DrvBind(DB2DRV_STATEMENT *statement, int pos, int sqlType
                        break;
                case DB_BIND_TRANSIENT:
 #if defined(_WIN32) || defined(UNICODE_UCS2)
-                       sqlBuffer = nx_memdup(buffer, (cType == DB_CTYPE_STRING) ? (DWORD)(length * sizeof(WCHAR)) : bufferSize[cType]);
+         if (cType == DB_CTYPE_UTF8_STRING)
+         {
+            sqlBuffer = WideStringFromUTF8String((char *)buffer);
+            length = (int)strlen(char *)sqlBuffer) + 1;
+         }
+         else
+         {
+            sqlBuffer = nx_memdup(buffer, (cType == DB_CTYPE_STRING) ? (DWORD)(length * sizeof(WCHAR)) : bufferSize[cType]);
+         }
 #else
                        if (cType == DB_CTYPE_STRING)
                        {
                                sqlBuffer = UCS2StringFromUCS4String((WCHAR *)buffer);
                        }
+                       else if (cType == DB_CTYPE_UTF8_STRING)
+         {
+            sqlBuffer = UCS2StringFromUTF8String((char *)buffer);
+            length = (int)strlen(char *)sqlBuffer) + 1;
+         }
                        else
                        {
                                sqlBuffer = nx_memdup(buffer, bufferSize[cType]);
@@ -419,7 +462,7 @@ extern "C" void EXPORT DrvBind(DB2DRV_STATEMENT *statement, int pos, int sqlType
                        return; // Invalid call
        }
        SQLBindParameter(statement->handle, pos, SQL_PARAM_INPUT, odbcCType[cType], odbcSqlType[sqlType],
-                        (cType == DB_CTYPE_STRING) ? length : 0, 0, sqlBuffer, 0, NULL);
+                        ((cType == DB_CTYPE_STRING) || (cType == DB_CTYPE_UTF8_STRING)) ? length : 0, 0, sqlBuffer, 0, NULL);
 }
 
 
index 2201f95..66f29d7 100644 (file)
@@ -308,45 +308,67 @@ extern "C" DBDRV_STATEMENT EXPORT DrvPrepare(INFORMIX_CONN *pConn, WCHAR *pwszQu
        return result;
 }
 
-
-//
-// Bind parameter to statement
-//
-
+/**
+ * Bind parameter to statement
+ */
 extern "C" void EXPORT DrvBind(INFORMIX_STATEMENT *statement, int pos, int sqlType, int cType, void *buffer, int allocType)
 {
        static SQLSMALLINT odbcSqlType[] = { SQL_VARCHAR, SQL_INTEGER, SQL_BIGINT, SQL_DOUBLE, SQL_LONGVARCHAR };
-       static SQLSMALLINT odbcCType[] = { SQL_C_WCHAR, SQL_C_SLONG, SQL_C_ULONG, SQL_C_SBIGINT, SQL_C_UBIGINT, SQL_C_DOUBLE };
-       static DWORD bufferSize[] = { 0, sizeof(LONG), sizeof(DWORD), sizeof(INT64), sizeof(QWORD), sizeof(double) };
+       static SQLSMALLINT odbcCType[] = { SQL_C_WCHAR, SQL_C_SLONG, SQL_C_ULONG, SQL_C_SBIGINT, SQL_C_UBIGINT, SQL_C_DOUBLE, SQL_C_WCHAR };
+       static DWORD bufferSize[] = { 0, sizeof(LONG), sizeof(DWORD), sizeof(INT64), sizeof(QWORD), sizeof(double), 0 };
 
-       int length = (int)wcslen((WCHAR *)buffer) + 1;
+       int length = (cType == DB_CTYPE_STRING) ? (int)wcslen((WCHAR *)buffer) + 1 : 0;
 
        SQLPOINTER sqlBuffer;
        switch(allocType)
        {
                case DB_BIND_STATIC:
-                       sqlBuffer = buffer;
+         if (cType == DB_CTYPE_UTF8_STRING)
+         {
+            sqlBuffer = WideStringFromUTF8String((char *)buffer);
+            statement->buffers->add(sqlBuffer);
+            length = strlen((char *)sqlBuffer) + 1;
+         }
+         else
+         {
+            sqlBuffer = buffer;
+         }
                        break;
                case DB_BIND_DYNAMIC:
-                       sqlBuffer = buffer;
+         if (cType == DB_CTYPE_UTF8_STRING)
+         {
+            sqlBuffer = WideStringFromUTF8String((char *)buffer);
+            free(buffer);
+            length = strlen((char *)sqlBuffer) + 1;
+         }
+         else
+         {
+            sqlBuffer = buffer;
+         }
                        statement->buffers->add(sqlBuffer);
                        break;
                case DB_BIND_TRANSIENT:
-                       sqlBuffer = nx_memdup(buffer, (cType == DB_CTYPE_STRING) ? (DWORD)(length * sizeof(WCHAR)) : bufferSize[cType]);
+         if (cType == DB_CTYPE_UTF8_STRING)
+         {
+            sqlBuffer = WideStringFromUTF8String((char *)buffer);
+            length = strlen((char *)sqlBuffer) + 1;
+         }
+         else
+         {
+            sqlBuffer = nx_memdup(buffer, (cType == DB_CTYPE_STRING) ? (DWORD)(length * sizeof(WCHAR)) : bufferSize[cType]);
+         }
                        statement->buffers->add(sqlBuffer);
                        break;
                default:
                        return; // Invalid call
        }
        SQLBindParameter(statement->handle, pos, SQL_PARAM_INPUT, odbcCType[cType], odbcSqlType[sqlType],
-                        (cType == DB_CTYPE_STRING) ? length : 0, 0, sqlBuffer, 0, NULL);
+                        ((cType == DB_CTYPE_STRING) || (cType == DB_CTYPE_UTF8_STRING)) ? length : 0, 0, sqlBuffer, 0, NULL);
 }
 
-
-//
-// Execute prepared statement
-//
-
+/**
+ * Execute prepared statement
+ */
 extern "C" DWORD EXPORT DrvExecute(INFORMIX_CONN *pConn, INFORMIX_STATEMENT *statement, WCHAR *errorText)
 {
        DWORD dwResult;
index 9bd19bf..aa214ae 100644 (file)
@@ -323,7 +323,7 @@ extern "C" DBDRV_STATEMENT EXPORT DrvPrepare(MYSQL_CONN *pConn, WCHAR *pwszQuery
  */
 extern "C" void EXPORT DrvBind(MYSQL_STATEMENT *hStmt, int pos, int sqlType, int cType, void *buffer, int allocType)
 {
-       static size_t bufferSize[] = { 0, sizeof(INT32), sizeof(UINT32), sizeof(INT64), sizeof(UINT64), sizeof(double) };
+       static size_t bufferSize[] = { 0, sizeof(INT32), sizeof(UINT32), sizeof(INT64), sizeof(UINT64), sizeof(double), 0 };
 
        if ((pos < 1) || (pos > hStmt->paramCount))
                return;
@@ -340,6 +340,15 @@ extern "C" void EXPORT DrvBind(MYSQL_STATEMENT *hStmt, int pos, int sqlType, int
                b->length = &hStmt->lengthFields[pos - 1];
                b->buffer_type = MYSQL_TYPE_STRING;
        }
+       else if (cType == DB_CTYPE_UTF8_STRING)
+   {
+      b->buffer = (allocType == DB_BIND_DYNAMIC) ? buffer : strdup((char *)buffer);
+      hStmt->buffers->add(b->buffer);
+      b->buffer_length = (unsigned long)strlen((char *)b->buffer) + 1;
+      hStmt->lengthFields[pos - 1] = b->buffer_length - 1;
+      b->length = &hStmt->lengthFields[pos - 1];
+      b->buffer_type = MYSQL_TYPE_STRING;
+   }
        else
        {
                switch(allocType)
index 8327824..2a97b8e 100644 (file)
@@ -338,11 +338,11 @@ extern "C" DBDRV_STATEMENT EXPORT DrvPrepare(ODBCDRV_CONN *pConn, NETXMS_WCHAR *
 extern "C" void EXPORT DrvBind(ODBCDRV_STATEMENT *stmt, int pos, int sqlType, int cType, void *buffer, int allocType)
 {
        static SQLSMALLINT odbcSqlType[] = { SQL_VARCHAR, SQL_INTEGER, SQL_BIGINT, SQL_DOUBLE, SQL_LONGVARCHAR };
-       static SQLSMALLINT odbcCTypeW[] = { SQL_C_WCHAR, SQL_C_SLONG, SQL_C_ULONG, SQL_C_SBIGINT, SQL_C_UBIGINT, SQL_C_DOUBLE };
-       static SQLSMALLINT odbcCTypeA[] = { SQL_C_CHAR, SQL_C_SLONG, SQL_C_ULONG, SQL_C_SBIGINT, SQL_C_UBIGINT, SQL_C_DOUBLE };
-       static DWORD bufferSize[] = { 0, sizeof(LONG), sizeof(DWORD), sizeof(INT64), sizeof(QWORD), sizeof(double) };
+       static SQLSMALLINT odbcCTypeW[] = { SQL_C_WCHAR, SQL_C_SLONG, SQL_C_ULONG, SQL_C_SBIGINT, SQL_C_UBIGINT, SQL_C_DOUBLE, SQL_C_WCHAR };
+       static SQLSMALLINT odbcCTypeA[] = { SQL_C_CHAR, SQL_C_SLONG, SQL_C_ULONG, SQL_C_SBIGINT, SQL_C_UBIGINT, SQL_C_DOUBLE, SQL_C_CHAR };
+       static DWORD bufferSize[] = { 0, sizeof(LONG), sizeof(DWORD), sizeof(INT64), sizeof(QWORD), sizeof(double), 0 };
 
-       int length = (int)wcslen((NETXMS_WCHAR *)buffer) + 1;
+       int length = (cType == DB_CTYPE_STRING) ? (int)wcslen((NETXMS_WCHAR *)buffer) + 1 : 0;
 
        SQLPOINTER sqlBuffer;
        switch(allocType)
@@ -351,13 +351,28 @@ extern "C" void EXPORT DrvBind(ODBCDRV_STATEMENT *stmt, int pos, int sqlType, in
                        if (m_useUnicode)
                        {
 #if defined(_WIN32) || defined(UNICODE_UCS2)
-                               sqlBuffer = buffer;
+            if (cType == DB_CTYPE_UTF8_STRING)
+            {
+               sqlBuffer = WideStringFromUTF8String((char *)buffer);
+               stmt->buffers->add(sqlBuffer);
+               length = (int)strlen((char *)sqlBuffer) + 1;
+            }
+            else
+            {
+               sqlBuffer = buffer;
+            }
 #else
                                if (cType == DB_CTYPE_STRING)
                                {
                                        sqlBuffer = UCS2StringFromUCS4String((NETXMS_WCHAR *)buffer);
                                        stmt->buffers->add(sqlBuffer);
                                }
+                               else if (cType == DB_CTYPE_UTF8_STRING)
+            {
+               sqlBuffer = UCS2StringFromUTF8String((char *)buffer);
+               stmt->buffers->add(sqlBuffer);
+               length = (int)strlen((char *)sqlBuffer) + 1;
+            }
                                else
                                {
                                        sqlBuffer = buffer;
@@ -371,6 +386,12 @@ extern "C" void EXPORT DrvBind(ODBCDRV_STATEMENT *stmt, int pos, int sqlType, in
                                        sqlBuffer = MBStringFromWideString((NETXMS_WCHAR *)buffer);
                                        stmt->buffers->add(sqlBuffer);
                                }
+                               else if (cType == DB_CTYPE_UTF8_STRING)
+            {
+               sqlBuffer = MBStringFromUTF8String((char *)buffer);
+               stmt->buffers->add(sqlBuffer);
+               length = (int)strlen((char *)sqlBuffer) + 1;
+            }
                                else
                                {
                                        sqlBuffer = buffer;
@@ -381,13 +402,28 @@ extern "C" void EXPORT DrvBind(ODBCDRV_STATEMENT *stmt, int pos, int sqlType, in
                        if (m_useUnicode)
                        {
 #if defined(_WIN32) || defined(UNICODE_UCS2)
-                               sqlBuffer = buffer;
+            if (cType == DB_CTYPE_UTF8_STRING)
+            {
+               sqlBuffer = WideStringFromUTF8String((char *)buffer);
+               free(buffer);
+               length = (int)strlen((char *)sqlBuffer) + 1;
+            }
+            else
+            {
+               sqlBuffer = buffer;
+            }
 #else
                                if (cType == DB_CTYPE_STRING)
                                {
                                        sqlBuffer = UCS2StringFromUCS4String((NETXMS_WCHAR *)buffer);
                                        free(buffer);
                                }
+            else if (cType == DB_CTYPE_UTF8_STRING)
+            {
+               sqlBuffer = UCS2StringFromUTF8String((char *)buffer);
+               free(buffer);
+               length = (int)strlen((char *)sqlBuffer) + 1;
+            }
                                else
                                {
                                        sqlBuffer = buffer;
@@ -401,6 +437,12 @@ extern "C" void EXPORT DrvBind(ODBCDRV_STATEMENT *stmt, int pos, int sqlType, in
                                        sqlBuffer = MBStringFromWideString((NETXMS_WCHAR *)buffer);
                                        free(buffer);
                                }
+            else if (cType == DB_CTYPE_UTF8_STRING)
+            {
+               sqlBuffer = MBStringFromUTF8String((char *)buffer);
+               free(buffer);
+               length = (int)strlen((char *)sqlBuffer) + 1;
+            }
                                else
                                {
                                        sqlBuffer = buffer;
@@ -412,12 +454,25 @@ extern "C" void EXPORT DrvBind(ODBCDRV_STATEMENT *stmt, int pos, int sqlType, in
                        if (m_useUnicode)
                        {
 #if defined(_WIN32) || defined(UNICODE_UCS2)
-                               sqlBuffer = nx_memdup(buffer, (cType == DB_CTYPE_STRING) ? (DWORD)(length * sizeof(WCHAR)) : bufferSize[cType]);
+            if (cType == DB_CTYPE_UTF8_STRING)
+            {
+               sqlBuffer = WideStringFromUTF8String((char *)buffer);
+               length = (int)strlen((char *)sqlBuffer) + 1;
+            }
+            else
+            {
+               sqlBuffer = nx_memdup(buffer, (cType == DB_CTYPE_STRING) ? (DWORD)(length * sizeof(WCHAR)) : bufferSize[cType]);
+            }
 #else
                                if (cType == DB_CTYPE_STRING)
                                {
                                        sqlBuffer = UCS2StringFromUCS4String((NETXMS_WCHAR *)buffer);
                                }
+            if (cType == DB_CTYPE_UTF8_STRING)
+            {
+               sqlBuffer = UCS2StringFromUTF8String((char *)buffer);
+               length = (int)strlen((char *)sqlBuffer) + 1;
+            }
                                else
                                {
                                        sqlBuffer = nx_memdup(buffer, bufferSize[cType]);
@@ -430,6 +485,11 @@ extern "C" void EXPORT DrvBind(ODBCDRV_STATEMENT *stmt, int pos, int sqlType, in
                                {
                                        sqlBuffer = MBStringFromWideString((NETXMS_WCHAR *)buffer);
                                }
+                               else if (cType == DB_CTYPE_UTF8_STRING)
+            {
+               sqlBuffer = MBStringFromUTF8String((char *)buffer);
+               length = (int)strlen((char *)sqlBuffer) + 1;
+            }
                                else
                                {
                                        sqlBuffer = nx_memdup(buffer, bufferSize[cType]);
@@ -441,7 +501,7 @@ extern "C" void EXPORT DrvBind(ODBCDRV_STATEMENT *stmt, int pos, int sqlType, in
                        return; // Invalid call
        }
        SQLBindParameter(stmt->handle, pos, SQL_PARAM_INPUT, m_useUnicode ? odbcCTypeW[cType] : odbcCTypeA[cType], odbcSqlType[sqlType],
-                        (cType == DB_CTYPE_STRING) ? length : 0, 0, sqlBuffer, 0, NULL);
+                        ((cType == DB_CTYPE_STRING) || (cType == DB_CTYPE_UTF8_STRING)) ? length : 0, 0, sqlBuffer, 0, NULL);
 }
 
 /**
index 73d2f88..c80287a 100644 (file)
@@ -491,6 +491,20 @@ static void BindNormal(ORACLE_STATEMENT *stmt, int pos, int sqlType, int cType,
                                                    (sqlType == DB_SQLTYPE_TEXT) ? SQLT_LNG : SQLT_STR,
                                                    NULL, NULL, NULL, 0, NULL, OCI_DEFAULT);
                        break;
+      case DB_CTYPE_UTF8_STRING:
+#if UNICODE_UCS4
+         sqlBuffer = UCS2StringFromUTF8String((char *)buffer);
+#else
+         sqlBuffer = WideStringFromUTF8String((char *)buffer);
+#endif
+         stmt->buffers->set(pos - 1, sqlBuffer);
+         if (allocType == DB_BIND_DYNAMIC)
+            free(buffer);
+         OCIBindByPos(stmt->handleStmt, &handleBind, stmt->handleError, pos, sqlBuffer,
+                      ((sb4)ucs2_strlen((UCS2CHAR *)sqlBuffer) + 1) * sizeof(UCS2CHAR),
+                      (sqlType == DB_SQLTYPE_TEXT) ? SQLT_LNG : SQLT_STR,
+                      NULL, NULL, NULL, 0, NULL, OCI_DEFAULT);
+         break;
                case DB_CTYPE_INT64:    // OCI prior to 11.2 cannot bind 64 bit integers
                   sqlBuffer = malloc(sizeof(OCINumber));
          stmt->buffers->set(pos - 1, sqlBuffer);
@@ -692,6 +706,16 @@ static void BindBatch(ORACLE_STATEMENT *stmt, int pos, int sqlType, int cType, v
 #endif
          bind->set(sqlBuffer);
                        break;
+      case DB_CTYPE_UTF8_STRING:
+#if UNICODE_UCS4
+         sqlBuffer = UCS2StringFromUTF8String((char *)buffer);
+#else
+         sqlBuffer = WideStringFromUTF8String((char *)buffer);
+#endif
+         if (allocType == DB_BIND_DYNAMIC)
+            free(buffer);
+         bind->set(sqlBuffer);
+         break;
                case DB_CTYPE_INT64:    // OCI prior to 11.2 cannot bind 64 bit integers
 #ifdef UNICODE_UCS2
                        sqlBuffer = malloc(64 * sizeof(WCHAR));
index 2fa1c71..5aec07a 100644 (file)
@@ -402,13 +402,24 @@ extern "C" void EXPORT DrvBind(PG_STATEMENT *hStmt, int pos, int sqlType, int cT
        if (hStmt->pcount < pos)
                hStmt->pcount = pos;
 
-       safe_free(hStmt->buffers[pos - 1]);
+       free(hStmt->buffers[pos - 1]);
 
        switch(cType)
        {
                case DB_CTYPE_STRING:
                        hStmt->buffers[pos - 1] = UTF8StringFromWideString((WCHAR *)buffer);
                        break;
+      case DB_CTYPE_UTF8_STRING:
+         if (allocType == DB_BIND_DYNAMIC)
+         {
+            hStmt->buffers[pos - 1] = (char *)buffer;
+            buffer = NULL; // prevent deallocation
+         }
+         else
+         {
+            hStmt->buffers[pos - 1] = strdup((char *)buffer);
+         }
+         break;
                case DB_CTYPE_INT32:
                        hStmt->buffers[pos - 1] = (char *)malloc(16);
                        sprintf(hStmt->buffers[pos - 1], "%d", *((int *)buffer));
index 2ae3fe8..bb34031 100644 (file)
@@ -225,6 +225,10 @@ extern "C" void EXPORT DrvBind(sqlite3_stmt *stmt, int pos, int sqlType, int cTy
                        }
 #endif
                        break;
+      case DB_CTYPE_UTF8_STRING:
+         sqlite3_bind_text(stmt, pos, (char *)buffer, strlen((char *)buffer),
+            (allocType == DB_BIND_STATIC) ? SQLITE_STATIC : ((allocType == DB_BIND_DYNAMIC) ? free : SQLITE_TRANSIENT));
+         break;
                case DB_CTYPE_INT32:
                case DB_CTYPE_UINT32:
                        sqlite3_bind_int(stmt, pos, *((int *)buffer));
index 40d8762..7e4b7c9 100644 (file)
@@ -1191,6 +1191,10 @@ void LIBNXDB_EXPORTABLE DBBind(DB_STATEMENT hStmt, int pos, int sqlType, int cTy
                {
                        nxlog_debug(9, _T("{%p} bind at pos %d: \"%s\""), hStmt, pos, buffer);
                }
+               else if (cType == DB_CTYPE_UTF8_STRING)
+      {
+         nxlog_debug(9, _T("{%p} bind at pos %d (UTF-8): \"%hs\""), hStmt, pos, buffer);
+      }
                else
                {
                        TCHAR text[64];
index c790957..12814b9 100644 (file)
@@ -790,6 +790,99 @@ size_t LIBNETXMS_EXPORTABLE ucs2_to_utf8(const UCS2CHAR *src, int srcLen, char *
 #endif
 }
 
+/**
+ * Convert UTF-8 to UCS-2 using stub (no actual conversion for character codes above 0x007F)
+ */
+static size_t utf8_to_ucs2_simple_copy(const char *src, int srcLen, UCS2CHAR *dst, int dstLen)
+{
+   const char *psrc;
+   UCS2CHAR *pdst;
+   int pos, size;
+
+   size = (srcLen == -1) ? strlen(src) : srcLen;
+   if (size >= dstLen)
+      size = dstLen - 1;
+   for(psrc = src, pos = 0, pdst = dst; pos < size; pos++, psrc++, pdst++)
+      *pdst = (*psrc < 128) ? (char) (*psrc) : '?';
+   *pdst = 0;
+   return size;
+}
+
+#ifndef __DISABLE_ICONV
+
+/**
+ * Convert UCS-2 to UTF-8 using iconv
+ */
+static size_t utf8_to_ucs2_iconv(const char *src, int srcLen, UCS2CHAR *dst, int dstLen)
+{
+   iconv_t cd;
+   const char *inbuf;
+   char *outbuf;
+   size_t count, inbytes, outbytes;
+
+   cd = IconvOpen(UCS2_CODEPAGE_NAME, "UTF-8");
+   if (cd == (iconv_t) (-1))
+   {
+      return utf8_to_ucs2_simple_copy(src, srcLen, dst, dstLen);
+   }
+
+   inbuf = (const char *)src;
+   inbytes = (srcLen == -1) ? strlen(src) + 1 : (size_t) srcLen;
+   outbuf = (char *)dst;
+   outbytes = (size_t)dstLen * sizeof(UCS2CHAR);
+   count = iconv(cd, (ICONV_CONST char **) &inbuf, &inbytes, &outbuf, &outbytes);
+   IconvClose(cd);
+
+   if (count == (size_t) - 1)
+   {
+      if (errno == EILSEQ)
+      {
+         count = (dstLen * sizeof(UCS2CHAR) - outbytes) / sizeof(UCS2CHAR);
+      }
+      else
+      {
+         count = 0;
+      }
+   }
+   else
+   {
+      count = (dstLen - outbytes) / sizeof(UCS2CHAR);
+   }
+   if ((srcLen == -1) && (outbytes >= sizeof(UCS2CHAR)))
+   {
+      *((UCS2CHAR *)outbuf) = 0;
+   }
+
+   return count;
+}
+
+#endif
+
+/**
+ * Convert UTF-8 to UCS-2
+ */
+size_t LIBNETXMS_EXPORTABLE utf8_to_ucs2(const char *src, int srcLen, UCS2CHAR *dst, int dstLen)
+{
+#if HAVE_ICONV && !defined(__DISABLE_ICONV)
+   return utf8_to_ucs2_iconv(src, srcLen, dst, dstLen);
+#else
+   return utf8_to_ucs2_simple_copy(src, srcLen, dst, dstLen);
+#endif
+}
+
+/**
+ * Convert UTF-8 to UCS-2 (dynamically allocated output string)
+ */
+UCS2CHAR LIBNETXMS_EXPORTABLE *UCS2StringFromUTF8String(const char *utf8String)
+{
+   if (utf8String == NULL)
+      return NULL;
+   int nLen = (int)strlen(utf8String) + 1;
+   UCS2CHAR *out = (UCS2CHAR *)malloc(nLen * sizeof(UCS2CHAR));
+   utf8_to_ucs2(utf8String, -1, out, nLen);
+   return out;
+}
+
 #endif /* UNICODE_UCS4 */
 
 #ifdef _WIN32