1//
2// Utility.cpp
3//
4// Library: SQL/SQLite
5// Package: SQLite
6// Module: Utility
7//
8// Implementation of Utility
9//
10// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
11// and Contributors.
12//
13// SPDX-License-Identifier: BSL-1.0
14//
15
16
17#include "Poco/SQL/SQLite/Utility.h"
18#include "Poco/SQL/SQLite/SQLiteException.h"
19#include "Poco/NumberFormatter.h"
20#include "Poco/String.h"
21#include "Poco/Any.h"
22#include "Poco/Exception.h"
23#if defined(POCO_UNBUNDLED)
24#include <sqlite3.h>
25#else
26#include "sqlite3.h"
27#endif
28
29
30#ifndef SQLITE_OPEN_URI
31#define SQLITE_OPEN_URI 0
32#endif
33
34
35namespace Poco {
36namespace SQL {
37namespace SQLite {
38
39
40const int Utility::THREAD_MODE_SINGLE = SQLITE_CONFIG_SINGLETHREAD;
41const int Utility::THREAD_MODE_MULTI = SQLITE_CONFIG_MULTITHREAD;
42const int Utility::THREAD_MODE_SERIAL = SQLITE_CONFIG_SERIALIZED;
43int Utility::_threadMode =
44#if (SQLITE_THREADSAFE == 0)
45 SQLITE_CONFIG_SINGLETHREAD;
46#elif (SQLITE_THREADSAFE == 1)
47 SQLITE_CONFIG_SERIALIZED;
48#elif (SQLITE_THREADSAFE == 2)
49 SQLITE_CONFIG_MULTITHREAD;
50#endif
51
52const int Utility::OPERATION_INSERT = SQLITE_INSERT;
53const int Utility::OPERATION_DELETE = SQLITE_DELETE;
54const int Utility::OPERATION_UPDATE = SQLITE_UPDATE;
55
56const std::string Utility::SQLITE_DATE_FORMAT = "%Y-%m-%d";
57const std::string Utility::SQLITE_TIME_FORMAT = "%H:%M:%S";
58Utility::TypeMap Utility::_types;
59Poco::Mutex Utility::_mutex;
60
61
62Utility::SQLiteMutex::SQLiteMutex(sqlite3* pDB): _pMutex((pDB) ? sqlite3_db_mutex(pDB) : 0)
63{
64 if (_pMutex)
65 sqlite3_mutex_enter(_pMutex);
66}
67
68
69Utility::SQLiteMutex::~SQLiteMutex()
70{
71 if (_pMutex)
72 sqlite3_mutex_leave(_pMutex);
73}
74
75
76Utility::Utility()
77{
78 initializeDefaultTypes();
79}
80
81
82void Utility::initializeDefaultTypes()
83{
84 if (_types.empty())
85 {
86 _types.insert(TypeMap::value_type("", MetaColumn::FDT_STRING));
87 _types.insert(TypeMap::value_type("BOOL", MetaColumn::FDT_BOOL));
88 _types.insert(TypeMap::value_type("BOOLEAN", MetaColumn::FDT_BOOL));
89 _types.insert(TypeMap::value_type("BIT", MetaColumn::FDT_BOOL));
90 _types.insert(TypeMap::value_type("UINT8", MetaColumn::FDT_UINT8));
91 _types.insert(TypeMap::value_type("UTINY", MetaColumn::FDT_UINT8));
92 _types.insert(TypeMap::value_type("UINTEGER8", MetaColumn::FDT_UINT8));
93 _types.insert(TypeMap::value_type("INT8", MetaColumn::FDT_INT8));
94 _types.insert(TypeMap::value_type("TINY", MetaColumn::FDT_INT8));
95 _types.insert(TypeMap::value_type("INTEGER8", MetaColumn::FDT_INT8));
96 _types.insert(TypeMap::value_type("UINT16", MetaColumn::FDT_UINT16));
97 _types.insert(TypeMap::value_type("USHORT", MetaColumn::FDT_UINT16));
98 _types.insert(TypeMap::value_type("UINTEGER16", MetaColumn::FDT_UINT16));
99 _types.insert(TypeMap::value_type("INT16", MetaColumn::FDT_INT16));
100 _types.insert(TypeMap::value_type("SHORT", MetaColumn::FDT_INT16));
101 _types.insert(TypeMap::value_type("INTEGER16", MetaColumn::FDT_INT16));
102 _types.insert(TypeMap::value_type("UINT", MetaColumn::FDT_UINT32));
103 _types.insert(TypeMap::value_type("UINT32", MetaColumn::FDT_UINT32));
104 _types.insert(TypeMap::value_type("UINTEGER32", MetaColumn::FDT_UINT32));
105 _types.insert(TypeMap::value_type("INT", MetaColumn::FDT_INT32));
106 _types.insert(TypeMap::value_type("INT32", MetaColumn::FDT_INT32));
107 _types.insert(TypeMap::value_type("INTEGER", MetaColumn::FDT_INT64));
108 _types.insert(TypeMap::value_type("INTEGER32", MetaColumn::FDT_INT32));
109 _types.insert(TypeMap::value_type("UINT64", MetaColumn::FDT_UINT64));
110 _types.insert(TypeMap::value_type("ULONG", MetaColumn::FDT_INT64));
111 _types.insert(TypeMap::value_type("UINTEGER64", MetaColumn::FDT_UINT64));
112 _types.insert(TypeMap::value_type("INT64", MetaColumn::FDT_INT64));
113 _types.insert(TypeMap::value_type("LONG", MetaColumn::FDT_INT64));
114 _types.insert(TypeMap::value_type("INTEGER64", MetaColumn::FDT_INT64));
115 _types.insert(TypeMap::value_type("TINYINT", MetaColumn::FDT_INT8));
116 _types.insert(TypeMap::value_type("SMALLINT", MetaColumn::FDT_INT16));
117 _types.insert(TypeMap::value_type("BIGINT", MetaColumn::FDT_INT64));
118 _types.insert(TypeMap::value_type("LONGINT", MetaColumn::FDT_INT64));
119 _types.insert(TypeMap::value_type("COUNTER", MetaColumn::FDT_UINT64));
120 _types.insert(TypeMap::value_type("AUTOINCREMENT", MetaColumn::FDT_UINT64));
121 _types.insert(TypeMap::value_type("REAL", MetaColumn::FDT_DOUBLE));
122 _types.insert(TypeMap::value_type("FLOA", MetaColumn::FDT_DOUBLE));
123 _types.insert(TypeMap::value_type("FLOAT", MetaColumn::FDT_DOUBLE));
124 _types.insert(TypeMap::value_type("DOUB", MetaColumn::FDT_DOUBLE));
125 _types.insert(TypeMap::value_type("DOUBLE", MetaColumn::FDT_DOUBLE));
126 _types.insert(TypeMap::value_type("DECIMAL", MetaColumn::FDT_DOUBLE));
127 _types.insert(TypeMap::value_type("NUMERIC", MetaColumn::FDT_DOUBLE));
128 _types.insert(TypeMap::value_type("CHAR", MetaColumn::FDT_STRING));
129 _types.insert(TypeMap::value_type("CLOB", MetaColumn::FDT_STRING));
130 _types.insert(TypeMap::value_type("TEXT", MetaColumn::FDT_STRING));
131 _types.insert(TypeMap::value_type("VARCHAR", MetaColumn::FDT_STRING));
132 _types.insert(TypeMap::value_type("NCHAR", MetaColumn::FDT_STRING));
133 _types.insert(TypeMap::value_type("NCLOB", MetaColumn::FDT_STRING));
134 _types.insert(TypeMap::value_type("NTEXT", MetaColumn::FDT_STRING));
135 _types.insert(TypeMap::value_type("NVARCHAR", MetaColumn::FDT_STRING));
136 _types.insert(TypeMap::value_type("LONGVARCHAR", MetaColumn::FDT_STRING));
137 _types.insert(TypeMap::value_type("BLOB", MetaColumn::FDT_BLOB));
138 _types.insert(TypeMap::value_type("DATE", MetaColumn::FDT_DATE));
139 _types.insert(TypeMap::value_type("TIME", MetaColumn::FDT_TIME));
140 _types.insert(TypeMap::value_type("DATETIME", MetaColumn::FDT_TIMESTAMP));
141 _types.insert(TypeMap::value_type("TIMESTAMP", MetaColumn::FDT_TIMESTAMP));
142 }
143}
144
145
146void Utility::addColumnType(std::string sqliteType, MetaColumn::ColumnDataType pocoType)
147{
148 // Check for errors in the mapping
149 if (MetaColumn::FDT_UNKNOWN == pocoType)
150 throw Poco::SQL::NotSupportedException("Cannot map to unknown poco type.");
151
152 // Initialize default types
153 initializeDefaultTypes();
154
155 // Add type to internal map
156 Poco::toUpperInPlace(sqliteType);
157 _types[sqliteType] = pocoType;
158}
159
160
161std::string Utility::lastError(sqlite3* pDB)
162{
163 std::string errStr;
164 SQLiteMutex m(pDB);
165 const char* pErr = sqlite3_errmsg(pDB);
166 if (pErr) errStr = pErr;
167 return errStr;
168}
169
170
171MetaColumn::ColumnDataType Utility::getColumnType(sqlite3_stmt* pStmt, std::size_t pos)
172{
173 poco_assert_dbg (pStmt);
174
175 // Ensure statics are initialized
176 {
177 Poco::Mutex::ScopedLock lock(_mutex);
178 static Utility u;
179 }
180
181 const char* pc = sqlite3_column_decltype(pStmt, (int) pos);
182 std::string sqliteType = pc ? pc : "";
183 Poco::toUpperInPlace(sqliteType);
184 sqliteType = sqliteType.substr(0, sqliteType.find_first_of(" ("));
185
186 TypeMap::const_iterator it = _types.find(Poco::trimInPlace(sqliteType));
187 if (_types.end() == it)
188 return MetaColumn::FDT_BLOB;
189 else
190 return it->second;
191}
192
193
194void Utility::throwException(sqlite3* pDB, int rc, const std::string& addErrMsg)
195{
196 switch (rc)
197 {
198 case SQLITE_OK:
199 break;
200 case SQLITE_ERROR:
201 throw InvalidSQLStatementException(lastError(pDB), addErrMsg);
202 case SQLITE_INTERNAL:
203 throw InternalDBErrorException(lastError(pDB), addErrMsg);
204 case SQLITE_PERM:
205 throw DBAccessDeniedException(lastError(pDB), addErrMsg);
206 case SQLITE_ABORT:
207 throw ExecutionAbortedException(lastError(pDB), addErrMsg);
208 case SQLITE_BUSY:
209 case SQLITE_BUSY_RECOVERY:
210#if defined(SQLITE_BUSY_SNAPSHOT)
211 case SQLITE_BUSY_SNAPSHOT:
212#endif
213 throw DBLockedException(lastError(pDB), addErrMsg);
214 case SQLITE_LOCKED:
215 throw TableLockedException(lastError(pDB), addErrMsg);
216 case SQLITE_NOMEM:
217 throw NoMemoryException(lastError(pDB), addErrMsg);
218 case SQLITE_READONLY:
219 throw ReadOnlyException(lastError(pDB), addErrMsg);
220 case SQLITE_INTERRUPT:
221 throw InterruptException(lastError(pDB), addErrMsg);
222 case SQLITE_IOERR:
223 throw IOErrorException(lastError(pDB), addErrMsg);
224 case SQLITE_CORRUPT:
225 throw CorruptImageException(lastError(pDB), addErrMsg);
226 case SQLITE_NOTFOUND:
227 throw TableNotFoundException(lastError(pDB), addErrMsg);
228 case SQLITE_FULL:
229 throw DatabaseFullException(lastError(pDB), addErrMsg);
230 case SQLITE_CANTOPEN:
231 throw CantOpenDBFileException(lastError(pDB), addErrMsg);
232 case SQLITE_PROTOCOL:
233 throw LockProtocolException(lastError(pDB), addErrMsg);
234 case SQLITE_EMPTY:
235 throw InternalDBErrorException(lastError(pDB), addErrMsg);
236 case SQLITE_SCHEMA:
237 throw SchemaDiffersException(lastError(pDB), addErrMsg);
238 case SQLITE_TOOBIG:
239 throw RowTooBigException(lastError(pDB), addErrMsg);
240 case SQLITE_CONSTRAINT:
241 throw ConstraintViolationException(lastError(pDB), addErrMsg);
242 case SQLITE_MISMATCH:
243 throw DataTypeMismatchException(lastError(pDB), addErrMsg);
244 case SQLITE_MISUSE:
245 throw InvalidLibraryUseException(lastError(pDB), addErrMsg);
246 case SQLITE_NOLFS:
247 throw OSFeaturesMissingException(lastError(pDB), addErrMsg);
248 case SQLITE_AUTH:
249 throw AuthorizationDeniedException(lastError(pDB), addErrMsg);
250 case SQLITE_FORMAT:
251 throw CorruptImageException(lastError(pDB), addErrMsg);
252 case SQLITE_NOTADB:
253 throw CorruptImageException(lastError(pDB), addErrMsg);
254 case SQLITE_RANGE:
255 throw InvalidSQLStatementException(lastError(pDB), addErrMsg);
256 case SQLITE_ROW:
257 break; // sqlite_step() has another row ready
258 case SQLITE_DONE:
259 break; // sqlite_step() has finished executing
260 default:
261 throw SQLiteException(Poco::format("Unknown error code: %d", rc), addErrMsg);
262 }
263}
264
265
266bool Utility::fileToMemory(sqlite3* pInMemory, const std::string& fileName)
267{
268 int rc;
269 sqlite3* pFile;
270 sqlite3_backup* pBackup;
271
272 rc = sqlite3_open_v2(fileName.c_str(), &pFile, SQLITE_OPEN_READONLY | SQLITE_OPEN_URI, NULL);
273 if(rc == SQLITE_OK )
274 {
275 pBackup = sqlite3_backup_init(pInMemory, "main", pFile, "main");
276 if( pBackup )
277 {
278 sqlite3_backup_step(pBackup, -1);
279 sqlite3_backup_finish(pBackup);
280 }
281 rc = sqlite3_errcode(pFile);
282 }
283
284 sqlite3_close(pFile);
285 return SQLITE_OK == rc;
286}
287
288
289bool Utility::memoryToFile(const std::string& fileName, sqlite3* pInMemory)
290{
291 int rc;
292 sqlite3* pFile;
293 sqlite3_backup* pBackup;
294
295 rc = sqlite3_open_v2(fileName.c_str(), &pFile, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_URI, NULL);
296 if(rc == SQLITE_OK )
297 {
298 pBackup = sqlite3_backup_init(pFile, "main", pInMemory, "main");
299 if( pBackup )
300 {
301 sqlite3_backup_step(pBackup, -1);
302 sqlite3_backup_finish(pBackup);
303 }
304 rc = sqlite3_errcode(pFile);
305 }
306
307 sqlite3_close(pFile);
308 return SQLITE_OK == rc;
309}
310
311
312bool Utility::isThreadSafe()
313{
314 return 0 != sqlite3_threadsafe();
315}
316
317
318int Utility::getThreadMode()
319{
320 return _threadMode;
321}
322
323
324bool Utility::setThreadMode(int mode)
325{
326#if (SQLITE_THREADSAFE != 0)
327 if (SQLITE_OK == sqlite3_shutdown())
328 {
329 if (SQLITE_OK == sqlite3_config(mode))
330 {
331 _threadMode = mode;
332 if (SQLITE_OK == sqlite3_initialize())
333 return true;
334 }
335 sqlite3_initialize();
336 }
337#endif
338 return false;
339}
340
341
342void* Utility::eventHookRegister(sqlite3* pDB, UpdateCallbackType callbackFn, void* pParam)
343{
344 typedef void(*pF)(void*, int, const char*, const char*, sqlite3_int64);
345 return sqlite3_update_hook(pDB, reinterpret_cast<pF>(callbackFn), pParam);
346}
347
348
349void* Utility::eventHookRegister(sqlite3* pDB, CommitCallbackType callbackFn, void* pParam)
350{
351 return sqlite3_commit_hook(pDB, callbackFn, pParam);
352}
353
354
355void* Utility::eventHookRegister(sqlite3* pDB, RollbackCallbackType callbackFn, void* pParam)
356{
357 return sqlite3_rollback_hook(pDB, callbackFn, pParam);
358}
359
360
361// NOTE: Utility::dbHandle() has been moved to SessionImpl.cpp,
362// as a workaround for a failing AnyCast with Clang.
363// See <https://github.com/pocoproject/poco/issues/578>
364// for a discussion.
365
366
367} } } // namespace Poco::SQL::SQLite
368