Чистая резервная копия Python для базы данных SQLite3 с памятью на диск

Не устанавливая дополнительные модули, как я могу использовать API резервного копирования SQLite для резервного копирования базы данных в памяти в базу данных на диске? Мне удалось успешно выполнить резервное копирование на диск-диск, но проблема с уже существующим подключением в памяти к функции sqlite3_backup_init.

Мой пример с игрушкой, адаптированный с https://gist.github.com/achimnol/3021995 и сокращенный до минимума, выглядит следующим образом:

import sqlite3
import ctypes

# Create a junk in-memory database
sourceconn = sqlite3.connect(':memory:')
cursor = sourceconn.cursor()
cursor.execute('''CREATE TABLE stocks
 (date text, trans text, symbol text, qty real, price real)''')
cursor.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)")
sourceconn.commit()

target = r'C:\data\sqlite\target.db'
dllpath = u'C:\\Python27\DLLs\\sqlite3.dll'

# Constants from the SQLite 3 API defining various return codes of state.
SQLITE_OK = 0
SQLITE_ERROR = 1
SQLITE_BUSY = 5
SQLITE_LOCKED = 6
SQLITE_OPEN_READONLY = 1
SQLITE_OPEN_READWRITE = 2
SQLITE_OPEN_CREATE = 4

# Tweakable variables
pagestocopy = 20
millisecondstosleep = 100

# dllpath = ctypes.util.find_library('sqlite3') # I had ******* with this on Windows
sqlitedll = ctypes.CDLL(dllpath)
sqlitedll.sqlite3_backup_init.restype = ctypes.c_void_p

# Setup some ctypes
p_src_db = ctypes.c_void_p(None)
p_dst_db = ctypes.c_void_p(None)
null_ptr = ctypes.c_void_p(None)

# Check to see if the first argument (source database) can be opened for reading.
# ret = sqlitedll.sqlite3_open_v2(sourceconn, ctypes.byref(p_src_db), SQLITE_OPEN_READONLY, null_ptr)
#assert ret == SQLITE_OK
#assert p_src_db.value is not None

# Check to see if the second argument (target database) can be opened for writing.
ret = sqlitedll.sqlite3_open_v2(target, ctypes.byref(p_dst_db), SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, null_ptr)
assert ret == SQLITE_OK
assert p_dst_db.value is not None

# Start a backup.
print 'Starting backup to SQLite database "%s" to SQLite database "%s" ...' % (sourceconn, target)
p_backup = sqlitedll.sqlite3_backup_init(p_dst_db, 'main', sourceconn, 'main')
print ' Backup handler: {0:#08x}'.format(p_backup)
assert p_backup is not None

# Step through a backup.
while True:
 ret = sqlitedll.sqlite3_backup_step(p_backup, pagestocopy)
 remaining = sqlitedll.sqlite3_backup_remaining(p_backup)
 pagecount = sqlitedll.sqlite3_backup_pagecount(p_backup)
 print ' Backup in progress: {0:.2f}%'.format((pagecount - remaining) / float(pagecount) * 100)
 if remaining == 0:
 break
 if ret in (SQLITE_OK, SQLITE_BUSY, SQLITE_LOCKED):
 sqlitedll.sqlite3_sleep(millisecondstosleep)

# Finish the bakcup
sqlitedll.sqlite3_backup_finish(p_backup)

# Close database connections
sqlitedll.sqlite3_close(p_dst_db)
sqlitedll.sqlite3_close(p_src_db)

Я получаю сообщение об ошибке ctypes.ArgumentError: argument 3: <type 'exceptions.typeerror'="">: Don't know how to convert parameter 3</type> в строку 49 (p_backup = sqlitedll.sqlite3_backup_init(p_dst_db, 'main', sourceconn, 'main')). Как-то мне нужно передать ссылку на базу данных в память на эту функцию sqlite3_backup_init.

Я не знаю достаточно C, чтобы понять специфику самого API.

Настройка: Windows 7, ActiveState Python 2.7

2 ответа

Доступ к базе данных в памяти можно получить только через библиотеку SQLite, которая ее создала (в данном случае, встроенный SQLite для Python).

Модуль Python sqlite3 не предоставляет доступ к API резервного копирования, поэтому копировать базу данных в памяти невозможно.

Вам нужно будет установить дополнительный модуль или использовать базу данных на диске в первую очередь.


Хотя это не является строго решением ваших вопросов (поскольку он не использует API-интерфейс резервного копирования), он служит минимальным усилием и хорошо работает для небольших баз данных памяти.

import os
import sqlite3

database = sqlite3.connect(':memory:')

# fill the in memory db with your data here

dbfile = 'dbcopy.db'
if os.path.exists(dbfile):
 os.remove(dbfile) # remove last db dump

new_db = sqlite3.connect(dbfile)
c = new_db.cursor() 
c.executescript("\r\n".join(database.iterdump()))
new_db.close()

licensed under cc by-sa 3.0 with attribution.