Abstracted the DB layer for use by Zotero utilities
All the former Zotero.DB methods are now part of an instantiable Zotero.DBConnection object, and Zotero.DB is just one instance of it. Utilities can create and access a new SQLite database within the Zotero data folder by instantiating the DBConnection object: this.DB = new Zotero.DBConnection('myutility'); Utilities have access to everything the DB layer provides, including automatic backup and restore of databases. Utility writers are on their own for schema management, at least for now. Also: - Cleared non-English DB restore localized strings after change. - Disabled shutdown observer in Zotero object after moving DB backup code to DB layer
This commit is contained in:
parent
f35f9f4827
commit
49b0f28f26
|
@ -20,40 +20,28 @@
|
|||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
Zotero.DB = new function(){
|
||||
Zotero.DBConnection = function(dbName) {
|
||||
if (!dbName) {
|
||||
throw ('DB name not provided in Zotero.DBConnection()');
|
||||
}
|
||||
|
||||
// Private members
|
||||
var _connection;
|
||||
var _transactionRollback;
|
||||
var _transactionNestingLevel = 0;
|
||||
var _callbacks = { begin: [], commit: [], rollback: [] };
|
||||
this._dbName = dbName;
|
||||
this._shutdown = false;
|
||||
this._connection = null;
|
||||
this._transactionRollback = null;
|
||||
this._transactionNestingLevel = 0;
|
||||
this._callbacks = { begin: [], commit: [], rollback: [] };
|
||||
this._self = this;
|
||||
}
|
||||
|
||||
this.query = query;
|
||||
this.valueQuery = valueQuery;
|
||||
this.rowQuery = rowQuery;
|
||||
this.columnQuery = columnQuery;
|
||||
this.getStatement = getStatement;
|
||||
this.getLastInsertID = getLastInsertID;
|
||||
this.getLastErrorString = getLastErrorString;
|
||||
this.beginTransaction = beginTransaction;
|
||||
this.commitTransaction = commitTransaction;
|
||||
this.rollbackTransaction = rollbackTransaction;
|
||||
this.addCallback = addCallback;
|
||||
this.removeCallback = removeCallback;
|
||||
this.transactionInProgress = transactionInProgress;
|
||||
this.commitAllTransactions = commitAllTransactions;
|
||||
this.tableExists = tableExists;
|
||||
this.getColumns = getColumns;
|
||||
this.getColumnHash = getColumnHash;
|
||||
this.getNextID = getNextID;
|
||||
this.getNextName = getNextName;
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Public methods
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Privileged methods
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
/*
|
||||
* Run an SQL query
|
||||
*
|
||||
* Optional _params_ is an array of bind parameters in the form
|
||||
|
@ -65,29 +53,29 @@ Zotero.DB = new function(){
|
|||
* - TRUE for other successful queries
|
||||
* - FALSE on error
|
||||
*/
|
||||
function query(sql,params){
|
||||
var db = _getDBConnection();
|
||||
Zotero.DBConnection.prototype.query = function (sql,params) {
|
||||
var db = this._getDBConnection();
|
||||
|
||||
try {
|
||||
// Parse out the SQL command being used
|
||||
var op = sql.match(/^[^a-z]*[^ ]+/i);
|
||||
if (op){
|
||||
if (op) {
|
||||
op = op.toString().toLowerCase();
|
||||
}
|
||||
|
||||
// If SELECT statement, return result
|
||||
if (op=='select'){
|
||||
if (op=='select') {
|
||||
// Until the native dataset methods work (or at least exist),
|
||||
// we build a multi-dimensional associative array manually
|
||||
|
||||
var statement = getStatement(sql, params);
|
||||
var statement = this.getStatement(sql, params);
|
||||
|
||||
var dataset = new Array();
|
||||
while (statement.executeStep()){
|
||||
while (statement.executeStep()) {
|
||||
var row = new Array();
|
||||
|
||||
for(var i=0; i<statement.columnCount; i++) {
|
||||
row[statement.getColumnName(i)] = _getTypedValue(statement, i);
|
||||
row[statement.getColumnName(i)] = this._getTypedValue(statement, i);
|
||||
}
|
||||
dataset.push(row);
|
||||
}
|
||||
|
@ -96,16 +84,16 @@ Zotero.DB = new function(){
|
|||
return dataset.length ? dataset : false;
|
||||
}
|
||||
else {
|
||||
if (params){
|
||||
var statement = getStatement(sql, params);
|
||||
if (params) {
|
||||
var statement = this.getStatement(sql, params);
|
||||
statement.execute();
|
||||
}
|
||||
else {
|
||||
Zotero.debug(sql,5);
|
||||
this._debug(sql,5);
|
||||
db.executeSimpleSQL(sql);
|
||||
}
|
||||
|
||||
if (op=='insert'){
|
||||
if (op=='insert') {
|
||||
return db.lastInsertRowID;
|
||||
}
|
||||
// DEBUG: Can't get affected rows for UPDATE or DELETE?
|
||||
|
@ -114,63 +102,63 @@ Zotero.DB = new function(){
|
|||
}
|
||||
}
|
||||
}
|
||||
catch (e){
|
||||
catch (e) {
|
||||
var dberr = (db.lastErrorString!='not an error')
|
||||
? ' [ERROR: ' + db.lastErrorString + ']' : '';
|
||||
throw(e + ' [QUERY: ' + sql + ']' + dberr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
* Query a single value and return it
|
||||
*/
|
||||
function valueQuery(sql,params){
|
||||
var statement = getStatement(sql, params);
|
||||
Zotero.DBConnection.prototype.valueQuery = function (sql,params) {
|
||||
var statement = this.getStatement(sql, params);
|
||||
|
||||
// No rows
|
||||
if (!statement.executeStep()){
|
||||
if (!statement.executeStep()) {
|
||||
statement.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
var value = _getTypedValue(statement, 0);
|
||||
var value = this._getTypedValue(statement, 0);
|
||||
statement.reset();
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
* Run a query and return the first row
|
||||
*/
|
||||
function rowQuery(sql,params){
|
||||
Zotero.DBConnection.prototype.rowQuery = function (sql,params) {
|
||||
var result = query(sql,params);
|
||||
if (result){
|
||||
if (result) {
|
||||
return result[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
* Run a query and return the first column as a numerically-indexed array
|
||||
*/
|
||||
function columnQuery(sql,params){
|
||||
var statement = getStatement(sql, params);
|
||||
Zotero.DBConnection.prototype.columnQuery = function (sql,params) {
|
||||
var statement = this.getStatement(sql, params);
|
||||
|
||||
if (statement){
|
||||
if (statement) {
|
||||
var column = new Array();
|
||||
while (statement.executeStep()){
|
||||
column.push(_getTypedValue(statement, 0));
|
||||
while (statement.executeStep()) {
|
||||
column.push(this._getTypedValue(statement, 0));
|
||||
}
|
||||
statement.reset();
|
||||
return column.length ? column : false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
/*
|
||||
/*
|
||||
* Get a raw mozStorage statement from the DB for manual processing
|
||||
*
|
||||
* This should only be used externally for manual parameter binding for
|
||||
|
@ -179,44 +167,44 @@ Zotero.DB = new function(){
|
|||
* Optional _params_ is an array of bind parameters in the form
|
||||
* [1,"hello",3] or [{'int':2},{'string':'foobar'}]
|
||||
*/
|
||||
function getStatement(sql, params){
|
||||
var db = _getDBConnection();
|
||||
Zotero.DBConnection.prototype.getStatement = function (sql, params) {
|
||||
var db = this._getDBConnection();
|
||||
|
||||
try {
|
||||
Zotero.debug(sql,5);
|
||||
this._debug(sql,5);
|
||||
var statement = db.createStatement(sql);
|
||||
}
|
||||
catch (e){
|
||||
catch (e) {
|
||||
var dberr = (db.lastErrorString!='not an error')
|
||||
? ' [ERROR: ' + db.lastErrorString + ']' : '';
|
||||
throw(e + ' [QUERY: ' + sql + ']' + dberr);
|
||||
}
|
||||
|
||||
if (params){
|
||||
if (params) {
|
||||
// If single scalar value or single non-array object, wrap in an array
|
||||
if (typeof params != 'object' || params===null ||
|
||||
(params && typeof params == 'object' && !params.length)){
|
||||
(params && typeof params == 'object' && !params.length)) {
|
||||
params = [params];
|
||||
}
|
||||
|
||||
for (var i=0; i<params.length; i++){
|
||||
for (var i=0; i<params.length; i++) {
|
||||
// Integer
|
||||
if (params[i]!==null && typeof params[i]['int'] != 'undefined'){
|
||||
if (params[i]!==null && typeof params[i]['int'] != 'undefined') {
|
||||
var type = 'int';
|
||||
var value = params[i]['int'];
|
||||
}
|
||||
// String
|
||||
else if (params[i]!==null && typeof params[i]['string'] != 'undefined'){
|
||||
else if (params[i]!==null && typeof params[i]['string'] != 'undefined') {
|
||||
var type = 'string';
|
||||
var value = params[i]['string'];
|
||||
}
|
||||
// Null
|
||||
else if (params[i]!==null && typeof params[i]['null'] != 'undefined'){
|
||||
else if (params[i]!==null && typeof params[i]['null'] != 'undefined') {
|
||||
var type = 'null';
|
||||
}
|
||||
// Automatic (trust the JS type)
|
||||
else {
|
||||
switch (typeof params[i]){
|
||||
switch (typeof params[i]) {
|
||||
case 'string':
|
||||
var type = 'string';
|
||||
break;
|
||||
|
@ -225,7 +213,7 @@ Zotero.DB = new function(){
|
|||
break;
|
||||
// Object
|
||||
default:
|
||||
if (params[i]===null){
|
||||
if (params[i]===null) {
|
||||
var type = 'null';
|
||||
}
|
||||
else {
|
||||
|
@ -237,21 +225,21 @@ Zotero.DB = new function(){
|
|||
}
|
||||
|
||||
// Bind the parameter as the correct type
|
||||
switch (type){
|
||||
switch (type) {
|
||||
case 'int':
|
||||
Zotero.debug('Binding parameter ' + (i+1)
|
||||
this._debug('Binding parameter ' + (i+1)
|
||||
+ ' of type int: ' + value, 5);
|
||||
statement.bindInt32Parameter(i, value);
|
||||
break;
|
||||
|
||||
case 'string':
|
||||
Zotero.debug('Binding parameter ' + (i+1)
|
||||
this._debug('Binding parameter ' + (i+1)
|
||||
+ ' of type string: "' + value + '"', 5);
|
||||
statement.bindUTF8StringParameter(i, value);
|
||||
break;
|
||||
|
||||
case 'null':
|
||||
Zotero.debug('Binding parameter ' + (i+1)
|
||||
this._debug('Binding parameter ' + (i+1)
|
||||
+ ' of type NULL', 5);
|
||||
statement.bindNullParameter(i);
|
||||
break;
|
||||
|
@ -259,117 +247,117 @@ Zotero.DB = new function(){
|
|||
}
|
||||
}
|
||||
return statement;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Only for use externally with getStatement()
|
||||
/*
|
||||
* Only for use externally with this.getStatement()
|
||||
*/
|
||||
function getLastInsertID(){
|
||||
var db = _getDBConnection();
|
||||
Zotero.DBConnection.prototype.getLastInsertID = function () {
|
||||
var db = this._getDBConnection();
|
||||
return db.lastInsertRowID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Only for use externally with getStatement()
|
||||
/*
|
||||
* Only for use externally with this.getStatement()
|
||||
*/
|
||||
function getLastErrorString(){
|
||||
var db = _getDBConnection();
|
||||
Zotero.DBConnection.prototype.getLastErrorString = function () {
|
||||
var db = this._getDBConnection();
|
||||
return db.lastErrorString;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function beginTransaction(){
|
||||
var db = _getDBConnection();
|
||||
Zotero.DBConnection.prototype.beginTransaction = function () {
|
||||
var db = this._getDBConnection();
|
||||
|
||||
if (db.transactionInProgress){
|
||||
_transactionNestingLevel++;
|
||||
Zotero.debug('Transaction in progress -- increasing level to '
|
||||
+ _transactionNestingLevel, 5);
|
||||
if (db.transactionInProgress) {
|
||||
this._transactionNestingLevel++;
|
||||
this._debug('Transaction in progress -- increasing level to '
|
||||
+ this._transactionNestingLevel, 5);
|
||||
}
|
||||
else {
|
||||
Zotero.debug('Beginning DB transaction', 5);
|
||||
this._debug('Beginning DB transaction', 5);
|
||||
db.beginTransaction();
|
||||
|
||||
// Run callbacks
|
||||
for (var i=0; i<_callbacks.begin.length; i++) {
|
||||
if (_callbacks.begin[i]) {
|
||||
_callbacks.begin[i]();
|
||||
}
|
||||
for (var i=0; i<this._callbacks.begin.length; i++) {
|
||||
if (this._callbacks.begin[i]) {
|
||||
this._callbacks.begin[i]();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function commitTransaction(){
|
||||
var db = _getDBConnection();
|
||||
Zotero.DBConnection.prototype.commitTransaction = function () {
|
||||
var db = this._getDBConnection();
|
||||
|
||||
if (_transactionNestingLevel){
|
||||
_transactionNestingLevel--;
|
||||
Zotero.debug('Decreasing transaction level to ' + _transactionNestingLevel, 5);
|
||||
if (this._transactionNestingLevel) {
|
||||
this._transactionNestingLevel--;
|
||||
this._debug('Decreasing transaction level to ' + this._transactionNestingLevel, 5);
|
||||
}
|
||||
else if (_transactionRollback){
|
||||
Zotero.debug('Rolling back previously flagged transaction', 5);
|
||||
else if (this._transactionRollback) {
|
||||
this._debug('Rolling back previously flagged transaction', 5);
|
||||
db.rollbackTransaction();
|
||||
}
|
||||
else {
|
||||
Zotero.debug('Committing transaction',5);
|
||||
this._debug('Committing transaction',5);
|
||||
try {
|
||||
db.commitTransaction();
|
||||
|
||||
// Run callbacks
|
||||
for (var i=0; i<_callbacks.commit.length; i++) {
|
||||
if (_callbacks.commit[i]) {
|
||||
_callbacks.commit[i]();
|
||||
for (var i=0; i<this._callbacks.commit.length; i++) {
|
||||
if (this._callbacks.commit[i]) {
|
||||
this._callbacks.commit[i]();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(e){
|
||||
catch(e) {
|
||||
var dberr = (db.lastErrorString!='not an error')
|
||||
? ' [ERROR: ' + db.lastErrorString + ']' : '';
|
||||
throw(e + dberr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function rollbackTransaction(){
|
||||
var db = _getDBConnection();
|
||||
Zotero.DBConnection.prototype.rollbackTransaction = function () {
|
||||
var db = this._getDBConnection();
|
||||
|
||||
if (!db.transactionInProgress) {
|
||||
Zotero.debug("Transaction is not in progress in rollbackTransaction()", 2);
|
||||
this._debug("Transaction is not in progress in rollbackTransaction()", 2);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_transactionNestingLevel){
|
||||
_transactionNestingLevel--;
|
||||
_transactionRollback = true;
|
||||
Zotero.debug('Flagging nested transaction for rollback', 5);
|
||||
if (this._transactionNestingLevel) {
|
||||
this._transactionNestingLevel--;
|
||||
this._transactionRollback = true;
|
||||
this._debug('Flagging nested transaction for rollback', 5);
|
||||
}
|
||||
else {
|
||||
Zotero.debug('Rolling back transaction', 5);
|
||||
_transactionRollback = false;
|
||||
this._debug('Rolling back transaction', 5);
|
||||
this._transactionRollback = false;
|
||||
try {
|
||||
db.rollbackTransaction();
|
||||
|
||||
// Run callbacks
|
||||
for (var i=0; i<_callbacks.rollback.length; i++) {
|
||||
if (_callbacks.rollback[i]) {
|
||||
_callbacks.rollback[i]();
|
||||
for (var i=0; i<this._callbacks.rollback.length; i++) {
|
||||
if (this._callbacks.rollback[i]) {
|
||||
this._callbacks.rollback[i]();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(e){
|
||||
catch(e) {
|
||||
var dberr = (db.lastErrorString!='not an error')
|
||||
? ' [ERROR: ' + db.lastErrorString + ']' : '';
|
||||
throw(e + dberr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function addCallback(type, cb) {
|
||||
Zotero.DBConnection.prototype.addCallback = function (type, cb) {
|
||||
switch (type) {
|
||||
case 'begin':
|
||||
case 'commit':
|
||||
|
@ -380,13 +368,13 @@ Zotero.DB = new function(){
|
|||
throw ("Invalid callback type '" + type + "' in DB.addCallback()");
|
||||
}
|
||||
|
||||
var id = _callbacks[type].length;
|
||||
_callbacks[type][id] = cb;
|
||||
var id = this._callbacks[type].length;
|
||||
this._callbacks[type][id] = cb;
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function removeCallback(type, id) {
|
||||
Zotero.DBConnection.prototype.removeCallback = function (type, id) {
|
||||
switch (type) {
|
||||
case 'begin':
|
||||
case 'commit':
|
||||
|
@ -397,124 +385,124 @@ Zotero.DB = new function(){
|
|||
throw ("Invalid callback type '" + type + "' in DB.removeCallback()");
|
||||
}
|
||||
|
||||
delete _callbacks[type][id];
|
||||
}
|
||||
delete this._callbacks[type][id];
|
||||
}
|
||||
|
||||
|
||||
function transactionInProgress(){
|
||||
var db = _getDBConnection();
|
||||
Zotero.DBConnection.prototype.transactionInProgress = function () {
|
||||
var db = this._getDBConnection();
|
||||
return db.transactionInProgress;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* Safety function used on shutdown to make sure we're not stuck in the
|
||||
* middle of a transaction
|
||||
*/
|
||||
function commitAllTransactions(){
|
||||
if (transactionInProgress()){
|
||||
var level = _transactionNestingLevel;
|
||||
_transactionNestingLevel = 0;
|
||||
Zotero.DBConnection.prototype.commitAllTransactions = function () {
|
||||
if (this.transactionInProgress()) {
|
||||
var level = this._transactionNestingLevel;
|
||||
this._transactionNestingLevel = 0;
|
||||
try {
|
||||
Zotero.DB.commitTransaction();
|
||||
this.commitTransaction();
|
||||
}
|
||||
catch (e){}
|
||||
catch (e) {}
|
||||
return level ? level : true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function tableExists(table){
|
||||
return _getDBConnection().tableExists(table);
|
||||
}
|
||||
Zotero.DBConnection.prototype.tableExists = function (table) {
|
||||
return this._getDBConnection().tableExists(table);
|
||||
}
|
||||
|
||||
|
||||
function getColumns(table){
|
||||
var db = _getDBConnection();
|
||||
Zotero.DBConnection.prototype.getColumns = function (table) {
|
||||
var db = this._getDBConnection();
|
||||
|
||||
try {
|
||||
var sql = "SELECT * FROM " + table + " LIMIT 1";
|
||||
var statement = getStatement(sql);
|
||||
var statement = this.getStatement(sql);
|
||||
var cols = new Array();
|
||||
for (var i=0,len=statement.columnCount; i<len; i++){
|
||||
for (var i=0,len=statement.columnCount; i<len; i++) {
|
||||
cols.push(statement.getColumnName(i));
|
||||
}
|
||||
statement.reset();
|
||||
return cols;
|
||||
}
|
||||
catch (e){
|
||||
Zotero.debug(e,1);
|
||||
catch (e) {
|
||||
this._debug(e,1);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function getColumnHash(table){
|
||||
var cols = getColumns(table);
|
||||
Zotero.DBConnection.prototype.getColumnHash = function (table) {
|
||||
var cols = this.getColumns(table);
|
||||
var hash = new Array();
|
||||
if (cols.length){
|
||||
for (var i=0; i<cols.length; i++){
|
||||
if (cols.length) {
|
||||
for (var i=0; i<cols.length; i++) {
|
||||
hash[cols[i]] = true;
|
||||
}
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find the lowest unused integer >0 in a table column
|
||||
*
|
||||
* Note: This retrieves all the rows of the column, so it's not really
|
||||
* meant for particularly large tables.
|
||||
**/
|
||||
function getNextID(table, column){
|
||||
/**
|
||||
* Find the lowest unused integer >0 in a table column
|
||||
*
|
||||
* Note: This retrieves all the rows of the column, so it's not really
|
||||
* meant for particularly large tables.
|
||||
**/
|
||||
Zotero.DBConnection.prototype.getNextID = function (table, column) {
|
||||
var sql = 'SELECT ' + column + ' FROM ' + table + ' ORDER BY ' + column;
|
||||
var vals = Zotero.DB.columnQuery(sql);
|
||||
var vals = this.columnQuery(sql);
|
||||
|
||||
if (!vals){
|
||||
if (!vals) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (vals[0] === '0'){
|
||||
if (vals[0] === '0') {
|
||||
vals.shift();
|
||||
}
|
||||
|
||||
for (var i=0, len=vals.length; i<len; i++){
|
||||
if (vals[i] != i+1){
|
||||
for (var i=0, len=vals.length; i<len; i++) {
|
||||
if (vals[i] != i+1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return i+1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find the next lowest numeric suffix for a value in table column
|
||||
*
|
||||
* For example, if "Untitled" and "Untitled 2" and "Untitled 4",
|
||||
* returns "Untitled 3"
|
||||
*
|
||||
* DEBUG: doesn't work once there's an "Untitled 10"
|
||||
*
|
||||
* If _name_ alone is available, returns that
|
||||
**/
|
||||
function getNextName(table, field, name)
|
||||
{
|
||||
/**
|
||||
* Find the next lowest numeric suffix for a value in table column
|
||||
*
|
||||
* For example, if "Untitled" and "Untitled 2" and "Untitled 4",
|
||||
* returns "Untitled 3"
|
||||
*
|
||||
* DEBUG: doesn't work once there's an "Untitled 10"
|
||||
*
|
||||
* If _name_ alone is available, returns that
|
||||
**/
|
||||
Zotero.DBConnection.prototype.getNextName = function (table, field, name)
|
||||
{
|
||||
var sql = "SELECT " + field + " FROM " + table + " WHERE " + field
|
||||
+ " LIKE ? ORDER BY " + field + " COLLATE NOCASE";
|
||||
var untitleds = Zotero.DB.columnQuery(sql, name + '%');
|
||||
var untitleds = this.columnQuery(sql, name + '%');
|
||||
|
||||
if (!untitleds || untitleds[0]!=name){
|
||||
if (!untitleds || untitleds[0]!=name) {
|
||||
return name;
|
||||
}
|
||||
|
||||
var i = 1;
|
||||
var num = 2;
|
||||
while (untitleds[i] && untitleds[i]==(name + ' ' + num)){
|
||||
while (untitleds[i+1] && untitleds[i]==untitleds[i+1]){
|
||||
Zotero.debug('Next ' + i + ' is ' + untitleds[i]);
|
||||
while (untitleds[i] && untitleds[i]==(name + ' ' + num)) {
|
||||
while (untitleds[i+1] && untitleds[i]==untitleds[i+1]) {
|
||||
this._debug('Next ' + i + ' is ' + untitleds[i]);
|
||||
i++;
|
||||
}
|
||||
|
||||
|
@ -523,41 +511,117 @@ Zotero.DB = new function(){
|
|||
}
|
||||
|
||||
return name + ' ' + num;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Shutdown observer
|
||||
*/
|
||||
Zotero.DBConnection.prototype.observe = function(subject, topic, data) {
|
||||
switch (topic) {
|
||||
case 'xpcom-shutdown':
|
||||
if (this._shutdown) {
|
||||
this._debug('returning');
|
||||
return;
|
||||
}
|
||||
|
||||
var level = this.commitAllTransactions();
|
||||
if (level) {
|
||||
level = level === true ? '0' : level;
|
||||
this._debug("A transaction in DB '" + this._dbName + "' was still open! (level " + level + ")", 2);
|
||||
}
|
||||
|
||||
this._shutdown = true;
|
||||
this.backupDatabase();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Private methods
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////
|
||||
Zotero.DBConnection.prototype.backupDatabase = function () {
|
||||
if (this.transactionInProgress()) {
|
||||
this._debug("Transaction in progress--skipping backup of DB '" + this._dbName + "'", 2);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
this._debug("Backing up database '" + this._dbName + "'");
|
||||
|
||||
var file = Zotero.getZoteroDatabase(this._dbName);
|
||||
var backupFile = Zotero.getZoteroDatabase(this._dbName, 'bak');
|
||||
|
||||
// Copy via a temporary file so we don't run into disk space issues
|
||||
// after deleting the old backup file
|
||||
var tmpFile = Zotero.getZoteroDatabase(this._dbName, 'tmp');
|
||||
if (tmpFile.exists()) {
|
||||
tmpFile.remove(null);
|
||||
}
|
||||
|
||||
try {
|
||||
file.copyTo(file.parent, tmpFile.leafName);
|
||||
}
|
||||
catch (e){
|
||||
// TODO: deal with low disk space
|
||||
throw (e);
|
||||
}
|
||||
|
||||
try {
|
||||
var store = Components.classes["@mozilla.org/storage/service;1"].
|
||||
getService(Components.interfaces.mozIStorageService);
|
||||
|
||||
var connection = store.openDatabase(tmpFile);
|
||||
}
|
||||
catch (e){
|
||||
this._debug("Database file '" + tmpFile.leafName + "' is corrupt--skipping backup");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove old backup file
|
||||
if (backupFile.exists()) {
|
||||
backupFile.remove(null);
|
||||
}
|
||||
|
||||
tmpFile.moveTo(tmpFile.parent, backupFile.leafName);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Private methods
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
* Retrieve a link to the data store
|
||||
*/
|
||||
function _getDBConnection(){
|
||||
if (_connection){
|
||||
return _connection;
|
||||
Zotero.DBConnection.prototype._getDBConnection = function () {
|
||||
if (this._connection) {
|
||||
return this._connection;
|
||||
}
|
||||
|
||||
this._debug("Opening database '" + this._dbName + "'");
|
||||
|
||||
// Get the storage service
|
||||
var store = Components.classes["@mozilla.org/storage/service;1"].
|
||||
getService(Components.interfaces.mozIStorageService);
|
||||
|
||||
var file = Zotero.getZoteroDatabase();
|
||||
var backupFile = Zotero.getZoteroDatabase('bak');
|
||||
var file = Zotero.getZoteroDatabase(this._dbName);
|
||||
var backupFile = Zotero.getZoteroDatabase(this._dbName, 'bak');
|
||||
|
||||
if (ZOTERO_CONFIG['DB_REBUILD']){
|
||||
if (confirm('Erase all user data and recreate database from schema?')){
|
||||
var fileName = this._dbName + '.sqlite';
|
||||
|
||||
if (this._dbName == 'zotero' && ZOTERO_CONFIG['DB_REBUILD']) {
|
||||
if (confirm('Erase all user data and recreate database from schema?')) {
|
||||
// Delete existing Zotero database
|
||||
if (file.exists()){
|
||||
if (file.exists()) {
|
||||
file.remove(null);
|
||||
}
|
||||
|
||||
// Delete existing storage folder
|
||||
var dir = Zotero.getStorageDirectory();
|
||||
if (dir.exists()){
|
||||
if (dir.exists()) {
|
||||
dir.remove(true);
|
||||
}
|
||||
}
|
||||
|
@ -565,77 +629,78 @@ Zotero.DB = new function(){
|
|||
|
||||
// DEBUG: Temporary check
|
||||
// Test the backup file (to make sure the backup mechanism is working)
|
||||
if (backupFile.exists()){
|
||||
if (backupFile.exists()) {
|
||||
try {
|
||||
_connection = store.openDatabase(backupFile);
|
||||
this._connection = store.openDatabase(backupFile);
|
||||
}
|
||||
catch (e){
|
||||
Zotero.debug('Backup file was corrupt', 1);
|
||||
catch (e) {
|
||||
this._debug("Backup file '" + backupFile.leafName + "' was corrupt!", 1);
|
||||
}
|
||||
_connection = undefined;
|
||||
this._connection = undefined;
|
||||
}
|
||||
|
||||
catchBlock: try {
|
||||
_connection = store.openDatabase(file);
|
||||
this._connection = store.openDatabase(file);
|
||||
}
|
||||
catch (e){
|
||||
if (e.name=='NS_ERROR_FILE_CORRUPTED'){
|
||||
Zotero.debug('Database file corrupted', 1);
|
||||
catch (e) {
|
||||
if (e.name=='NS_ERROR_FILE_CORRUPTED') {
|
||||
this._debug("Database file '" + file.leafName + "' corrupted", 1);
|
||||
|
||||
// No backup file! Eek!
|
||||
if (!backupFile.exists()){
|
||||
Zotero.debug('No backup file exists', 1);
|
||||
if (!backupFile.exists()) {
|
||||
this._debug("No backup file for DB '" + this._dbName + "' exists", 1);
|
||||
|
||||
// Save damaged filed
|
||||
Zotero.debug('Saving damaged DB file with .damaged extension', 1);
|
||||
var damagedFile = Zotero.getZoteroDatabase('damaged');
|
||||
this._debug('Saving damaged DB file with .damaged extension', 1);
|
||||
var damagedFile = Zotero.getZoteroDatabase(this._dbName, 'damaged');
|
||||
Zotero.moveToUnique(file, damagedFile);
|
||||
|
||||
// Create new main database
|
||||
var file = Zotero.getZoteroDatabase();
|
||||
_connection = store.openDatabase(file);
|
||||
var file = Zotero.getZoteroDatabase(this._dbName);
|
||||
this._connection = store.openDatabase(file);
|
||||
|
||||
alert(Zotero.getString('db.dbCorruptedNoBackup'));
|
||||
alert(Zotero.getString('db.dbCorruptedNoBackup', fileName));
|
||||
break catchBlock;
|
||||
}
|
||||
|
||||
// Save damaged file
|
||||
Zotero.debug('Saving damaged DB file with .damaged extension', 1);
|
||||
var damagedFile = Zotero.getZoteroDatabase('damaged');
|
||||
this._debug('Saving damaged DB file with .damaged extension', 1);
|
||||
var damagedFile = Zotero.getZoteroDatabase(this._dbName, 'damaged');
|
||||
Zotero.moveToUnique(file, damagedFile);
|
||||
|
||||
// Test the backup file
|
||||
try {
|
||||
_connection = store.openDatabase(backupFile);
|
||||
this._connection = store.openDatabase(backupFile);
|
||||
}
|
||||
// Can't open backup either
|
||||
catch (e){
|
||||
catch (e) {
|
||||
// Create new main database
|
||||
var file = Zotero.getZoteroDatabase();
|
||||
_connection = store.openDatabase(file);
|
||||
var file = Zotero.getZoteroDatabase(this._dbName);
|
||||
this._connection = store.openDatabase(file);
|
||||
|
||||
alert(Zotero.getString('db.dbRestoreFailed'));
|
||||
alert(Zotero.getString('db.dbRestoreFailed', fileName));
|
||||
break catchBlock;
|
||||
}
|
||||
|
||||
_connection = undefined;
|
||||
this._connection = undefined;
|
||||
|
||||
// Copy backup file to main DB file
|
||||
Zotero.debug('Restoring main database from backup file', 1);
|
||||
this._debug("Restoring database '" + this._dbName + "' from backup file", 1);
|
||||
try {
|
||||
backupFile.copyTo(backupFile.parent, ZOTERO_CONFIG['DB_FILE']);
|
||||
backupFile.copyTo(backupFile.parent, fileName);
|
||||
}
|
||||
catch (e){
|
||||
catch (e) {
|
||||
// TODO: deal with low disk space
|
||||
throw (e);
|
||||
}
|
||||
|
||||
// Open restored database
|
||||
var file = Zotero.getZoteroDirectory();
|
||||
file.append(ZOTERO_CONFIG['DB_FILE']);
|
||||
_connection = store.openDatabase(file);
|
||||
Zotero.debug('Database restored', 1);
|
||||
file.append(fileName);
|
||||
this._connection = store.openDatabase(file);
|
||||
this._debug('Database restored', 1);
|
||||
var msg = Zotero.getString('db.dbRestored', [
|
||||
fileName,
|
||||
Zotero.Date.getFileDateString(backupFile),
|
||||
Zotero.Date.getFileTimeString(backupFile)
|
||||
]);
|
||||
|
@ -648,13 +713,26 @@ Zotero.DB = new function(){
|
|||
throw (e);
|
||||
}
|
||||
|
||||
return _connection;
|
||||
}
|
||||
|
||||
// Register shutdown handler to call this.onShutdown() for DB backup
|
||||
var observerService = Components.classes["@mozilla.org/observer-service;1"]
|
||||
.getService(Components.interfaces.nsIObserverService);
|
||||
|
||||
observerService.addObserver(this, "xpcom-shutdown", false);
|
||||
|
||||
return this._connection;
|
||||
}
|
||||
|
||||
|
||||
function _getTypedValue(statement, i){
|
||||
Zotero.DBConnection.prototype._debug = function (str, level) {
|
||||
var prefix = this._dbName == 'zotero' ? '' : '[' + this._dbName + '] ';
|
||||
Zotero.debug(prefix + str, level);
|
||||
}
|
||||
|
||||
|
||||
Zotero.DBConnection.prototype._getTypedValue = function (statement, i) {
|
||||
var type = statement.getTypeOfIndex(i);
|
||||
switch (type){
|
||||
switch (type) {
|
||||
case statement.VALUE_TYPE_INTEGER:
|
||||
var func = statement.getInt64;
|
||||
break;
|
||||
|
@ -672,5 +750,10 @@ Zotero.DB = new function(){
|
|||
}
|
||||
|
||||
return func(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Initialize main database connection
|
||||
Zotero.DB = new Zotero.DBConnection('zotero');
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
|
||||
const ZOTERO_CONFIG = {
|
||||
GUID: 'zotero@chnm.gmu.edu',
|
||||
DB_FILE: 'zotero.sqlite',
|
||||
DB_REBUILD: false, // erase DB and recreate from schema
|
||||
REPOSITORY_URL: 'http://www.zotero.org/repo',
|
||||
REPOSITORY_CHECK_INTERVAL: 86400, // 24 hours
|
||||
|
@ -36,17 +35,16 @@ var Zotero = new function(){
|
|||
var _initialized = false;
|
||||
var _debugLogging;
|
||||
var _debugLevel;
|
||||
var _shutdown = false;
|
||||
//var _shutdown = false;
|
||||
var _localizedStringBundle;
|
||||
|
||||
// Privileged (public) methods
|
||||
this.init = init;
|
||||
this.shutdown = shutdown;
|
||||
//this.shutdown = shutdown;
|
||||
this.getProfileDirectory = getProfileDirectory;
|
||||
this.getZoteroDirectory = getZoteroDirectory;
|
||||
this.getStorageDirectory = getStorageDirectory;
|
||||
this.getZoteroDatabase = getZoteroDatabase;
|
||||
this.backupDatabase = backupDatabase;
|
||||
this.debug = debug;
|
||||
this.varDump = varDump;
|
||||
this.safeDebug = safeDebug;
|
||||
|
@ -77,6 +75,7 @@ var Zotero = new function(){
|
|||
}
|
||||
|
||||
// Register shutdown handler to call Zotero.shutdown()
|
||||
/*
|
||||
var observerService = Components.classes["@mozilla.org/observer-service;1"]
|
||||
.getService(Components.interfaces.nsIObserverService);
|
||||
observerService.addObserver({
|
||||
|
@ -84,6 +83,7 @@ var Zotero = new function(){
|
|||
Zotero.shutdown(subject, topic, data)
|
||||
}
|
||||
}, "xpcom-shutdown", false);
|
||||
*/
|
||||
|
||||
// Load in the preferences branch for the extension
|
||||
Zotero.Prefs.init();
|
||||
|
@ -143,24 +143,15 @@ var Zotero = new function(){
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
function shutdown(subject, topic, data){
|
||||
// Called twice otherwise, for some reason
|
||||
if (_shutdown){
|
||||
return false;
|
||||
}
|
||||
|
||||
var level = Zotero.DB.commitAllTransactions();
|
||||
if (level){
|
||||
level = level===true ? '0' : level;
|
||||
Zotero.debug("A transaction was still open! (level " + level + ")", 2);
|
||||
}
|
||||
|
||||
_shutdown = true;
|
||||
|
||||
Zotero.backupDatabase();
|
||||
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
function getProfileDirectory(){
|
||||
|
@ -193,66 +184,16 @@ var Zotero = new function(){
|
|||
return file;
|
||||
}
|
||||
|
||||
function getZoteroDatabase(ext){
|
||||
function getZoteroDatabase(name, ext){
|
||||
name = name ? name + '.sqlite' : 'zotero.sqlite';
|
||||
ext = ext ? '.' + ext : '';
|
||||
|
||||
var file = Zotero.getZoteroDirectory();
|
||||
file.append(ZOTERO_CONFIG['DB_FILE'] + ext);
|
||||
file.append(name + ext);
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Back up the main database file
|
||||
*/
|
||||
function backupDatabase(){
|
||||
if (Zotero.DB.transactionInProgress()){
|
||||
Zotero.debug('Transaction in progress--skipping DB backup', 2);
|
||||
return false;
|
||||
}
|
||||
|
||||
Zotero.debug('Backing up database');
|
||||
|
||||
var file = Zotero.getZoteroDatabase();
|
||||
var backupFile = Zotero.getZoteroDatabase('bak');
|
||||
|
||||
// Copy via a temporary file so we don't run into disk space issues
|
||||
// after deleting the old backup file
|
||||
var tmpFile = Zotero.getZoteroDatabase('tmp');
|
||||
if (tmpFile.exists()){
|
||||
tmpFile.remove(null);
|
||||
}
|
||||
|
||||
try {
|
||||
file.copyTo(file.parent, tmpFile.leafName);
|
||||
}
|
||||
catch (e){
|
||||
// TODO: deal with low disk space
|
||||
throw (e);
|
||||
}
|
||||
|
||||
try {
|
||||
var store = Components.classes["@mozilla.org/storage/service;1"].
|
||||
getService(Components.interfaces.mozIStorageService);
|
||||
|
||||
var connection = store.openDatabase(tmpFile);
|
||||
}
|
||||
catch (e){
|
||||
Zotero.debug("Database file is corrupt--skipping backup");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove old backup file
|
||||
if (backupFile.exists()){
|
||||
backupFile.remove(null);
|
||||
}
|
||||
|
||||
tmpFile.moveTo(tmpFile.parent, backupFile.leafName);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Debug logging function
|
||||
*
|
||||
|
|
|
@ -217,10 +217,6 @@ ingester.scrapeComplete=Artikel gespeichert.
|
|||
ingester.scrapeError=Artikel konnte nicht gespeichert werden.
|
||||
ingester.scrapeErrorDescription=Ein Fehler ist aufgetreten bei dem Versuch, diesen Artikel zu speichern. Wenn dieser Fehler weiterhin auftritt, kontaktieren Sie bitte den Autor des Übersetzers.
|
||||
|
||||
db.dbCorruptedNoBackup=Die Zotero-Datenbank wurde offensichtlich beschädigt und es gibt kein automatisches Backup.\n\nEine neue Datenbank wurde erstellt. Die beschädigte Datei bleibt im Zotero-Ordner gespeichert.
|
||||
db.dbRestored=Die Zotero-Datenbank wurde offensichtlich beschädigt.\n\nDie Daten wurde aus dem letztigen automatischen Backup vom %1$S um %2$S wiederhergestellt. Die beschädigte Datei bleibt im Zotero-Ordner gespeichert.
|
||||
db.dbRestoreFailed=Die Zotero-Datenbank wurde offensichtlich beschädigt, und der Versuch, die Daten aus dem letztigen automatischen Backup wiederherzustellen, hat nicht funktioniert.\n\nEine neue Datenbank wurde erstellt. Die beschädigte Datei bleibt im Zotero-Ordner gespeichert.
|
||||
|
||||
zotero.preferences.update.updated=Updated
|
||||
zotero.preferences.update.upToDate=Up to date
|
||||
zotero.preferences.update.error=Error
|
||||
|
|
|
@ -217,10 +217,6 @@ ingester.scrapeComplete=Artikel gespeichert.
|
|||
ingester.scrapeError=Artikel konnte nicht gespeichert werden.
|
||||
ingester.scrapeErrorDescription=Ein Fehler ist aufgetreten bei dem Versuch, diesen Artikel zu speichern. Wenn dieser Fehler weiterhin auftritt, kontaktieren Sie bitte den Autor des Übersetzers.
|
||||
|
||||
db.dbCorruptedNoBackup=Die Zotero-Datenbank wurde offensichtlich beschädigt und es gibt kein automatisches Backup.\n\nEine neue Datenbank wurde erstellt. Die beschädigte Datei bleibt im Zotero-Ordner gespeichert.
|
||||
db.dbRestored=Die Zotero-Datenbank wurde offensichtlich beschädigt.\n\nDie Daten wurde aus dem letztigen automatischen Backup vom %1$S um %2$S wiederhergestellt. Die beschädigte Datei bleibt im Zotero-Ordner gespeichert.
|
||||
db.dbRestoreFailed=Die Zotero-Datenbank wurde offensichtlich beschädigt, und der Versuch, die Daten aus dem letztigen automatischen Backup wiederherzustellen, hat nicht funktioniert.\n\nEine neue Datenbank wurde erstellt. Die beschädigte Datei bleibt im Zotero-Ordner gespeichert.
|
||||
|
||||
zotero.preferences.update.updated=Updated
|
||||
zotero.preferences.update.upToDate=Up to date
|
||||
zotero.preferences.update.error=Error
|
||||
|
|
|
@ -217,10 +217,6 @@ ingester.scrapeComplete=Artikel gespeichert.
|
|||
ingester.scrapeError=Artikel konnte nicht gespeichert werden.
|
||||
ingester.scrapeErrorDescription=Ein Fehler ist aufgetreten bei dem Versuch, diesen Artikel zu speichern. Wenn dieser Fehler weiterhin auftritt, kontaktieren Sie bitte den Autor des Übersetzers.
|
||||
|
||||
db.dbCorruptedNoBackup=Die Zotero-Datenbank wurde offensichtlich beschädigt und es gibt kein automatisches Backup.\n\nEine neue Datenbank wurde erstellt. Die beschädigte Datei bleibt im Zotero-Ordner gespeichert.
|
||||
db.dbRestored=Die Zotero-Datenbank wurde offensichtlich beschädigt.\n\nDie Daten wurde aus dem letztigen automatischen Backup vom %1$S um %2$S wiederhergestellt. Die beschädigte Datei bleibt im Zotero-Ordner gespeichert.
|
||||
db.dbRestoreFailed=Die Zotero-Datenbank wurde offensichtlich beschädigt, und der Versuch, die Daten aus dem letztigen automatischen Backup wiederherzustellen, hat nicht funktioniert.\n\nEine neue Datenbank wurde erstellt. Die beschädigte Datei bleibt im Zotero-Ordner gespeichert.
|
||||
|
||||
zotero.preferences.update.updated=Updated
|
||||
zotero.preferences.update.upToDate=Up to date
|
||||
zotero.preferences.update.error=Error
|
||||
|
|
|
@ -226,9 +226,9 @@ ingester.scrapeComplete = Item Saved.
|
|||
ingester.scrapeError = Could Not Save Item.
|
||||
ingester.scrapeErrorDescription = An error occurred while saving this item. Please try again. If this error persists, contact the translator author.
|
||||
|
||||
db.dbCorruptedNoBackup = The Zotero database appears to have become corrupted, and no automatic backup is available.\n\nA new database file has been created. The damaged file was saved in your Zotero directory.
|
||||
db.dbRestored = The Zotero database appears to have become corrupted.\n\nYour data was restored from the last automatic backup made on %1$S at %2$S. The damaged file was saved in your Zotero directory.
|
||||
db.dbRestoreFailed = The Zotero database appears to have become corrupted, and an attempt to restore from the last automatic backup failed.\n\nA new database file has been created. The damaged file was saved in your Zotero directory.
|
||||
db.dbCorruptedNoBackup = The Zotero database '%S' appears to have become corrupted, and no automatic backup is available.\n\nA new database file has been created. The damaged file was saved in your Zotero directory.
|
||||
db.dbRestored = The Zotero database '%1$S' appears to have become corrupted.\n\nYour data was restored from the last automatic backup made on %2$S at %3$S. The damaged file was saved in your Zotero directory.
|
||||
db.dbRestoreFailed = The Zotero database '%S' appears to have become corrupted, and an attempt to restore from the last automatic backup failed.\n\nA new database file has been created. The damaged file was saved in your Zotero directory.
|
||||
|
||||
zotero.preferences.update.updated = Updated
|
||||
zotero.preferences.update.upToDate = Up to date
|
||||
|
|
|
@ -217,10 +217,6 @@ ingester.scrapeComplete=Élément enregistré.
|
|||
ingester.scrapeError=Échec de l'enregistrement.
|
||||
ingester.scrapeErrorDescription=Une erreur s'est produite lors de l'enregistrement de cet élément. Veuillez réessayer. Si cette erreur persiste, contactez l'auteur du collecteur de données.
|
||||
|
||||
db.dbCorruptedNoBackup=La base de données Zotero semble avoir été corrompue et aucune sauvegarde automatique n'est disponible.\n\nUn nouveau fichier de base de données a été créé. Le fichier endommagé a été enregistré dans le dossier Zotero.
|
||||
db.dbRestored=La base de données Zotero semble avoir été corrompue.\n\nVos données ont été rétablies à partir de la dernière sauvegarde automatique faite le %1$S à %2$S. Le fichier endommagé a été enregistré dans le dossier Zotero.
|
||||
db.dbRestoreFailed=La base de données Zotero semble avoir été corrompue et une tentative de rétablissement à partir de la dernière sauvegarde automatique a échoué.\n\nUn nouveau fichier de base de données a été créé. Le fichier endommagé a été enregistré dans le dossier Zotero.
|
||||
|
||||
zotero.preferences.update.updated=Updated
|
||||
zotero.preferences.update.upToDate=Up to date
|
||||
zotero.preferences.update.error=Error
|
||||
|
|
|
@ -217,10 +217,6 @@ ingester.scrapeComplete=Elemento salvato
|
|||
ingester.scrapeError=Impossibile salvare elemento
|
||||
ingester.scrapeErrorDescription=Si è verificato un errore durante il salvataggio dell'elemento. Provare nuovamente. Se l'errore persiste, contattare l'autore del motore di ricerca.
|
||||
|
||||
db.dbCorruptedNoBackup=Il database di Zotero risulta essere corrotto e nessun backup risulta essere disponibile. \n\nÈ stato creato un nuovo database. Il file danneggiato è stato salvato all'interno della cartella di Zotero.
|
||||
db.dbRestored=Il database di Zotero risulta essere corrotto. \n\nI dati sono stati ripristinati dall'ultimo backup automatico eseguito il %1$S alle %2$S. Il file danneggiato è stato salvato all'interno della cartella di Zotero.
|
||||
db.dbRestoreFailed=Il database di Zotero risulta essere corrotto e il tentativo di ripristinare l'ultimo backup automatico ha dato esito negativo. \n\nÈ stato creato un nuovo database. Il file danneggiato è stato salvato all'interno della cartella di Zotero.
|
||||
|
||||
zotero.preferences.update.updated=Updated
|
||||
zotero.preferences.update.upToDate=Up to date
|
||||
zotero.preferences.update.error=Error
|
||||
|
|
|
@ -217,10 +217,6 @@ ingester.scrapeComplete=アイテムを保存しました。
|
|||
ingester.scrapeError=アイテムを保存できませんでした。
|
||||
ingester.scrapeErrorDescription=アイテムの保存中にエラーが発生しました。もう一度試してください。それでもエラーが発生する場合、スクレーパの作成者までご連絡ください。
|
||||
|
||||
db.dbCorruptedNoBackup=Zoteroのデータベースが破損しているようですが、自動バックアップはありません。\n\n新規データベース・ファイルが作成されました。破損されたファイルをZoteroフォルダに保存しました。
|
||||
db.dbRestored=Zoteroのデータベースが破損しているようです。\n\nデータは最終の自動バックアップ(%1$S %2$S)から復元されました。破損されたファイルをZoteroフォルダに保存しました。
|
||||
db.dbRestoreFailed=Zoteroのデータベースが破損しているようですが、データを最終の自動バックアップから復元できませんでした。\n\n新規データベース・ファイルが作成されました。破損されたファイルをZoteroフォルダに保存しました。
|
||||
|
||||
zotero.preferences.update.updated=Updated
|
||||
zotero.preferences.update.upToDate=Up to date
|
||||
zotero.preferences.update.error=Error
|
||||
|
|
|
@ -217,10 +217,6 @@ ingester.scrapeComplete=항목 저장됨.
|
|||
ingester.scrapeError=항목을 저장할 수 없습니다.
|
||||
ingester.scrapeErrorDescription=항목 저장중 오류가 발생했습니다. 다시 시도해 주세요. 오류가 지족적으로 발생하는 경우, 작성자에게 연락해 주십시오.
|
||||
|
||||
db.dbCorruptedNoBackup=Zotero의 데이타베이스가 훼손되어 있는 것으로 보이며, 자동 백업본이 존재하지 않습니다. \n\n신규 데이타베이스·파일이 생성되었습니다. 파손된 파일을 Zotero 폴더에 저장했습니다.
|
||||
db.dbRestored=Zotero의 데이타베이스가 훼손되어 있는 것으로 보입니다. \n\n데이터는 최종 자동 백업(%1$S %2$S)으로부터 복원되었습니다. 파손된 파일을 Zotero 폴더에 저장했습니다.
|
||||
db.dbRestoreFailed=Zotero의 데이타베이스가 훼손되어 있는 것으로 보이며, 최종 자동 백업으로부터 복원에 실패했습니다. \n\n신규 데이타베이스 파일이 생성되었습니다. 파손된 파일을 Zotero 폴더에 저장했습니다.
|
||||
|
||||
zotero.preferences.update.updated=Updated
|
||||
zotero.preferences.update.upToDate=Up to date
|
||||
zotero.preferences.update.error=Error
|
||||
|
|
|
@ -217,10 +217,6 @@ ingester.scrapeComplete=Element lagret.
|
|||
ingester.scrapeError=Kunne ikke lagre element.
|
||||
ingester.scrapeErrorDescription=En feil oppsto mens dette elementet ble forsøkt lagret. Vennligst prøv igjen. Vennligst kontakt forfatteren av oversetteren dersom denne feilen vedvarer.
|
||||
|
||||
db.dbCorruptedNoBackup=Zotero-databasen synes å ha blitt korrupt, og ingen automatisk backup er tilgjengelig.\n\nEn ny database har blitt skapt. Den skadde filen ble lagret i Zotero-mappen.
|
||||
db.dbRestored=Zotero-databasen synes å ha blitt korrupt.\n\nDataene dine ble gjenopprettet fra den siste automatiske backupfilen, skapt %1$S den %2$S. Den skadde filen ble lagret i Zotero-mappen.
|
||||
db.dbRestoreFailed=Zotero-databasen synes å ha blitt korrupt, og et forsøk på å gjenopprette fra sist backup feilet.\n\nEn ny database har blitt skapt. Den skadde filen ble lagret i Zotero-mappen.
|
||||
|
||||
zotero.preferences.update.updated=Updated
|
||||
zotero.preferences.update.upToDate=Up to date
|
||||
zotero.preferences.update.error=Error
|
||||
|
|
|
@ -217,10 +217,6 @@ ingester.scrapeComplete=Item Opgeslagen.
|
|||
ingester.scrapeError=Dit Item Kon Niet Opgeslagen Worden.
|
||||
ingester.scrapeErrorDescription=Er trad een fout op bij het opslagen van dit item. Probeer nogmaals. Indien deze fout zich nog voordoet, contacteer dan auteur van de site-vertaler.
|
||||
|
||||
db.dbCorruptedNoBackup=De Zotero gegevensbank blijkt corrupt, en er is geen automatische backup beschikbaar. Er werd een nieuwe gevevensbank aangemaakt. Het beschadigde bestand werd opgeslagen in je Zotero map.
|
||||
db.dbRestored=De Zotero gegevensbank blijkt corrupt.\n\nJe data werden hersteld sinds de laatste automatische backup, aangemaakt op %1$S om %2$S. Het beschadigde bestand werd opgeslagen in je Zotero map.
|
||||
db.dbRestoreFailed=De Zotero gegevensbank blijkt corrupt, en een poging om te herstellen sinds de laatste automatische backup mislukte. Er werd een nieuwe gegevensbank aangemaakt. Het beschadigde bestand werd opgeslagen in je Zotero map.
|
||||
|
||||
zotero.preferences.update.updated=Updated
|
||||
zotero.preferences.update.upToDate=Up to date
|
||||
zotero.preferences.update.error=Error
|
||||
|
|
|
@ -217,10 +217,6 @@ ingester.scrapeComplete=Ставка сачувана.
|
|||
ingester.scrapeError=Ставка није могле бити сачувана.
|
||||
ingester.scrapeErrorDescription=Грешка је начињена током сачувавања ставке. Покушајте поново. Ако грешка остане, контактирајте аутора „преводиоца странице“.
|
||||
|
||||
db.dbCorruptedNoBackup=Зотеро датабаза се игледа оштетила, а нема ни једне самонаправљене резервне копије. \n\nНова датотека датабазе је направљена. Остећена дадотека је сачувана у вашем Зотеро директоријуму.
|
||||
db.dbRestored=Зотеро дата база се изгледа оштетила.\n\nВаши подаци су обновљени из задње резервне копије самонаправљене %1$S у %2$S. Оштећена датотека је сачувана у вашем Зотеро директоријуму.
|
||||
db.dbRestoreFailed=Зотеро датабаза се игледа оштетила, а покушај да се подаци обнове из задње сачуване резервне копије није успео. \n\nНова датотека датабазе је направљена. Остећена дадотека је сачувана у вашем Зотеро директоријуму.
|
||||
|
||||
zotero.preferences.update.updated=Updated
|
||||
zotero.preferences.update.upToDate=Up to date
|
||||
zotero.preferences.update.error=Error
|
||||
|
|
|
@ -217,10 +217,6 @@ ingester.scrapeComplete=条目已保存.
|
|||
ingester.scrapeError=无法保存条目.
|
||||
ingester.scrapeErrorDescription=保存条目时发生错误. 请重试. 如果错误依旧, 请联系转换器作者.
|
||||
|
||||
db.dbCorruptedNoBackup=Zotero 数据库似乎已损坏, 而且无可用的自动备份.\n\n已建立一新的数据库. 损坏的文件已保存到您的 Zotero 目录中.
|
||||
db.dbRestored=Zotero 数据库似乎已损坏.\n\n您的数据已经从最新的自动备份里恢复, 所使用的备份建立于%1$S 位于 %2$S. 损坏的文件已保存到您的 Zotero 目录中.
|
||||
db.dbRestoreFailed=Zotero 数据库似乎已损坏. 试图从最新的自动备份里恢复时失败. \n\n已创建一新的数据库. 损坏的文件已保存到您的 Zotero 目录中.
|
||||
|
||||
zotero.preferences.update.updated=Updated
|
||||
zotero.preferences.update.upToDate=Up to date
|
||||
zotero.preferences.update.error=Error
|
||||
|
|
Loading…
Reference in New Issue
Block a user