fixed crash in DBFreeStatement after session reconnect
authorVictor Kirhenshtein <victor@netxms.org>
Sun, 20 Oct 2013 13:04:43 +0000 (13:04 +0000)
committerVictor Kirhenshtein <victor@netxms.org>
Sun, 20 Oct 2013 13:04:43 +0000 (13:04 +0000)
12 files changed:
.gitignore
include/nms_util.h
src/db/dbdrv/mysql/mysql.cpp
src/db/dbdrv/oracle/oracle.cpp
src/db/dbdrv/sqlite/sqlite.cpp
src/db/libnxdb/libnxdb.h
src/db/libnxdb/session.cpp
src/install/windows/netxms-minimal.iss
src/install/windows/setup.iss
src/java/build/pack.cmd
src/java/netxms-eclipse/core/plugin.xml
src/libnetxms/array.cpp

index f032450..37cc997 100644 (file)
@@ -451,6 +451,7 @@ src/zlib/Makefile.in
 tools/Makefile
 tools/Makefile.in
 webui/eclipse
+webui/webapp/Core/jar/certificate-manager-*.jar
 webui/webapp/Core/jar/netxms-base-*.jar
 webui/webapp/Core/jar/netxms-client-*.jar
 webui/webapp/Core/jar/netxms-client-api-*.jar
index b5c29c5..fd89369 100644 (file)
@@ -407,10 +407,13 @@ public:
 
        int add(void *object);
        void *get(int index) { return ((index >= 0) && (index < m_size)) ? m_data[index] : NULL; }
+   int indexOf(void *object);
        void set(int index, void *object);
        void replace(int index, void *object);
        void remove(int index) { internalRemove(index, true); }
+   void remove(void *object) { internalRemove(indexOf(object), true); }
        void unlink(int index) { internalRemove(index, false); }
+       void unlink(void *object) { internalRemove(indexOf(object), false); }
        void clear();
 
        int size() { return m_size; }
@@ -433,8 +436,13 @@ public:
 
        int add(T *object) { return Array::add((void *)object); }
        T *get(int index) { return (T*)Array::get(index); }
+   int indexOf(T *object) { return Array::indexOf((void *)object); }
        void set(int index, T *object) { Array::set(index, (void *)object); }
        void replace(int index, T *object) { Array::replace(index, (void *)object); }
+       void remove(int index) { Array::remove(index); }
+   void remove(T *object) { Array::remove((void *)object); }
+       void unlink(int index) { Array::unlink(index); }
+   void unlink(T *object) { Array::unlink((void *)object); }
 };
 
 /**
index a55f24a..c92743e 100644 (file)
@@ -639,11 +639,9 @@ extern "C" LONG EXPORT DrvGetFieldLength(MYSQL_RESULT *hResult, int iRow, int iC
        }
 }
 
-
-//
-// Get field value from result
-//
-
+/**
+ * Get field value from result
+ */
 extern "C" WCHAR EXPORT *DrvGetField(MYSQL_RESULT *hResult, int iRow, int iColumn, WCHAR *pBuffer, int nBufSize)
 {
        WCHAR *pRet = NULL;
index b65c3a9..f676a0e 100644 (file)
@@ -1,6 +1,6 @@
 /* 
 ** Oracle Database Driver
-** Copyright (C) 2007-2012 Victor Kirhenshtein
+** Copyright (C) 2007-2013 Victor Kirhenshtein
 **
 ** This program is free software; you can redistribute it and/or modify
 ** it under the terms of the GNU General Public License as published by
@@ -60,6 +60,9 @@ extern "C" WCHAR EXPORT *DrvPrepareStringW(const WCHAR *str)
        return out;
 }
 
+/**
+ * Prepare string for using in SQL query - enclose in quotes and escape as needed
+ */
 extern "C" char EXPORT *DrvPrepareStringA(const char *str)
 {
        int len = (int)strlen(str) + 3;   // + two quotes and \0 at the end
@@ -258,11 +261,9 @@ extern "C" DBDRV_CONNECTION EXPORT DrvConnect(const char *host, const char *logi
    return (DBDRV_CONNECTION)pConn;
 }
 
-
-//
-// Disconnect from database
-//
-
+/**
+ * Disconnect from database
+ */
 extern "C" void EXPORT DrvDisconnect(ORACLE_CONN *pConn)
 {
        if (pConn != NULL)
@@ -275,11 +276,9 @@ extern "C" void EXPORT DrvDisconnect(ORACLE_CONN *pConn)
        }
 }
 
-
-//
-// Convert query from NetXMS portable format to native Oracle format
-//
-
+/**
+ * Convert query from NetXMS portable format to native Oracle format
+ */
 static UCS2CHAR *ConvertQuery(WCHAR *query)
 {
 #if UNICODE_UCS4
index 53601ad..45302ea 100644 (file)
@@ -247,11 +247,9 @@ extern "C" void EXPORT DrvBind(sqlite3_stmt *stmt, int pos, int sqlType, int cTy
        }
 }
 
-
-//
-// Execute prepared statement
-//
-
+/**
+ * Execute prepared statement
+ */
 extern "C" DWORD EXPORT DrvExecute(SQLITE_CONN *hConn, sqlite3_stmt *stmt, WCHAR *errorText)
 {
        DWORD result;
@@ -279,21 +277,18 @@ extern "C" DWORD EXPORT DrvExecute(SQLITE_CONN *hConn, sqlite3_stmt *stmt, WCHAR
        return result;
 }
 
-
-//
-// Destroy prepared statement
-//
-
+/**
+ * Destroy prepared statement
+ */
 extern "C" void EXPORT DrvFreeStatement(sqlite3_stmt *stmt)
 {
-       sqlite3_finalize(stmt);
+   if (stmt != NULL)
+          sqlite3_finalize(stmt);
 }
 
-
-//
-// Internal query
-//
-
+/**
+ * Internal query
+ */
 static DWORD DrvQueryInternal(SQLITE_CONN *pConn, const char *pszQuery, WCHAR *errorText)
 {
    DWORD result;
index 19151e8..df8bc00 100644 (file)
 #include <nms_threads.h>\r
 #include <nxdbapi.h>\r
 \r
-\r
-//\r
-// Constants\r
-//\r
-\r
+/**\r
+ * Max number of loaded database drivers\r
+ */\r
 #define MAX_DB_DRIVERS                 16\r
 \r
-\r
-//\r
-// Database driver structure\r
-//\r
-\r
+/**\r
+ * Database driver structure\r
+ */\r
 struct db_driver_t\r
 {\r
        const char *m_name;\r
@@ -81,11 +77,20 @@ struct db_driver_t
        char* (* m_fpDrvPrepareStringA)(const char *);\r
 };\r
 \r
+/**\r
+ * Prepared statement\r
+ */\r
+struct db_statement_t\r
+{\r
+       DB_DRIVER m_driver;\r
+       DB_HANDLE m_connection;\r
+       DBDRV_STATEMENT m_statement;\r
+       TCHAR *m_query;\r
+};\r
 \r
-//\r
-// database connection structure\r
-//\r
-\r
+/**\r
+ * Database connection structure\r
+ */\r
 struct db_handle_t\r
 {\r
    DBDRV_CONNECTION m_connection;\r
@@ -99,26 +104,12 @@ struct db_handle_t
    char *m_password;\r
    char *m_dbName;\r
    char *m_schema;\r
+   ObjectArray<db_statement_t> *m_preparedStatements;\r
 };\r
 \r
-\r
-//\r
-// prepared statement\r
-//\r
-\r
-struct db_statement_t\r
-{\r
-       DB_DRIVER m_driver;\r
-       DB_HANDLE m_connection;\r
-       DBDRV_STATEMENT m_statement;\r
-       TCHAR *m_query;\r
-};\r
-\r
-\r
-//\r
-// SELECT query result\r
-//\r
-\r
+/**\r
+ * SELECT query result\r
+ */\r
 struct db_result_t\r
 {\r
        DB_DRIVER m_driver;\r
@@ -126,11 +117,9 @@ struct db_result_t
        DBDRV_RESULT m_data;\r
 };\r
 \r
-\r
-//\r
-// Async SELECT query result\r
-//\r
-\r
+/**\r
+ * Async SELECT query result\r
+ */\r
 struct db_async_result_t\r
 {\r
        DB_DRIVER m_driver;\r
index ae0a361..86a2932 100644 (file)
 
 #include "libnxdb.h"
 
+/**
+ * Check if statement handle is valid
+ */
+#define IS_VALID_STATEMENT_HANDLE(s) ((s != NULL) && (s->m_connection != NULL))
+
+/**
+ * Invalidate all prepared statements on connection
+ */
+static void InvalidatePreparedStatements(DB_HANDLE hConn)
+{
+   for(int i = 0; i < hConn->m_preparedStatements->size(); i++)
+   {
+      db_statement_t *stmt = hConn->m_preparedStatements->get(i);
+      hConn->m_driver->m_fpDrvFreeStatement(stmt->m_statement);
+      stmt->m_statement = NULL;
+      stmt->m_connection = NULL;
+   }
+}
+
 /**
  * Connect to database
  */
@@ -58,6 +77,7 @@ DB_HANDLE LIBNXDB_EXPORTABLE DBConnect(DB_DRIVER driver, const TCHAR *server, co
                        hConn->m_connection = hDrvConn;
          hConn->m_mutexTransLock = MutexCreateRecursive();
          hConn->m_transactionLevel = 0;
+         hConn->m_preparedStatements = new ObjectArray<db_statement_t>(4, 4, false);
 #ifdef UNICODE
          hConn->m_dbName = mbDatabase;
          hConn->m_login = mbLogin;
@@ -101,6 +121,8 @@ void LIBNXDB_EXPORTABLE DBDisconnect(DB_HANDLE hConn)
 
    __DBDbgPrintf(4, _T("DB connection %p closed"), hConn);
    
+   InvalidatePreparedStatements(hConn);
+
        hConn->m_driver->m_fpDrvDisconnect(hConn->m_connection);
    MutexDestroy(hConn->m_mutexTransLock);
    safe_free(hConn->m_dbName);
@@ -108,6 +130,7 @@ void LIBNXDB_EXPORTABLE DBDisconnect(DB_HANDLE hConn)
    safe_free(hConn->m_password);
    safe_free(hConn->m_server);
    safe_free(hConn->m_schema);
+   delete hConn->m_preparedStatements;
    free(hConn);
 }
 
@@ -132,6 +155,7 @@ static void DBReconnect(DB_HANDLE hConn)
 
    __DBDbgPrintf(4, _T("DB reconnect: handle=%p"), hConn);
 
+   InvalidatePreparedStatements(hConn);
        hConn->m_driver->m_fpDrvDisconnect(hConn->m_connection);
    for(nCount = 0; ; nCount++)
    {
@@ -293,21 +317,17 @@ DB_RESULT LIBNXDB_EXPORTABLE DBSelect(DB_HANDLE hConn, const TCHAR *query)
        return DBSelectEx(hConn, query, errorText);
 }
 
-
-//
-// Get number of columns
-//
-
+/**
+ * Get number of columns
+ */
 int LIBNXDB_EXPORTABLE DBGetColumnCount(DB_RESULT hResult)
 {
        return hResult->m_driver->m_fpDrvGetColumnCount(hResult->m_data);
 }
 
-
-//
-// Get column name
-//
-
+/**
+ * Get column name
+ */
 BOOL LIBNXDB_EXPORTABLE DBGetColumnName(DB_RESULT hResult, int column, TCHAR *buffer, int bufSize)
 {
        const char *name;
@@ -325,21 +345,17 @@ BOOL LIBNXDB_EXPORTABLE DBGetColumnName(DB_RESULT hResult, int column, TCHAR *bu
        return name != NULL;
 }
 
-
-//
-// Get column count for async request
-//
-
+/**
+ * Get column count for async request
+ */
 int LIBNXDB_EXPORTABLE DBGetColumnCountAsync(DB_ASYNC_RESULT hResult)
 {
        return hResult->m_driver->m_fpDrvGetColumnCountAsync(hResult->m_data);
 }
 
-
-//
-// Get column name for async request
-//
-
+/**
+ * Get column name for async request
+ */
 BOOL LIBNXDB_EXPORTABLE DBGetColumnNameAsync(DB_ASYNC_RESULT hResult, int column, TCHAR *buffer, int bufSize)
 {
        const char *name;
@@ -913,11 +929,9 @@ UINT32 LIBNXDB_EXPORTABLE DBGetFieldAsyncIPAddr(DB_ASYNC_RESULT hResult, int iCo
    return (DBGetFieldAsync(hResult, iColumn, szBuffer, 64) == NULL) ? INADDR_NONE : ntohl(_t_inet_addr(szBuffer));
 }
 
-
-//
-// Free asynchronous SELECT result
-//
-
+/**
+ * Free asynchronous SELECT result
+ */
 void LIBNXDB_EXPORTABLE DBFreeAsyncResult(DB_ASYNC_RESULT hResult)
 {
        hResult->m_driver->m_fpDrvFreeAsyncResult(hResult->m_data);
@@ -925,11 +939,9 @@ void LIBNXDB_EXPORTABLE DBFreeAsyncResult(DB_ASYNC_RESULT hResult)
        free(hResult);
 }
 
-
-//
-// Prepare statement
-//
-
+/**
+ * Prepare statement
+ */
 DB_STATEMENT LIBNXDB_EXPORTABLE DBPrepareEx(DB_HANDLE hConn, const TCHAR *query, TCHAR *errorText)
 {
        DB_STATEMENT result = NULL;
@@ -988,26 +1000,39 @@ DB_STATEMENT LIBNXDB_EXPORTABLE DBPrepareEx(DB_HANDLE hConn, const TCHAR *query,
        free(pwszQuery);
 #endif
 
+   if (result != NULL)
+   {
+      hConn->m_preparedStatements->add(result);
+   }
+
        return result;
 #undef pwszQuery
 #undef wcErrorText
 }
 
+/**
+ * Prepare statement
+ */
 DB_STATEMENT LIBNXDB_EXPORTABLE DBPrepare(DB_HANDLE hConn, const TCHAR *query)
 {
        TCHAR errorText[DBDRV_MAX_ERROR_TEXT];
        return DBPrepareEx(hConn, query, errorText);
 }
 
-
-//
-// Destroy prepared statement
-//
-
+/**
+ * Destroy prepared statement
+ */
 void LIBNXDB_EXPORTABLE DBFreeStatement(DB_STATEMENT hStmt)
 {
-       hStmt->m_driver->m_fpDrvFreeStatement(hStmt->m_statement);
-       safe_free(hStmt->m_query);
+   if (hStmt == NULL)
+      return;
+
+   if (hStmt->m_connection != NULL)
+   {
+      hStmt->m_connection->m_preparedStatements->remove(hStmt);
+   }
+   hStmt->m_driver->m_fpDrvFreeStatement(hStmt->m_statement);
+   safe_free(hStmt->m_query);
        free(hStmt);
 }
 
@@ -1016,7 +1041,7 @@ void LIBNXDB_EXPORTABLE DBFreeStatement(DB_STATEMENT hStmt)
  */
 void LIBNXDB_EXPORTABLE DBBind(DB_STATEMENT hStmt, int pos, int sqlType, int cType, void *buffer, int allocType)
 {
-       if (pos <= 0)
+       if ((pos <= 0) || !IS_VALID_STATEMENT_HANDLE(hStmt))
                return;
 
 #ifdef UNICODE
@@ -1164,6 +1189,12 @@ void LIBNXDB_EXPORTABLE DBBind(DB_STATEMENT hStmt, int pos, int sqlType, double
  */
 BOOL LIBNXDB_EXPORTABLE DBExecuteEx(DB_STATEMENT hStmt, TCHAR *errorText)
 {
+   if (!IS_VALID_STATEMENT_HANDLE(hStmt))
+   {
+      _tcscpy(errorText, _T("Invalid statement handle"));
+      return FALSE;
+   }
+
 #ifdef UNICODE
 #define wcErrorText errorText
 #else
@@ -1217,6 +1248,9 @@ BOOL LIBNXDB_EXPORTABLE DBExecuteEx(DB_STATEMENT hStmt, TCHAR *errorText)
 #undef wcErrorText
 }
 
+/**
+ * Execute prepared statement (non-SELECT)
+ */
 BOOL LIBNXDB_EXPORTABLE DBExecute(DB_STATEMENT hStmt)
 {
        TCHAR errorText[DBDRV_MAX_ERROR_TEXT];
@@ -1228,10 +1262,13 @@ BOOL LIBNXDB_EXPORTABLE DBExecute(DB_STATEMENT hStmt)
  */
 DB_RESULT LIBNXDB_EXPORTABLE DBSelectPreparedEx(DB_STATEMENT hStmt, TCHAR *errorText)
 {
-   DBDRV_RESULT hResult;
+   if (!IS_VALID_STATEMENT_HANDLE(hStmt))
+   {
+      _tcscpy(errorText, _T("Invalid statement handle"));
+      return NULL;
+   }
+
        DB_RESULT result = NULL;
-   DWORD dwError;
-   INT64 ms;
 #ifdef UNICODE
 #define wcErrorText errorText
 #else
@@ -1240,9 +1277,12 @@ DB_RESULT LIBNXDB_EXPORTABLE DBSelectPreparedEx(DB_STATEMENT hStmt, TCHAR *error
 
        DB_HANDLE hConn = hStmt->m_connection;
    MutexLock(hConn->m_mutexTransLock);
+
+   INT64 ms;
    if (hConn->m_driver->m_dumpSql)
       ms = GetCurrentTimeMs();
-       hResult = hConn->m_driver->m_fpDrvSelectPrepared(hConn->m_connection, hStmt->m_statement, &dwError, wcErrorText);
+   DWORD dwError;
+       DBDRV_RESULT hResult = hConn->m_driver->m_fpDrvSelectPrepared(hConn->m_connection, hStmt->m_statement, &dwError, wcErrorText);
 
    if (hConn->m_driver->m_dumpSql)
    {
index fd5b5cc..b796896 100644 (file)
@@ -2,7 +2,7 @@
 ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
 
 #include "setup.iss"
-OutputBaseFilename=netxms-1.2.9-minimal
+OutputBaseFilename=netxms-1.2.10-M1-minimal
 
 [Components]
 Name: "base"; Description: "Base Files"; Types: full compact custom; Flags: fixed
index 5683d6b..3adb42c 100644 (file)
@@ -1,7 +1,7 @@
 [Setup]\r
 AppName=NetXMS\r
-AppVerName=NetXMS 1.2.9\r
-AppVersion=1.2.9\r
+AppVerName=NetXMS 1.2.10-M1\r
+AppVersion=1.2.10-M1\r
 AppPublisher=Raden Solutions\r
 AppPublisherURL=http://www.radensolutions.com\r
 AppSupportURL=http://www.netxms.org\r
index e650001..5628d93 100644 (file)
@@ -1,5 +1,5 @@
 @echo off
-set version=1.2.9
+set version=1.2.10-M1-cortex
 
 cd win32.win32.x86
 zip -r nxmc-%version%-win32-x86.zip nxmc
index 74013a4..b33ad24 100644 (file)
          point="org.eclipse.core.runtime.products">\r
       <product\r
             application="org.netxms.ui.eclipse.console.application"\r
-            name="NetXMS Management Console">\r
+            name="NetXMS Management Console for Cortex">\r
          <property\r
                name="appName"\r
-               value="NetXMS Management Console">\r
-         </property>\r
-         <property\r
-               name="aboutImage"\r
-               value="icons/launcher/128x128.png">\r
+               value="NetXMS Management Console for Cortex">\r
          </property>\r
          <property\r
                name="aboutText"\r
-               value="NetXMS Management Console&#x0A;&#x0A;Version 1.2.9&#x0A;Copyright (c) 2003-2013 Victor Kirhenshtein, Alex Kirhenshtein">\r
-         </property>\r
-         <property\r
-               name="windowImages"\r
-               value="icons/launcher/16x16.png,icons/launcher/32x32.png,icons/launcher/48x48.png,icons/launcher/64x64.png,icons/launcher/128x128.png">\r
+               value="NetXMS Cortex Management Console&#x0A;&#x0A;Copyright (c) 2003-2011 Raden Solutions">\r
          </property>\r
          <property\r
                name="startupForegroundColor"\r
-               value="410B73">\r
+               value="FFFF00">\r
          </property>\r
          <property\r
                name="startupMessageRect"\r
-               value="7,275,441,18">\r
+               value="7,265,386,20">\r
          </property>\r
          <property\r
                name="preferenceCustomization"\r
@@ -95,7 +87,7 @@
          </property>\r
          <property\r
                name="startupProgressRect"\r
-               value="500,284,455,10">\r
+               value="0,285,400,15">\r
          </property>\r
       </product>\r
    </extension>\r
index 18c5c6b..9951a43 100644 (file)
@@ -152,3 +152,14 @@ void Array::clear()
                m_allocated = m_grow;
        }
 }
+
+/**
+ * Get index of given object
+ */
+int Array::indexOf(void *object)
+{
+       for(int i = 0; i < m_size; i++)
+      if (m_data[i] == object)
+         return i;
+   return -1;
+}