Add support for more SQLite database open options. (#565)

* Add support for in-memory SQLite databases.

* Add support for opening SQLite databases via file URI.
This commit is contained in:
Nicholas Hastings 2016-12-04 11:23:08 -05:00 committed by GitHub
parent 19db7aef46
commit 70d81430f8
2 changed files with 70 additions and 58 deletions

View File

@ -12,7 +12,9 @@ elif binary.compiler.vendor == 'msvc':
binary.compiler.defines += [ binary.compiler.defines += [
'SQLITE_OMIT_LOAD_EXTENSION', 'SQLITE_OMIT_LOAD_EXTENSION',
'SQLITE_THREADSAFE' 'SQLITE_THREADSAFE',
'SQLITE_USE_URI',
'SQLITE_ALLOW_URI_AUTHORITY',
] ]
if builder.target_platform == 'linux': if builder.target_platform == 'linux':
binary.compiler.postlink += ['-ldl', '-lpthread'] binary.compiler.postlink += ['-ldl', '-lpthread']

View File

@ -33,6 +33,7 @@
#include "extension.h" #include "extension.h"
#include "SqDriver.h" #include "SqDriver.h"
#include "SqDatabase.h" #include "SqDatabase.h"
#include <am-string.h>
SqDriver g_SqDriver; SqDriver g_SqDriver;
@ -179,70 +180,79 @@ IDatabase *SqDriver::Connect(const DatabaseInfo *info, bool persistent, char *er
{ {
ke::AutoLock lock(&m_OpenLock); ke::AutoLock lock(&m_OpenLock);
/* Format our path */ /* Full path to the database file */
char path[PLATFORM_MAX_PATH];
size_t len = libsys->PathFormat(path, sizeof(path), "sqlite/%s", info->database);
/* Chop any filename off */
for (size_t i = len-1;
i <= len-1;
i--)
{
if (IsPathSepChar(path[i]))
{
path[i] = '\0';
break;
}
}
/* Test the full path */
char fullpath[PLATFORM_MAX_PATH]; char fullpath[PLATFORM_MAX_PATH];
g_pSM->BuildPath(Path_SM, fullpath, sizeof(fullpath), "data/%s", path);
if (!libsys->IsPathDirectory(fullpath)) if (strcmp(info->database, ":memory:") == 0 || strncmp(info->database, "file:", 5) == 0)
{ {
/* Make sure the data folder exists */ ke::SafeStrcpy(fullpath, sizeof(fullpath), info->database);
len = g_pSM->BuildPath(Path_SM, fullpath, sizeof(fullpath), "data"); }
if (!libsys->IsPathDirectory(fullpath)) else
{ {
if (!libsys->CreateFolder(fullpath)) /* Format our path */
{ char path[PLATFORM_MAX_PATH];
strncopy(error, "Could not create or open \"data\" folder\"", maxlength); size_t len = libsys->PathFormat(path, sizeof(path), "sqlite/%s", info->database);
return NULL;
}
}
/* The data folder exists - create each subdir as needed! */ /* Chop any filename off */
char *cur_ptr = path; for (size_t i = len-1;
i <= len-1;
do i--)
{ {
/* Find the next suitable path */ if (IsPathSepChar(path[i]))
char *next_ptr = cur_ptr;
while (*next_ptr != '\0')
{
if (IsPathSepChar(*next_ptr))
{
*next_ptr = '\0';
next_ptr++;
break;
}
next_ptr++;
}
if (*next_ptr == '\0')
{
next_ptr = NULL;
}
len += libsys->PathFormat(&fullpath[len], sizeof(fullpath)-len, "/%s", cur_ptr);
if (!libsys->IsPathDirectory(fullpath) && !libsys->CreateFolder(fullpath))
{ {
path[i] = '\0';
break; break;
} }
cur_ptr = next_ptr; }
} while (cur_ptr);
}
/* Build the FINAL path. */ /* Test the full path */
g_pSM->BuildPath(Path_SM, fullpath, sizeof(fullpath), "data/sqlite/%s.sq3", info->database); g_pSM->BuildPath(Path_SM, fullpath, sizeof(fullpath), "data/%s", path);
if (!libsys->IsPathDirectory(fullpath))
{
/* Make sure the data folder exists */
len = g_pSM->BuildPath(Path_SM, fullpath, sizeof(fullpath), "data");
if (!libsys->IsPathDirectory(fullpath))
{
if (!libsys->CreateFolder(fullpath))
{
strncopy(error, "Could not create or open \"data\" folder\"", maxlength);
return NULL;
}
}
/* The data folder exists - create each subdir as needed! */
char *cur_ptr = path;
do
{
/* Find the next suitable path */
char *next_ptr = cur_ptr;
while (*next_ptr != '\0')
{
if (IsPathSepChar(*next_ptr))
{
*next_ptr = '\0';
next_ptr++;
break;
}
next_ptr++;
}
if (*next_ptr == '\0')
{
next_ptr = NULL;
}
len += libsys->PathFormat(&fullpath[len], sizeof(fullpath)-len, "/%s", cur_ptr);
if (!libsys->IsPathDirectory(fullpath) && !libsys->CreateFolder(fullpath))
{
break;
}
cur_ptr = next_ptr;
} while (cur_ptr);
}
/* Build the FINAL path. */
g_pSM->BuildPath(Path_SM, fullpath, sizeof(fullpath), "data/sqlite/%s.sq3", info->database);
}
/* If we're requesting a persistent connection, see if something is already open */ /* If we're requesting a persistent connection, see if something is already open */
if (persistent) if (persistent)