fixed bug in agent local database structure check
[public/netxms.git] / src / agent / core / localdb.cpp
CommitLineData
c72b812a
VK
1/*
2** NetXMS multiplatform core agent
3** Copyright (C) 2003-2015 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**
7c7a57b9 19** File: localdb.cpp
c72b812a
VK
20**
21**/
22
23#include "nxagentd.h"
24
c72b812a
VK
25/**
26 * Database driver
27 */
28static DB_DRIVER s_driver = NULL;
29
30/**
31 * Database handle
32 */
33static DB_HANDLE s_db = NULL;
34
35/**
36 * Read metadata
37 */
d9c628e3 38TCHAR *ReadMetadata(const TCHAR *attr, TCHAR *buffer)
c72b812a
VK
39{
40 TCHAR query[256], *value = NULL;
41 _sntprintf(query, 256, _T("SELECT value FROM metadata WHERE attribute='%s'"), attr);
d9c628e3 42
c72b812a
VK
43 DB_RESULT hResult = DBSelect(s_db, query);
44 if (hResult != NULL)
45 {
46 value = DBGetField(hResult, 0, 0, buffer, MAX_DB_STRING);
47 DBFreeResult(hResult);
48 }
49 return value;
50}
51
52/**
53 * Read integer from metadata
54 */
a97f02e1 55INT32 ReadMetadataAsInt(const TCHAR *attr)
c72b812a
VK
56{
57 TCHAR buffer[MAX_DB_STRING];
58 if (ReadMetadata(attr, buffer) == NULL)
59 return 0;
60 return _tcstol(buffer, NULL, 0);
61}
62
a97f02e1
VK
63/**
64 * Set value in metadata
65 */
66bool WriteMetadata(const TCHAR *name, const TCHAR *value)
67{
68 String prepValue = DBPrepareString(s_db, value, 255);
69
70 TCHAR query[1024];
71 _sntprintf(query, 1024, _T("UPDATE OR IGNORE metadata SET value=%s WHERE attribute='%s'"), (const TCHAR *)prepValue, name);
72 if (!DBQuery(s_db, query))
73 return false;
74
75 _sntprintf(query, 1024, _T("INSERT OR IGNORE INTO metadata (attribute,value) VALUES ('%s',%s)"), name, (const TCHAR *)prepValue);
76 return DBQuery(s_db, query);
77}
78
79/**
80 * Set value in metadata from int
81 */
82bool WriteMetadata(const TCHAR *name, INT32 value)
83{
84 TCHAR buffer[64];
85 _sntprintf(buffer, 64, _T("%d"), value);
86 return WriteMetadata(name, buffer);
87}
88
fe00bd6f
VK
89/**
90 * DB init queries
91 */
92static const TCHAR *s_dbInitQueries[] =
93{
94 _T("CREATE TABLE agent_policy (")
95 _T(" guid varchar(36) not null,")
96 _T(" type integer not null,")
97 _T(" server_info varchar(64) null,")
98 _T(" server_id number(20) not null,")
99 _T(" version integer not null,")
100 _T(" PRIMARY KEY(guid))"),
101
102 _T("CREATE TABLE dc_config (")
103 _T(" server_id number(20) not null,")
104 _T(" dci_id integer not null,")
105 _T(" type integer not null,")
106 _T(" origin integer not null,")
107 _T(" name varchar(1023) null,")
108 _T(" polling_interval integer not null,")
109 _T(" last_poll integer not null,")
110 _T(" snmp_port integer not null,")
111 _T(" snmp_target_guid varchar(36) not null,")
112 _T(" snmp_raw_type integer not null,")
113 _T(" PRIMARY KEY(server_id,dci_id))"),
114
115 _T("CREATE TABLE dc_queue (")
116 _T(" server_id number(20) not null,")
117 _T(" dci_id integer not null,")
118 _T(" dci_type integer not null,")
119 _T(" dci_origin integer not null,")
120 _T(" snmp_target_guid varchar(36) not null,")
121 _T(" timestamp integer not null,")
122 _T(" value varchar not null,")
123 _T(" status_code integer not null,")
124 _T(" PRIMARY KEY(server_id,dci_id,timestamp))"),
125
126 _T("CREATE TABLE dc_snmp_targets (")
127 _T(" guid varchar(36) not null,")
128 _T(" server_id number(20) not null,")
129 _T(" ip_address varchar(48) not null,")
130 _T(" snmp_version integer not null,")
131 _T(" port integer not null,")
132 _T(" auth_type integer not null,")
133 _T(" enc_type integer not null,")
134 _T(" auth_name varchar(63),")
135 _T(" auth_pass varchar(63),")
136 _T(" enc_pass varchar(63),")
137 _T(" PRIMARY KEY(guid))"),
138
139 _T("CREATE TABLE registry (")
140 _T(" attribute varchar(63) null,")
141 _T(" value varchar null,")
142 _T(" PRIMARY KEY(attribute))"),
143
144 NULL
145};
146
147/**
148 * Initialize new database
149 */
150static bool InitDatabase()
151{
152 for(int i = 0; s_dbInitQueries[i] != NULL; i++)
153 if (!DBQuery(s_db, s_dbInitQueries[i]))
154 return false;
155 nxlog_debug(1, _T("Empty local database initialized successfully"));
156 return true;
157}
158
159/**
160 * Database tables
161 */
162static const TCHAR *s_dbTables[] = { _T("agent_policy"), _T("dc_config"), _T("dc_queue"), _T("dc_snmp_targets"), _T("registry"), NULL };
163
c72b812a
VK
164/**
165 * Check database structure
166 */
5e12ef62 167static bool CheckDatabaseStructure()
c72b812a
VK
168{
169 int version;
170 if (!DBIsTableExist(s_db, _T("metadata")))
171 {
172 DBQuery(s_db, _T("CREATE TABLE metadata (attribute varchar(63), value varchar(255), PRIMARY KEY(attribute))"));
173
fe00bd6f
VK
174 // assume empty database, create tables
175 if (!InitDatabase())
176 {
177 nxlog_write(MSG_LOCAL_DB_CORRUPTED, NXLOG_ERROR, NULL);
178 return false;
179 }
180
c72b812a
VK
181 TCHAR query[256];
182 _sntprintf(query, 256, _T("INSERT INTO metadata (attribute, value) VALUES ('SchemaVersion', '%d')"), DB_SCHEMA_VERSION);
183 DBQuery(s_db, query);
184
185 version = DB_SCHEMA_VERSION;
186 }
187 else
188 {
189 version = ReadMetadataAsInt(_T("SchemaVersion"));
190 }
191
192 if ((version <= 0) || (version > DB_SCHEMA_VERSION))
193 {
194 nxlog_write(MSG_LOCAL_DB_CORRUPTED, NXLOG_ERROR, NULL);
5e12ef62 195 return false;
c72b812a 196 }
fe00bd6f 197
d78e89be
VK
198 if (version < DB_SCHEMA_VERSION)
199 {
200 if (!UpgradeDatabase())
201 {
202 version = ReadMetadataAsInt(_T("SchemaVersion"));
203 nxlog_debug(1, _T("Local database schema version is %d and cannot be upgraded to %d"), version, DB_SCHEMA_VERSION);
204 nxlog_write(MSG_LOCAL_DB_CORRUPTED, NXLOG_ERROR, NULL);
205 return false;
206 }
207 }
208
fe00bd6f
VK
209 bool success = true;
210 for(int i = 0; s_dbTables[i] != NULL; i++)
211 {
212 if (!DBIsTableExist(s_db, s_dbTables[i]))
213 {
214 nxlog_debug(1, _T("Local database table %s does not exist"), s_dbTables[i]);
215 success = false;
216 }
217 }
218 if (!success)
219 {
220 nxlog_write(MSG_LOCAL_DB_CORRUPTED, NXLOG_ERROR, NULL);
221 return false;
222 }
223
5e12ef62 224 return true;
c72b812a
VK
225}
226
227/**
228 * Open local agent database
229 */
230bool OpenLocalDatabase()
231{
2df047f4 232 s_driver = DBLoadDriver(_T("sqlite.ddr"), _T(""), nxlog_get_debug_level() == 9, NULL, NULL);
c72b812a
VK
233 if (s_driver == NULL)
234 {
235 return false;
236 }
237
238 TCHAR dbFile[MAX_PATH];
239 nx_strncpy(dbFile, g_szDataDirectory, MAX_PATH - 12);
240 if (dbFile[_tcslen(dbFile) - 1] != FS_PATH_SEPARATOR_CHAR)
241 _tcscat(dbFile, FS_PATH_SEPARATOR);
242 _tcscat(dbFile, _T("nxagentd.db"));
c99dbf89
VK
243 if (g_dwFlags & AF_SUBAGENT_LOADER)
244 {
245 _tcscat(dbFile, _T("."));
246 _tcscat(dbFile, g_masterAgent);
247 }
c72b812a
VK
248
249 TCHAR errorText[DBDRV_MAX_ERROR_TEXT];
250 s_db = DBConnect(s_driver, NULL, dbFile, NULL, NULL, NULL, errorText);
251 if (s_db == NULL)
252 {
fe00bd6f 253 nxlog_debug(1, _T("Local database open error: %s"), errorText);
c5459490 254 g_failFlags |= FAIL_OPEN_DATABASE;
c72b812a
VK
255 return false;
256 }
257
d78e89be 258 if (!CheckDatabaseStructure())
5e12ef62 259 {
c5459490 260 g_failFlags |= FAIL_UPGRADE_DATABASE;
5e12ef62
VK
261 DBDisconnect(s_db);
262 s_db = NULL;
49c0f4a9 263 return false;
5e12ef62
VK
264 }
265
89d79e7b 266 if (g_longRunningQueryThreshold != 0)
267 DBSetLongRunningThreshold(g_longRunningQueryThreshold);
268
5e12ef62 269 DBQuery(s_db, _T("VACUUM"));
c99dbf89 270 DebugPrintf(INVALID_INDEX, 1, _T("Local database opened successfully"));
c72b812a
VK
271 return true;
272}
273
274/**
275 * Close local database
276 */
277void CloseLocalDatabase()
278{
279 DBDisconnect(s_db);
280 DBUnloadDriver(s_driver);
281}
282
283/**
284 * Get database handle
285 */
286DB_HANDLE GetLocalDatabaseHandle()
287{
288 return s_db;
289}