From 7434848fb1f1e9edaed025c46ce23992161ada56 Mon Sep 17 00:00:00 2001 From: Gerhard Haering Date: Tue, 26 Oct 2010 17:08:47 +0200 Subject: [PATCH] implemented backup functionality --- setup.py | 2 +- src/backup.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++ src/backup.h | 43 +++++++++++++++ src/connection.c | 36 +++++++++++++ src/module.c | 2 + 5 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 src/backup.c create mode 100644 src/backup.h diff --git a/setup.py b/setup.py index 6a590ab..0e46f08 100644 --- a/setup.py +++ b/setup.py @@ -37,7 +37,7 @@ sources = ["src/module.c", "src/connection.c", "src/cursor.c", "src/cache.c", "src/microprotocols.c", "src/prepare_protocol.c", "src/statement.c", - "src/util.c", "src/row.c"] + "src/util.c", "src/row.c", "src/backup.c"] include_dirs = [] library_dirs = [] diff --git a/src/backup.c b/src/backup.c new file mode 100644 index 0000000..bcdde6d --- /dev/null +++ b/src/backup.c @@ -0,0 +1,134 @@ +/* backup.c - the backup type + * + * Copyright (C) 2010 Gerhard Häring + * + * This file is part of pysqlite. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#include "module.h" +#include "backup.h" +#include "sqlitecompat.h" + +void pysqlite_backup_dealloc(pysqlite_Backup* self) +{ + int rc; + + if (self->backup) { + Py_BEGIN_ALLOW_THREADS + rc = sqlite3_backup_finish(self->backup); + Py_END_ALLOW_THREADS + + Py_DECREF(self->source_con); + Py_DECREF(self->dest_con); + + self->backup = NULL; + } + + Py_TYPE(self)->tp_free((PyObject*)self); +} + +PyObject* pysqlite_backup_step(pysqlite_Backup* self, PyObject* args, PyObject* kwargs) +{ + int npages; + + if (!PyArg_ParseTuple(args, "i", &npages)) { + return NULL; + } + + int rc = sqlite3_backup_step(self->backup, npages); + + if (rc == SQLITE_DONE) { + Py_RETURN_TRUE; + } else if (rc == SQLITE_OK) { + Py_RETURN_FALSE; + } else { + PyErr_SetString(pysqlite_OperationalError, sqlite3_errmsg(self->source_con->db)); + return NULL; + } +} + +static PyObject* pysqlite_backup_get_remaining(pysqlite_Backup* self, void* unused) +{ + return Py_BuildValue("i", sqlite3_backup_remaining(self->backup)); +} + +static PyObject* pysqlite_backup_get_pagecount(pysqlite_Backup* self, void* unused) +{ + return Py_BuildValue("i", sqlite3_backup_remaining(self->backup)); +} + +static PyGetSetDef pysqlite_backup_getset[] = { + {"remaining", (getter)pysqlite_backup_get_remaining, (setter)0}, + {"pagecount", (getter)pysqlite_backup_get_pagecount, (setter)0}, + {NULL} +}; + +static PyMethodDef pysqlite_backup_methods[] = { + {"step", (PyCFunction)pysqlite_backup_step, METH_VARARGS, + PyDoc_STR("Copy pages to backup database.")}, + {NULL, NULL} +}; + +PyTypeObject pysqlite_BackupType = { + PyVarObject_HEAD_INIT(NULL, 0) + MODULE_NAME ".Backup", /* tp_name */ + sizeof(pysqlite_Backup), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)pysqlite_backup_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + pysqlite_backup_methods, /* tp_methods */ + 0, /* tp_members */ + pysqlite_backup_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0 /* tp_free */ +}; + +extern int pysqlite_backup_setup_types(void) +{ + pysqlite_BackupType.tp_new = PyType_GenericNew; + return PyType_Ready(&pysqlite_BackupType); +} diff --git a/src/backup.h b/src/backup.h new file mode 100644 index 0000000..10720f0 --- /dev/null +++ b/src/backup.h @@ -0,0 +1,43 @@ +/* backup.h - definitions for the backup type + * + * Copyright (C) 2010 Gerhard Häring + * + * This file is part of pysqlite. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#ifndef PYSQLITE_BACKUP_H +#define PYSQLITE_BACKUP_H +#include "Python.h" + +#include "sqlite3.h" +#include "connection.h" + +typedef struct +{ + PyObject_HEAD + sqlite3_backup* backup; + pysqlite_Connection* source_con; + pysqlite_Connection* dest_con; +} pysqlite_Backup; + +extern PyTypeObject pysqlite_BackupType; + +int pysqlite_backup_setup_types(void); + +#endif diff --git a/src/connection.c b/src/connection.c index 8861462..4c1a988 100644 --- a/src/connection.c +++ b/src/connection.c @@ -21,6 +21,7 @@ * 3. This notice may not be removed or altered from any source distribution. */ +#include "backup.h" #include "cache.h" #include "module.h" #include "connection.h" @@ -351,6 +352,39 @@ PyObject* pysqlite_connection_cursor(pysqlite_Connection* self, PyObject* args, return cursor; } +PyObject* pysqlite_connection_backup(pysqlite_Connection* self, PyObject* args, PyObject* kwargs) +{ + static char *kwlist[] = {"dest_db", "source_name", "dest_db_name", NULL, NULL}; + char* source_name; + char* dest_name; + pysqlite_Connection* dest_con; + pysqlite_Backup* backup; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!ss", kwlist, + &pysqlite_ConnectionType, &dest_con, &source_name, &dest_name)) { + return NULL; + } + + if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { + return NULL; + } + + backup = PyObject_New(pysqlite_Backup, &pysqlite_BackupType); + if (!backup) { + return NULL; + } + + Py_INCREF(self); + backup->source_con = self; + + Py_INCREF(dest_con); + backup->dest_con = dest_con; + + backup->backup = sqlite3_backup_init(dest_con->db, dest_name, self->db, source_name); + + return (PyObject*)backup; +} + PyObject* pysqlite_connection_close(pysqlite_Connection* self, PyObject* args) { PyObject* ret; @@ -1554,6 +1588,8 @@ static PyGetSetDef connection_getset[] = { }; static PyMethodDef connection_methods[] = { + {"backup", (PyCFunction)pysqlite_connection_backup, METH_VARARGS|METH_KEYWORDS, + PyDoc_STR("Backup database.")}, {"cursor", (PyCFunction)pysqlite_connection_cursor, METH_VARARGS|METH_KEYWORDS, PyDoc_STR("Return a cursor for the connection.")}, {"close", (PyCFunction)pysqlite_connection_close, METH_NOARGS, diff --git a/src/module.c b/src/module.c index 8794809..ded2635 100644 --- a/src/module.c +++ b/src/module.c @@ -24,6 +24,7 @@ #include "connection.h" #include "statement.h" #include "cursor.h" +#include "backup.h" #include "cache.h" #include "prepare_protocol.h" #include "microprotocols.h" @@ -314,6 +315,7 @@ PyMODINIT_FUNC init_sqlite(void) (pysqlite_connection_setup_types() < 0) || (pysqlite_cache_setup_types() < 0) || (pysqlite_statement_setup_types() < 0) || + (pysqlite_backup_setup_types() < 0) || (pysqlite_prepare_protocol_setup_types() < 0) ) { return;