API de backup en línea
sqlite3_backup *sqlite3_backup_init( sqlite3 *pDest, /* Manipulador de base de datos de destino */ const char *zDestName, /* Nombre de base de datos de destino */ sqlite3 *pSource, /* Manipulador de base de datos de origen */ const char *zSourceName /* Nombre de base de datos de origen */ ); int sqlite3_backup_step(sqlite3_backup *p, int nPage); int sqlite3_backup_finish(sqlite3_backup *p); int sqlite3_backup_remaining(sqlite3_backup *p); int sqlite3_backup_pagecount(sqlite3_backup *p);
El API de backup copia el contenido de una base de datos a otra. Es útil para la creación de copias de seguridad de bases de datos o para copiar bases de datos en memoria a o desde ficheros persistentes.
SQLite mantiene una transacción de escritura abierta en la base de datos de destino mientras dura la operación de backup. La base de datos de origen está bloqueada sólo para lectura mientras está siendo leída; no está siempre bloqueada durante toda la operación de backup. Por lo tanto, la copia de seguridad puede realizarse en una base de datos de origen viva sin tener que prevenir otras conexiones que puedan leer o escribir en la base de datos origen mientras la copia de seguridad esté en marcha.
Para realizar una operación de copia de seguridad:
- Se invoca a sqlite3_backup_init() una vez para iniciar la copia de seguridad.
- Se invoca a sqlite3_backup_step() una o más veces para transferir los datos entre las dos bases de datos, finalmente.
- Se invoca a sqlite3_backup_finish() para liberar todos los recursos asociados con la operación de backup.
Debe haber exactamente una llamada a sqlite3_backup_finish() para cada llamada con éxito a sqlite3_backup_init().
sqlite3_backup_init()
Los argumentos D y N para sqlite3_backup_init(D,N,S,M) son la conexión de bases de datos asociada con la base de datos y su nombre, respectivamente. El nombre de base de datos es "main" para la base de datos principal, "temp" para la base de datos temporal, o el nombre especificado después de la palabra clave AS en la sentencia ATTACH para la base de datos conectada. Los argumentos S y M pasados a sqlite3_backup_init(D,N,S,M) identifican la conexión de la base de datos y el nombre de la base de datos de origen, respectivamente. Las conexiones de base de datos de origen y destino (parámetros S y D) deben ser diferentes o en caso contrario sqlite3_backup_init(D,N,S,M) fallará con un error.
Si se produce un error dentro de sqlite3_backup_init(D,N,S,M), se devuelve NULL y se almacena un código de error y un mensaje en la conexión de la base de datos de destino D. El código y el mensaje de error para la llamada fallida a sqlite3_backup_init() puede ser recuperado usando las funciones sqlite3_errcode(), sqlite3_errmsg(), y/o sqlite3_errmsg16(). Una llamada exitosa a sqlite3_backup_init() retorna un puntero a un objeto sqlite3_backup. El objeto sqlite3_backup puede ser usado por las funciones sqlite3_backup_step() y sqlite3_backup_finish() para realizar la operación de backup especificada.
sqlite3_backup_step()
La función sqlite3_backup_step(B,N) copiará N páginas entre las bases de datos de origen y destino especificadas por el objeto B de tipo sqlite3_backup. Si N es negativo, se copiarán todas las páginas que queden en la base de datos de origen. Si sqlite3_backup_step(B,N) copia N páginas con éxito y aún quedan páginas por copiar, la función retorna SQLITE_OK. Si sqlite3_backup_step(B,N) termina la copia de todas las páginas con éxito desde el origen al destino, entonces retorna con SQLITE_DONE. Si se produce un error mientras se ejecuta sqlite3_backup_step(B,N), se retorna un código de error. Además de SQLITE_OK y SQLITE_DONE, una llamada a sqlite3_backup_step() puede retornar los códigos de error extendidos SQLITE_READONLY, SQLITE_NOMEM, SQLITE_BUSY, SQLITE_LOCKED o SQLITE_IOERR_XXX.
The sqlite3_backup_step() podría retornar SQLITE_READONLY si:
- La base de datos de destino fue abierta en modo de sólo lectura, o
- La base de datos de destino está e uso para un diario de escritura anticipada de registro y los tamaños de página de destino y origen son diferentes, o
- La base de datos de destino es en memoria y los tamaños de página de destino y origen son diferentes.
Si sqlite3_backup_step() no puede obtener un bloqueo de fichero requerido, entonces se invoca a la función de está-ocupado (si se ha especificado una). Si la función está-ocupado retorna un valor no nulo antes de que el bloqueo esté disponible, entonces se devuelve SQLITE_BUSY. En ese caso la llamada a sqlite3_backup_step() se puede intentar de nuevo más tarde. Si la conexión con la base de datos origen está siendo usada para escribir en la base de datos cuando sqlite3_backup_step() es invocada, entonces se retorna SQLITE_LOCKED inmediatamente. De nuevo, en este caso la llamada a sqlite3_backup_step() se puede repetir de nuevo más tarde. Si se retorna SQLITE_IOERR_XXX, SQLITE_NOMEM o SQLITE_READONLY, no hay posibilidad de intentar una nueva llamada a sqlite3_backup_step(). Estos errores se consideran fatales. La aplicación debe aceptar que la operación de copia de seguridad ha fallado y pasar el manipulador de la operación a sqlite3_backup_finish() para liberar los recursos asociados.
La primera llamada a sqlite3_backup_step() obtiene un bloqueo exclusivo sobre el fichero de destino. Ese bloqueo no se libera hasta que se invoque a sqlite3_backup_finish() o la operación de backup se complete y sqlite3_backup_step() retorne con SQLITE_DONE. Todas las llamadas a sqlite3_backup_step() obtienen un bloqueo compartido sobre la base de datos de origen que se mantiene durante la ejecución de sqlite3_backup_step(). Como la base de datos de origen no está bloqueada entre distintas llamadas a sqlite3_backup_step(), la base de datos de origen puede ser modificada durante el proceso de copia de seguridad. Si esa base de datos es modificada por un proceso externo o mediante una conexión a base de datos distinta de la usada para la operación de copia de seguridad, entonces la copia de seguridad será reiniciada automáticamente por la siguiente llamada a sqlite3_backup_step(). Si la base de datos de origen es modificada usando la misma conexión que se usa para la operación de copia de seguridad, entonces la base de datos de backup se actualiza automáticamente al mismo tiempo.
sqlite3_backup_finish()
Cuando sqlite3_backup_step() ha retornado SQLITE_DONE, o cuando la aplicación desea abandonar la operación de copia de seguridad, la aplicación debe destruir el objeto sqlite3_backup pasándoselo a sqlite3_backup_finish(). El interfaz sqlite3_backup_finish() libera todos los recursos asociados con el objeto sqlite3_backup. Si sqlite3_backup_step() no ha devuelto aún SQLITE_DONE, se anulará cualquier transacción de escritura activa en la base de datos de destino. El objeto sqlite3_backup será inválido y no puede ser usado después de una llamada a sqlite3_backup_finish().
El valor retornado por sqlite3_backup_finish es SQLITE_OK si no se han producido errore en sqlite3_backup_step(), si importar si sqlite3_backup_step() se ha completado o no. Si se ha producido una falta de memoria o un error de entrada-salida durante una llamada previa a sqlite3_backup_step() con el mismo objeto sqlite3_backup, entonces sqlite3_backup_finish() retorna con el código de error correspondiente.
Un valor de retorno desde sqlite3_backup_step() de SQLITE_BUSY o SQLITE_LOCKED no es un error permanente y no afecta al valor de retorno de sqlite3_backup_finish().
sqlite3_backup_remaining() y sqlite3_backup_pagecount()
Cada llamada a sqlite3_backup_step() actualiza dos valores dentro del objeto sqlite3_backup: el número de páginas que aún quedan por copiar y el número total de páginas en el fichero de base de datos de origen. Los interfaces sqlite3_backup_remaining() y sqlite3_backup_pagecount() recuperan esos dos valores, respectivamente.
Los valores retornados por esas funciones sólo son actualizados por sqlite3_backup_step(). Si la base de datos de origen es modificada durante la operación de copia de seguridad, entonces los valores no son actualizados para tener en cuenta cualquier página extra que necesite ser actualizada o si el tamaño del fichero de la base de datos ha cambiado.
Uso concurrente de manipuladores de base de datos
La conexión de la base de datos origen puede ser usada por la aplicación para otros propósitos mientras una operación de copia de seguridad está en marcha o se está inicializando. Si SQLite está compilado y configurado para soportar conexiones de base de datos multihilo, entonces la conexión de la base de datos origen puede ser usada concurrentemente por otros subprocesos.
Sin embargo, la aplicación debe garantizar que la conexión con la base de datos de destino no sea pasada a ninguna otra función del API (por ningún hilo) desde el momento en que sqlite3_backup_init() es invocada hasta que se invoque su correspondiente sqlite3_backup_finish(). Actualmente SQLite no hace verificaciones para comprobar si la aplicación accede incorrectamente a la conexión de base de datos de destino de modo que no se genera ningún código de error, sin embargo las operaciones no funcionaran correctamente. El uso de la conexión de base de datos de destino mientras hay una copia de seguridad en curso pueden provocar además un bloqueo del mutex.
Si se ejecuta en modo de caché compartida, la aplicación debe garantizar que la caché compartida usada por la base de datos de destino no es accedida mientras la copia de seguidad se está ejecutando. En la práctica esto significa que la aplicación debe garantizar que el fichero de disco que se está copiando no sea accedido por ninguna conexión dentro del proceso, no sólo la conexión expecífica que se ha pasado a sqlite3_backup_init().
El propio objeto sqlite3_backup es parcialmente multihilo. Varios hilos pueden hacer con seguridad múltiples llamadas concurrentes a sqlite3_backup_step(). Sin embargo, la funciones sqlite3_backup_remaining() y sqlite3_backup_pagecount() no son multihilo estrictamente hablando. Si son invocadas al mismo tiempo que otro hilo está invocando a sqlite3_backup_step() es posible que retornen valores no válidos.