2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2014 Victor Kirhenshtein
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU Lesser General Public License as published by
7 ** the Free Software Foundation; either version 3 of the License, or
8 ** (at your option) any later version.
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
15 ** You should have received a copy of the GNU Lesser General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 UINT32 g_logMsgCode
= 0;
29 UINT32 g_sqlErrorMsgCode
= 0;
32 * Long-running query threshold
34 UINT32 g_sqlQueryExecTimeThreshold
= 0xFFFFFFFF;
39 static DB_DRIVER s_drivers
[MAX_DB_DRIVERS
];
40 static MUTEX s_driverListLock
;
45 static bool s_writeLog
= false;
46 static bool s_logSqlErrors
= false;
49 * Get symbol address and log errors
51 static void *DLGetSymbolAddrEx(HMODULE hModule
, const char *pszSymbol
, bool mandatory
= true)
54 TCHAR szErrorText
[256];
56 pFunc
= DLGetSymbolAddr(hModule
, pszSymbol
, szErrorText
);
57 if ((pFunc
== NULL
) && mandatory
&& s_writeLog
)
58 __DBWriteLog(EVENTLOG_WARNING_TYPE
, _T("Unable to resolve symbol \"%hs\": %s"), pszSymbol
, szErrorText
);
65 bool LIBNXDB_EXPORTABLE
DBInit(DWORD logMsgCode
, DWORD sqlErrorMsgCode
)
67 memset(s_drivers
, 0, sizeof(s_drivers
));
68 s_driverListLock
= MutexCreate();
70 g_logMsgCode
= logMsgCode
;
71 s_writeLog
= (logMsgCode
> 0);
72 g_sqlErrorMsgCode
= sqlErrorMsgCode
;
73 s_logSqlErrors
= (sqlErrorMsgCode
> 0) && s_writeLog
;
79 * Load and initialize database driver
80 * If logMsgCode == 0, logging will be disabled
81 * If sqlErrorMsgCode == 0, failed SQL queries will not be logged
83 * @return driver handle on success, NULL on failure
85 DB_DRIVER LIBNXDB_EXPORTABLE
DBLoadDriver(const TCHAR
*module
, const TCHAR
*initParameters
,
86 bool dumpSQL
, void (* fpEventHandler
)(DWORD
, const WCHAR
*, const WCHAR
*, bool, void *),
89 static DWORD dwVersionZero
= 0;
90 bool (* fpDrvInit
)(const char *);
92 TCHAR szErrorText
[256];
93 const char *driverName
;
95 bool alreadyLoaded
= false;
97 int i
; // have to define it here because otherwise HP aCC complains at goto statements
99 MutexLock(s_driverListLock
);
101 driver
= (DB_DRIVER
)malloc(sizeof(db_driver_t
));
102 memset(driver
, 0, sizeof(db_driver_t
));
104 driver
->m_logSqlErrors
= s_logSqlErrors
;
105 driver
->m_dumpSql
= dumpSQL
;
106 driver
->m_fpEventHandler
= fpEventHandler
;
107 driver
->m_userArg
= userArg
;
109 // Load driver's module
111 driver
->m_handle
= DLOpen(module
, szErrorText
);
113 TCHAR fullName
[MAX_PATH
];
114 if (_tcschr(module
, _T('/')) == NULL
)
116 const TCHAR
*homeDir
= _tgetenv(_T("NETXMS_HOME"));
117 if ((homeDir
!= NULL
) && (*homeDir
!= 0))
119 _sntprintf(fullName
, MAX_PATH
, _T("%s/lib/netxms/dbdrv/%s"), homeDir
, module
);
123 _sntprintf(fullName
, MAX_PATH
, _T("%s/dbdrv/%s"), PKGLIBDIR
, module
);
128 nx_strncpy(fullName
, module
, MAX_PATH
);
130 driver
->m_handle
= DLOpen(fullName
, szErrorText
);
132 if (driver
->m_handle
== NULL
)
135 __DBWriteLog(EVENTLOG_ERROR_TYPE
, _T("Unable to load database driver module \"%s\": %s"), module
, szErrorText
);
139 // Check API version supported by driver
140 pdwAPIVersion
= (DWORD
*)DLGetSymbolAddr(driver
->m_handle
, "drvAPIVersion", NULL
);
141 if (pdwAPIVersion
== NULL
)
142 pdwAPIVersion
= &dwVersionZero
;
143 if (*pdwAPIVersion
!= DBDRV_API_VERSION
)
146 __DBWriteLog(EVENTLOG_ERROR_TYPE
, _T("Database driver \"%s\" cannot be loaded because of API version mismatch (server: %d; driver: %d)"),
147 module
, (int)(DBDRV_API_VERSION
), (int)(*pdwAPIVersion
));
152 driverName
= *((const char **)DLGetSymbolAddr(driver
->m_handle
, "drvName", NULL
));
153 if (driverName
== NULL
)
156 __DBWriteLog(EVENTLOG_ERROR_TYPE
, _T("Unable to find all required entry points in database driver \"%s\""), module
);
160 for(i
= 0; i
< MAX_DB_DRIVERS
; i
++)
162 if ((s_drivers
[i
] != NULL
) && (!stricmp(s_drivers
[i
]->m_name
, driverName
)))
164 alreadyLoaded
= true;
168 if (s_drivers
[i
] == NULL
)
175 __DBWriteLog(EVENTLOG_INFORMATION_TYPE
, _T("Reusing already loaded database driver \"%hs\""), s_drivers
[position
]->m_name
);
182 __DBWriteLog(EVENTLOG_ERROR_TYPE
, _T("Unable to load database driver \"%s\": too many drivers already loaded"), module
);
187 fpDrvInit
= (bool (*)(const char *))DLGetSymbolAddrEx(driver
->m_handle
, "DrvInit");
188 driver
->m_fpDrvConnect
= (DBDRV_CONNECTION (*)(const char *, const char *, const char *, const char *, const char *, WCHAR
*))DLGetSymbolAddrEx(driver
->m_handle
, "DrvConnect");
189 driver
->m_fpDrvDisconnect
= (void (*)(DBDRV_CONNECTION
))DLGetSymbolAddrEx(driver
->m_handle
, "DrvDisconnect");
190 driver
->m_fpDrvSetPrefetchLimit
= (bool (*)(DBDRV_CONNECTION
, int))DLGetSymbolAddrEx(driver
->m_handle
, "DrvSetPrefetchLimit", false);
191 driver
->m_fpDrvPrepare
= (DBDRV_STATEMENT (*)(DBDRV_CONNECTION
, const WCHAR
*, DWORD
*, WCHAR
*))DLGetSymbolAddrEx(driver
->m_handle
, "DrvPrepare");
192 driver
->m_fpDrvFreeStatement
= (void (*)(DBDRV_STATEMENT
))DLGetSymbolAddrEx(driver
->m_handle
, "DrvFreeStatement");
193 driver
->m_fpDrvOpenBatch
= (bool (*)(DBDRV_STATEMENT
))DLGetSymbolAddrEx(driver
->m_handle
, "DrvOpenBatch", false);
194 driver
->m_fpDrvNextBatchRow
= (void (*)(DBDRV_STATEMENT
))DLGetSymbolAddrEx(driver
->m_handle
, "DrvNextBatchRow", false);
195 driver
->m_fpDrvBind
= (void (*)(DBDRV_STATEMENT
, int, int, int, void *, int))DLGetSymbolAddrEx(driver
->m_handle
, "DrvBind");
196 driver
->m_fpDrvExecute
= (DWORD (*)(DBDRV_CONNECTION
, DBDRV_STATEMENT
, WCHAR
*))DLGetSymbolAddrEx(driver
->m_handle
, "DrvExecute");
197 driver
->m_fpDrvQuery
= (DWORD (*)(DBDRV_CONNECTION
, const WCHAR
*, WCHAR
*))DLGetSymbolAddrEx(driver
->m_handle
, "DrvQuery");
198 driver
->m_fpDrvSelect
= (DBDRV_RESULT (*)(DBDRV_CONNECTION
, const WCHAR
*, DWORD
*, WCHAR
*))DLGetSymbolAddrEx(driver
->m_handle
, "DrvSelect");
199 driver
->m_fpDrvSelectUnbuffered
= (DBDRV_UNBUFFERED_RESULT (*)(DBDRV_CONNECTION
, const WCHAR
*, DWORD
*, WCHAR
*))DLGetSymbolAddrEx(driver
->m_handle
, "DrvSelectUnbuffered");
200 driver
->m_fpDrvSelectPrepared
= (DBDRV_RESULT (*)(DBDRV_CONNECTION
, DBDRV_STATEMENT
, DWORD
*, WCHAR
*))DLGetSymbolAddrEx(driver
->m_handle
, "DrvSelectPrepared");
201 driver
->m_fpDrvSelectPreparedUnbuffered
= (DBDRV_UNBUFFERED_RESULT (*)(DBDRV_CONNECTION
, DBDRV_STATEMENT
, DWORD
*, WCHAR
*))DLGetSymbolAddrEx(driver
->m_handle
, "DrvSelectPreparedUnbuffered");
202 driver
->m_fpDrvFetch
= (bool (*)(DBDRV_UNBUFFERED_RESULT
))DLGetSymbolAddrEx(driver
->m_handle
, "DrvFetch");
203 driver
->m_fpDrvGetFieldLength
= (LONG (*)(DBDRV_RESULT
, int, int))DLGetSymbolAddrEx(driver
->m_handle
, "DrvGetFieldLength");
204 driver
->m_fpDrvGetFieldLengthUnbuffered
= (LONG (*)(DBDRV_UNBUFFERED_RESULT
, int))DLGetSymbolAddrEx(driver
->m_handle
, "DrvGetFieldLengthUnbuffered");
205 driver
->m_fpDrvGetField
= (WCHAR
* (*)(DBDRV_RESULT
, int, int, WCHAR
*, int))DLGetSymbolAddrEx(driver
->m_handle
, "DrvGetField");
206 driver
->m_fpDrvGetFieldUTF8
= (char* (*)(DBDRV_RESULT
, int, int, char *, int))DLGetSymbolAddrEx(driver
->m_handle
, "DrvGetFieldUTF8", false); // optional entry point
207 driver
->m_fpDrvGetFieldUnbuffered
= (WCHAR
* (*)(DBDRV_UNBUFFERED_RESULT
, int, WCHAR
*, int))DLGetSymbolAddrEx(driver
->m_handle
, "DrvGetFieldUnbuffered");
208 driver
->m_fpDrvGetFieldUnbufferedUTF8
= (char* (*)(DBDRV_UNBUFFERED_RESULT
, int, char *, int))DLGetSymbolAddrEx(driver
->m_handle
, "DrvGetFieldUnbufferedUTF8");
209 driver
->m_fpDrvGetNumRows
= (int (*)(DBDRV_RESULT
))DLGetSymbolAddrEx(driver
->m_handle
, "DrvGetNumRows");
210 driver
->m_fpDrvGetColumnCount
= (int (*)(DBDRV_RESULT
))DLGetSymbolAddrEx(driver
->m_handle
, "DrvGetColumnCount");
211 driver
->m_fpDrvGetColumnName
= (const char* (*)(DBDRV_RESULT
, int))DLGetSymbolAddrEx(driver
->m_handle
, "DrvGetColumnName");
212 driver
->m_fpDrvGetColumnCountUnbuffered
= (int (*)(DBDRV_UNBUFFERED_RESULT
))DLGetSymbolAddrEx(driver
->m_handle
, "DrvGetColumnCountUnbuffered");
213 driver
->m_fpDrvGetColumnNameUnbuffered
= (const char* (*)(DBDRV_UNBUFFERED_RESULT
, int))DLGetSymbolAddrEx(driver
->m_handle
, "DrvGetColumnNameUnbuffered");
214 driver
->m_fpDrvFreeResult
= (void (*)(DBDRV_RESULT
))DLGetSymbolAddrEx(driver
->m_handle
, "DrvFreeResult");
215 driver
->m_fpDrvFreeUnbufferedResult
= (void (*)(DBDRV_UNBUFFERED_RESULT
))DLGetSymbolAddrEx(driver
->m_handle
, "DrvFreeUnbufferedResult");
216 driver
->m_fpDrvBegin
= (DWORD (*)(DBDRV_CONNECTION
))DLGetSymbolAddrEx(driver
->m_handle
, "DrvBegin");
217 driver
->m_fpDrvCommit
= (DWORD (*)(DBDRV_CONNECTION
))DLGetSymbolAddrEx(driver
->m_handle
, "DrvCommit");
218 driver
->m_fpDrvRollback
= (DWORD (*)(DBDRV_CONNECTION
))DLGetSymbolAddrEx(driver
->m_handle
, "DrvRollback");
219 driver
->m_fpDrvUnload
= (void (*)(void))DLGetSymbolAddrEx(driver
->m_handle
, "DrvUnload");
220 driver
->m_fpDrvPrepareStringA
= (char* (*)(const char *))DLGetSymbolAddrEx(driver
->m_handle
, "DrvPrepareStringA");
221 driver
->m_fpDrvPrepareStringW
= (WCHAR
* (*)(const WCHAR
*))DLGetSymbolAddrEx(driver
->m_handle
, "DrvPrepareStringW");
222 driver
->m_fpDrvIsTableExist
= (int (*)(DBDRV_CONNECTION
, const WCHAR
*))DLGetSymbolAddrEx(driver
->m_handle
, "DrvIsTableExist");
223 if ((fpDrvInit
== NULL
) || (driver
->m_fpDrvConnect
== NULL
) || (driver
->m_fpDrvDisconnect
== NULL
) ||
224 (driver
->m_fpDrvPrepare
== NULL
) || (driver
->m_fpDrvBind
== NULL
) || (driver
->m_fpDrvFreeStatement
== NULL
) ||
225 (driver
->m_fpDrvQuery
== NULL
) || (driver
->m_fpDrvSelect
== NULL
) || (driver
->m_fpDrvGetField
== NULL
) ||
226 (driver
->m_fpDrvGetNumRows
== NULL
) || (driver
->m_fpDrvFreeResult
== NULL
) || (driver
->m_fpDrvSelectPrepared
== NULL
) ||
227 (driver
->m_fpDrvSelectPreparedUnbuffered
== NULL
) || (driver
->m_fpDrvUnload
== NULL
) ||
228 (driver
->m_fpDrvSelectUnbuffered
== NULL
) || (driver
->m_fpDrvFetch
== NULL
) ||
229 (driver
->m_fpDrvFreeUnbufferedResult
== NULL
) || (driver
->m_fpDrvGetFieldUnbuffered
== NULL
) ||
230 (driver
->m_fpDrvBegin
== NULL
) || (driver
->m_fpDrvCommit
== NULL
) || (driver
->m_fpDrvRollback
== NULL
) ||
231 (driver
->m_fpDrvGetColumnCount
== NULL
) || (driver
->m_fpDrvGetColumnName
== NULL
) ||
232 (driver
->m_fpDrvGetColumnCountUnbuffered
== NULL
) || (driver
->m_fpDrvGetColumnNameUnbuffered
== NULL
) ||
233 (driver
->m_fpDrvGetFieldLength
== NULL
) || (driver
->m_fpDrvGetFieldLengthUnbuffered
== NULL
) ||
234 (driver
->m_fpDrvPrepareStringA
== NULL
) || (driver
->m_fpDrvPrepareStringW
== NULL
) || (driver
->m_fpDrvIsTableExist
== NULL
))
237 __DBWriteLog(EVENTLOG_ERROR_TYPE
, _T("Unable to find all required entry points in database driver \"%s\""), module
);
243 char mbInitParameters
[1024];
244 if (initParameters
!= NULL
)
246 WideCharToMultiByte(CP_ACP
, WC_COMPOSITECHECK
| WC_DEFAULTCHAR
, initParameters
, -1, mbInitParameters
, 1024, NULL
, NULL
);
247 mbInitParameters
[1023] = 0;
251 mbInitParameters
[0] = 0;
253 if (!fpDrvInit(mbInitParameters
))
255 if (!fpDrvInit(CHECK_NULL_EX(initParameters
)))
259 __DBWriteLog(EVENTLOG_ERROR_TYPE
, _T("Database driver \"%s\" initialization failed"), module
);
264 driver
->m_mutexReconnect
= MutexCreate();
265 driver
->m_name
= driverName
;
266 driver
->m_refCount
= 1;
267 driver
->m_defaultPrefetchLimit
= 10;
268 s_drivers
[position
] = driver
;
270 __DBWriteLog(EVENTLOG_INFORMATION_TYPE
, _T("Database driver \"%s\" loaded and initialized successfully"), module
);
271 MutexUnlock(s_driverListLock
);
275 if (driver
->m_handle
!= NULL
)
276 DLClose(driver
->m_handle
);
278 MutexUnlock(s_driverListLock
);
282 if (driver
->m_handle
!= NULL
)
283 DLClose(driver
->m_handle
);
285 s_drivers
[position
]->m_refCount
++;
286 MutexUnlock(s_driverListLock
);
287 return s_drivers
[position
];
293 void LIBNXDB_EXPORTABLE
DBUnloadDriver(DB_DRIVER driver
)
298 MutexLock(s_driverListLock
);
300 for(int i
= 0; i
< MAX_DB_DRIVERS
; i
++)
302 if (s_drivers
[i
] == driver
)
304 driver
->m_refCount
--;
305 if (driver
->m_refCount
<= 0)
307 driver
->m_fpDrvUnload();
308 DLClose(driver
->m_handle
);
309 MutexDestroy(driver
->m_mutexReconnect
);
317 MutexUnlock(s_driverListLock
);
321 * Get name of loaded driver
323 const char LIBNXDB_EXPORTABLE
*DBGetDriverName(DB_DRIVER driver
)
325 return driver
->m_name
;