Fixed problems with default iconv() codepage
[public/netxms.git] / src / server / tools / nxdbmgr / nxdbmgr.cpp
CommitLineData
fc935a60
VK
1/*
2** nxdbmgr - NetXMS database manager
3** Copyright (C) 2004 Victor Kirhenshtein
4**
5** This program is free software; you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation; either version 2 of the License, or
8** (at your option) any later version.
9**
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.
14**
15** You should have received a copy of the GNU 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.
18**
19** $module: nxdbmgr.cpp
20**
21**/
22
23#include "nxdbmgr.h"
24
748f71f5
VK
25#ifdef _WIN32
26#include <conio.h>
27#endif
28
fc935a60
VK
29
30//
31// Global variables
32//
33
34DB_HANDLE g_hCoreDB;
6ad5eb6d 35BOOL g_bIgnoreErrors = FALSE;
eae524f7 36BOOL g_bTrace = FALSE;
f10ca78d 37int g_iSyntax;
48ad2f8d 38TCHAR *g_pszTableSuffix = _T("");
7dbb6862 39TCHAR *g_pszSqlType[5][2] =
f10ca78d 40{
7dbb6862
VK
41 { _T("blob"), _T("bigint") }, // MySQL
42 { _T("varchar"), _T("bigint") }, // PostgreSQL
43 { _T("text"), _T("bigint") }, // Microsoft SQL
44 { _T("clob"), _T("number(20)") }, // Oracle
45 { _T("varchar"), _T("number(20)") } // SQLite
f10ca78d 46};
fc935a60
VK
47
48
49//
50// Static data
51//
52
5e40a69e 53static TCHAR m_szCodePage[MAX_PATH] = ICONV_DEFAULT_CODEPAGE;
fc935a60
VK
54static NX_CFG_TEMPLATE m_cfgTemplate[] =
55{
6253c842 56 { "CodePage", CT_STRING, 0, 0, MAX_PATH, 0, m_szCodePage },
fc935a60
VK
57 { "DBDriver", CT_STRING, 0, 0, MAX_PATH, 0, g_szDbDriver },
58 { "DBDrvParams", CT_STRING, 0, 0, MAX_PATH, 0, g_szDbDrvParams },
59 { "DBLogin", CT_STRING, 0, 0, MAX_DB_LOGIN, 0, g_szDbLogin },
60 { "DBName", CT_STRING, 0, 0, MAX_DB_NAME, 0, g_szDbName },
61 { "DBPassword", CT_STRING, 0, 0, MAX_DB_PASSWORD, 0, g_szDbPassword },
62 { "DBServer", CT_STRING, 0, 0, MAX_PATH, 0, g_szDbServer },
63 { "LogFailedSQLQueries", CT_IGNORE, 0, 0, 0, 0, NULL },
64 { "LogFile", CT_IGNORE, 0, 0, 0, 0, NULL },
65 { "", CT_END_OF_LIST, 0, 0, 0, 0, NULL }
66};
854e3fee 67static BOOL m_bForce = FALSE;
fc935a60
VK
68
69
eae524f7
VK
70//
71// Show query if trace mode is ON
72//
73
74void ShowQuery(TCHAR *pszQuery)
75{
76#ifdef _WIN32
77 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0x0F);
78 _tprintf(_T(">>> "));
79 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0x0A);
80 puts(pszQuery);
81 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0x07);
82#else
a30fe9f1 83 _tprintf(_T(">>> %s\n"), pszQuery);
eae524f7
VK
84#endif
85}
86
87
748f71f5
VK
88//
89// Get Yes or No answer from keyboard
90//
91
92BOOL GetYesNo(void)
93{
854e3fee
VK
94 if (m_bForce)
95 {
96 printf("Y\n");
97 return TRUE;
98 }
99 else
100 {
748f71f5 101#ifdef _WIN32
854e3fee 102 int ch;
748f71f5 103
854e3fee 104 while(1)
748f71f5 105 {
854e3fee
VK
106 ch = getch();
107 if ((ch == 'y') || (ch == 'Y'))
108 {
109 printf("Y\n");
110 return TRUE;
111 }
112 if ((ch == 'n') || (ch == 'N'))
113 {
114 printf("N\n");
115 return FALSE;
116 }
748f71f5 117 }
748f71f5 118#else
854e3fee 119 TCHAR szBuffer[16];
748f71f5 120
854e3fee
VK
121 fflush(stdout);
122 _fgetts(szBuffer, 16, stdin);
123 StrStrip(szBuffer);
124 return ((szBuffer[0] == 'y') || (szBuffer[0] == 'Y'));
748f71f5 125#endif
854e3fee 126 }
748f71f5
VK
127}
128
129
f10ca78d
VK
130//
131// Execute SQL SELECT query and print error message on screen if query failed
132//
133
134DB_RESULT SQLSelect(TCHAR *pszQuery)
135{
136 DB_RESULT hResult;
137
eae524f7
VK
138 if (g_bTrace)
139 ShowQuery(pszQuery);
140
f10ca78d
VK
141 hResult = DBSelect(g_hCoreDB, pszQuery);
142 if (hResult == NULL)
143 {
144#ifdef _WIN32
145 _tprintf(_T("SQL query failed:\n"));
146 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0x0E);
147 _tprintf(_T("%s\n"), pszQuery);
148 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0x07);
149#else
150 _tprintf(_T("SQL query failed:\n%s\n"), pszQuery);
151#endif
152 }
153 return hResult;
154}
155
156
6ad5eb6d
VK
157//
158// Execute SQL query and print error message on screen if query failed
159//
160
161BOOL SQLQuery(TCHAR *pszQuery)
162{
163 BOOL bResult;
164
eae524f7
VK
165 if (g_bTrace)
166 ShowQuery(pszQuery);
167
6ad5eb6d
VK
168 bResult = DBQuery(g_hCoreDB, pszQuery);
169 if (!bResult)
170 {
171#ifdef _WIN32
172 _tprintf(_T("SQL query failed:\n"));
173 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0x0E);
174 _tprintf(_T("%s\n"), pszQuery);
175 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0x07);
176#else
177 _tprintf(_T("SQL query failed:\n%s\n"), pszQuery);
178#endif
179 }
180 return bResult;
181}
182
183
22c38feb
VK
184//
185// Execute SQL batch
186//
187
188BOOL SQLBatch(TCHAR *pszBatch)
189{
eae524f7
VK
190 TCHAR *pszBuffer, *pszQuery, *ptr;
191 BOOL bRet = TRUE;
192
193 pszBuffer = _tcsdup(pszBatch);
194 TranslateStr(pszBuffer, _T("$SQL:TEXT"), g_pszSqlType[g_iSyntax][SQL_TYPE_TEXT]);
195 TranslateStr(pszBuffer, _T("$SQL:INT64"), g_pszSqlType[g_iSyntax][SQL_TYPE_INT64]);
22c38feb 196
eae524f7 197 pszQuery = pszBuffer;
22c38feb
VK
198 while(1)
199 {
200 ptr = _tcschr(pszQuery, _T('\n'));
201 if (ptr != NULL)
202 *ptr = 0;
203 if (!_tcscmp(pszQuery, _T("<END>")))
204 break;
eae524f7
VK
205
206 if (g_bTrace)
207 ShowQuery(pszQuery);
208
22c38feb
VK
209 if (!DBQuery(g_hCoreDB, pszQuery))
210 {
211#ifdef _WIN32
212 _tprintf(_T("SQL query failed:\n"));
213 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0x0E);
214 _tprintf(_T("%s\n"), pszQuery);
215 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0x07);
216#else
217 _tprintf(_T("SQL query failed:\n%s\n"), pszQuery);
218#endif
219 if (!g_bIgnoreErrors)
eae524f7
VK
220 {
221 bRet = FALSE;
222 break;
223 }
22c38feb
VK
224 }
225 ptr++;
226 pszQuery = ptr;
227 }
eae524f7
VK
228 free(pszBuffer);
229 return bRet;
22c38feb
VK
230}
231
232
b4fbaa08
VK
233//
234// Read string value from configuration table
235//
236
237BOOL ConfigReadStr(TCHAR *pszVar, TCHAR *pszBuffer, int iBufSize, const TCHAR *pszDefault)
238{
239 DB_RESULT hResult;
240 TCHAR szQuery[256];
241 BOOL bSuccess = FALSE;
242
c81979bc 243 nx_strncpy(pszBuffer, pszDefault, iBufSize);
b4fbaa08
VK
244 if (_tcslen(pszVar) > 127)
245 return FALSE;
246
247 _sntprintf(szQuery, 256, _T("SELECT var_value FROM config WHERE var_name='%s'"), pszVar);
248 hResult = SQLSelect(szQuery);
249 if (hResult == 0)
250 return FALSE;
251
252 if (DBGetNumRows(hResult) > 0)
253 {
7d4b78b3 254 DBGetField(hResult, 0, 0, pszBuffer, iBufSize);
56cd40b6 255 DecodeSQLString(pszBuffer);
b4fbaa08
VK
256 bSuccess = TRUE;
257 }
258
259 DBFreeResult(hResult);
260 return bSuccess;
261}
262
263
264//
265// Read integer value from configuration table
266//
267
268int ConfigReadInt(TCHAR *pszVar, int iDefault)
269{
270 TCHAR szBuffer[64];
271
272 if (ConfigReadStr(pszVar, szBuffer, 64, _T("")))
273 return _tcstol(szBuffer, NULL, 0);
274 else
275 return iDefault;
276}
277
278
279//
280// Read unsigned long value from configuration table
281//
282
283DWORD ConfigReadULong(TCHAR *pszVar, DWORD dwDefault)
284{
285 TCHAR szBuffer[64];
286
287 if (ConfigReadStr(pszVar, szBuffer, 64, _T("")))
288 return _tcstoul(szBuffer, NULL, 0);
289 else
290 return dwDefault;
291}
292
293
fc935a60
VK
294//
295// Startup
296//
297
298int main(int argc, char *argv[])
299{
300 BOOL bStart = TRUE, bForce = FALSE;
301 int ch;
f10ca78d
VK
302 TCHAR szSyntaxId[16], szConfigFile[MAX_PATH] = DEFAULT_CONFIG_FILE;
303 DB_RESULT hResult;
4db20d1c
VK
304#ifdef _WIN32
305 HKEY hKey;
306 DWORD dwSize;
307#else
308 char *pszEnv;
309#endif
fc935a60
VK
310
311 printf("NetXMS Database Manager Version " NETXMS_VERSION_STRING "\n\n");
312
4db20d1c
VK
313 // Check for alternate config file location
314#ifdef _WIN32
315 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\NetXMS\\Server"), 0,
316 KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
317 {
318 dwSize = MAX_PATH * sizeof(TCHAR);
319 RegQueryValueEx(hKey, _T("ConfigFile"), NULL, NULL, (BYTE *)szConfigFile, &dwSize);
320 RegCloseKey(hKey);
321 }
322#else
323 pszEnv = getenv("NETXMSD_CONFIG");
324 if (pszEnv != NULL)
325 nx_strncpy(szConfigFile, pszEnv, MAX_PATH);
326#endif
327
fc935a60
VK
328 // Parse command line
329 opterr = 1;
eae524f7 330 while((ch = getopt(argc, argv, "c:fhIMtvX")) != -1)
fc935a60
VK
331 {
332 switch(ch)
333 {
334 case 'h': // Display help and exit
335 _tprintf(_T("Usage: nxdbmgr [<options>] <command>\n"
336 "Valid commands are:\n"
337 " check : Check database for errors\n"
7dbb6862 338 " init <file> : Initialize database\n"
af4147f3 339 " unlock : Forced database unlock\n"
fc935a60
VK
340 " upgrade : Upgrade database to new version\n"
341 "Valid options are:\n"
37c4d6aa 342 " -c <config> : Use alternate configuration file. Default is " DEFAULT_CONFIG_FILE "\n"
fc935a60
VK
343 " -f : Force repair - do not ask for confirmation.\n"
344 " -h : Display help and exit.\n"
48ad2f8d
VK
345 " -I : MySQL only - specify TYPE=InnoDB for new tables.\n"
346 " -M : MySQL only - specify TYPE=MyISAM for new tables.\n"
eae524f7 347 " -t : Enable trace moded (show executed SQL queries).\n"
fc935a60 348 " -v : Display version and exit.\n"
6ad5eb6d 349 " -X : Ignore SQL errors when upgrading (USE WITH CARE!!!)\n"
fc935a60
VK
350 "\n"));
351 bStart = FALSE;
352 break;
353 case 'v': // Print version and exit
354 bStart = FALSE;
355 break;
356 case 'c':
c81979bc 357 nx_strncpy(szConfigFile, optarg, MAX_PATH);
fc935a60
VK
358 break;
359 case 'f':
854e3fee 360 m_bForce = TRUE;
fc935a60 361 break;
eae524f7
VK
362 case 't':
363 g_bTrace = TRUE;
364 break;
48ad2f8d
VK
365 case 'I':
366 g_pszTableSuffix = _T(" TYPE=InnoDB");
367 break;
368 case 'M':
369 g_pszTableSuffix = _T(" TYPE=MyISAM");
370 break;
6ad5eb6d
VK
371 case 'X':
372 g_bIgnoreErrors = TRUE;
373 break;
fc935a60
VK
374 case '?':
375 bStart = FALSE;
376 break;
377 default:
378 break;
379 }
380 }
381
382 if (!bStart)
383 return 1;
384
385 // Check parameter correctness
386 if (argc - optind == 0)
387 {
388 _tprintf(_T("Command missing. Type nxdbmgr -h for command line syntax.\n"));
389 return 1;
390 }
7dbb6862
VK
391 if (strcmp(argv[optind], "check") &&
392 strcmp(argv[optind], "upgrade") &&
af4147f3 393 strcmp(argv[optind], "unlock") &&
7dbb6862 394 strcmp(argv[optind], "init"))
fc935a60
VK
395 {
396 _tprintf(_T("Invalid command \"%s\". Type nxdbmgr -h for command line syntax.\n"), argv[optind]);
397 return 1;
398 }
7dbb6862
VK
399 if ((!strcmp(argv[optind], "init")) && (argc - optind < 2))
400 {
401 _tprintf("Required command argument missing\n");
402 return 1;
403 }
fc935a60
VK
404
405 // Read configuration file
406 if (NxLoadConfig(szConfigFile, _T(""), m_cfgTemplate, TRUE) != NXCFG_ERR_OK)
407 {
408 _tprintf(_T("Error loading configuration file\n"));
409 return 2;
410 }
15dcaed8 411#ifndef _WIN32
6253c842 412 SetDefaultCodepage(m_szCodePage);
15dcaed8 413#endif
fc935a60
VK
414
415 // Connect to database
27cc829a 416 if (!DBInit(FALSE, FALSE, FALSE, NULL))
fc935a60
VK
417 {
418 _tprintf(_T("Unable to load and initialize database driver \"%s\"\n"), g_szDbDriver);
419 return 3;
420 }
421
422 g_hCoreDB = DBConnect();
423 if (g_hCoreDB == NULL)
424 {
425 _tprintf(_T("Unable to connect to database %s@%s as %s\n"), g_szDbName,
426 g_szDbServer, g_szDbLogin);
427 DBUnloadDriver();
428 return 4;
429 }
430
7dbb6862
VK
431 if (!strcmp(argv[optind], "init"))
432 {
433 InitDatabase(argv[optind + 1]);
434 }
435 else
f10ca78d 436 {
7dbb6862
VK
437 // Get database syntax
438 hResult = DBSelect(g_hCoreDB, _T("SELECT var_value FROM config WHERE var_name='DBSyntax'"));
439 if (hResult != NULL)
f10ca78d 440 {
7dbb6862
VK
441 if (DBGetNumRows(hResult) > 0)
442 {
7d4b78b3 443 DBGetField(hResult, 0, 0, szSyntaxId, sizeof(szSyntaxId));
7dbb6862
VK
444 DecodeSQLString(szSyntaxId);
445 }
446 else
447 {
448 _tcscpy(szSyntaxId, _T("UNKNOWN"));
449 }
450 DBFreeResult(hResult);
f10ca78d
VK
451 }
452 else
453 {
7dbb6862
VK
454 _tprintf(_T("Unable to determine database syntax\n"));
455 DBDisconnect(g_hCoreDB);
456 DBUnloadDriver();
457 return 5;
f10ca78d 458 }
f10ca78d 459
7dbb6862
VK
460 if (!_tcscmp(szSyntaxId, _T("MYSQL")))
461 {
462 g_iSyntax = DB_SYNTAX_MYSQL;
463 }
464 else if (!_tcscmp(szSyntaxId, _T("PGSQL")))
465 {
466 g_iSyntax = DB_SYNTAX_PGSQL;
467 }
468 else if (!_tcscmp(szSyntaxId, _T("MSSQL")))
469 {
470 g_iSyntax = DB_SYNTAX_MSSQL;
471 }
472 else if (!_tcscmp(szSyntaxId, _T("ORACLE")))
473 {
474 g_iSyntax = DB_SYNTAX_ORACLE;
475 }
476 else if (!_tcscmp(szSyntaxId, _T("SQLITE")))
477 {
478 g_iSyntax = DB_SYNTAX_SQLITE;
479 }
480 else
481 {
482 _tprintf(_T("Unknown database syntax %s\n"), szSyntaxId);
483 DBDisconnect(g_hCoreDB);
484 DBUnloadDriver();
485 return 6;
486 }
f10ca78d 487
7dbb6862
VK
488 // Do requested operation
489 if (!strcmp(argv[optind], "check"))
490 CheckDatabase();
491 else if (!strcmp(argv[optind], "upgrade"))
492 UpgradeDatabase();
af4147f3
VK
493 else if (!strcmp(argv[optind], "unlock"))
494 UnlockDatabase();
7dbb6862 495 }
fc935a60
VK
496
497 // Shutdown
498 DBDisconnect(g_hCoreDB);
499 DBUnloadDriver();
500 return 0;
501}