add postgresql support

This commit is contained in:
konovalovsergey
2016-08-25 18:58:13 +03:00
parent f4e2432c5b
commit 65fc7a02d2
10 changed files with 177 additions and 86 deletions

View File

@ -63,16 +63,17 @@
"limits_image_types_copy": "jpg;png;gif;bmp;emf;wmf;svg;txt;bin" "limits_image_types_copy": "jpg;png;gif;bmp;emf;wmf;svg;txt;bin"
}, },
"sql": { "sql": {
"type": "mysql", "type": "postgres",
"tableChanges": "doc_changes", "tableChanges": "doc_changes",
"tableCallbacks": "doc_callbacks", "tableCallbacks": "doc_callbacks",
"tableResult": "task_result", "tableResult": "task_result",
"dbHost": "localhost", "dbHost": "localhost",
"dbPort": 3306, "dbPort": 5432,
"dbName": "onlyoffice", "dbName": "onlyoffice",
"dbUser": "root", "dbUser": "onlyoffice",
"dbPass": "onlyoffice", "dbPass": "onlyoffice",
"charset": "utf8", "charset": "utf8",
"connectionlimit": 10,
"max_allowed_packet": 1048575 "max_allowed_packet": 1048575
}, },
"redis": { "redis": {

View File

@ -32,6 +32,12 @@
}, },
"utils": { "utils": {
"utils_common_fontdir": "/Library/Fonts" "utils_common_fontdir": "/Library/Fonts"
},
"sql": {
"type": "mysql",
"dbPort": 3306,
"dbUser": "root",
"dbPass": "onlyoffice"
} }
} }
}, },

View File

@ -32,6 +32,12 @@
}, },
"utils": { "utils": {
"utils_common_fontdir": "C:\\Windows\\Fonts" "utils_common_fontdir": "C:\\Windows\\Fonts"
},
"sql": {
"type": "mysql",
"dbPort": 3306,
"dbUser": "root",
"dbPass": "onlyoffice"
} }
} }
}, },

View File

@ -16,7 +16,8 @@
"mime": "^1.3.4", "mime": "^1.3.4",
"multiparty": "^4.1.2", "multiparty": "^4.1.2",
"mysql": "^2.11.1", "mysql": "^2.11.1",
"pg": "^6.0.3", "pg": "^6.1.0",
"pg-escape": "^0.2.0",
"redis": "^2.6.2", "redis": "^2.6.2",
"sockjs": "http://d2ettrnqo7v976.cloudfront.net/npm/sockjs-node/v0.3.15.14.tar.gz", "sockjs": "http://d2ettrnqo7v976.cloudfront.net/npm/sockjs-node/v0.3.15.14.tar.gz",
"underscore": "^1.8.3" "underscore": "^1.8.3"

View File

@ -81,37 +81,9 @@ exports.loadTable = function (tableId, callbackFunction) {
var sqlCommand = "SELECT * FROM " + table + ";"; var sqlCommand = "SELECT * FROM " + table + ";";
baseConnector.sqlQuery(sqlCommand, callbackFunction); baseConnector.sqlQuery(sqlCommand, callbackFunction);
}; };
exports.upsertInTable = function (tableId, toInsert, toUpdate, callbackFunction) {
var table = getTableById(tableId);
var sqlCommand = "INSERT INTO " + table + " VALUES (";
for (var i = 0, l = toInsert.length; i < l; ++i) {
sqlCommand += baseConnector.sqlEscape(toInsert[i]);
if (i !== l - 1)
sqlCommand += ",";
}
sqlCommand += ") ON DUPLICATE KEY UPDATE ";
for (var i = 0, l = toUpdate.length; i + 1 < l; i += 2) {
sqlCommand += toUpdate[i] + "=" + baseConnector.sqlEscape(toUpdate[i+1]);
if (i + 1 !== l - 1)
sqlCommand += ",";
}
sqlCommand += ";";
baseConnector.sqlQuery(sqlCommand, callbackFunction);
};
exports.upsertInTablePromise = function (tableId, toInsert, toUpdate) {
return new Promise(function(resolve, reject) {
exports.upsertInTable(tableId, toInsert, toUpdate, function(error, result) {
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
};
exports.insertCallback = function(id, href, baseUrl, callbackFunction) { exports.insertCallback = function(id, href, baseUrl, callbackFunction) {
var sqlCommand = "INSERT IGNORE INTO " + tableCallbacks + " VALUES (" + baseConnector.sqlEscape(id) + "," + var sqlCommand = "INSERT " + baseConnector.ignoreStr + " INTO " + tableCallbacks + " VALUES (" + baseConnector.sqlEscape(id) + "," +
baseConnector.sqlEscape(href) + "," + baseConnector.sqlEscape(baseUrl) + ");"; baseConnector.sqlEscape(href) + "," + baseConnector.sqlEscape(baseUrl) + ") " + baseConnector.doNothingStr + ";";
baseConnector.sqlQuery(sqlCommand, callbackFunction); baseConnector.sqlQuery(sqlCommand, callbackFunction);
}; };

View File

@ -1 +1 @@
/* /*

View File

@ -31,29 +31,110 @@
*/ */
var pg = require('pg'); var pg = require('pg');
var co = require('co');
var pgEscape = require('pg-escape');
var types = require('pg').types;
var sqlBase = require('./baseConnector');
var configSql = require('config').get('services.CoAuthoring.sql'); var configSql = require('config').get('services.CoAuthoring.sql');
var connectionString = 'postgres://' + configSql.get('dbUser') + ':' + configSql.get('dbPass') + '@' + configSql.get('dbHost') + var pool = new pg.Pool({
(configSql.get('dbPort') ? (':' + configSql.get('dbPort')) : '') + '/' + configSql.get('dbName'); host: configSql.get('dbHost'),
port: configSql.get('dbPort'),
user: configSql.get('dbUser'),
password: configSql.get('dbPass'),
database: configSql.get('dbName'),
max: configSql.get('connectionlimit'),
min: 0,
ssl: false,
idleTimeoutMillis: 30000
});
//todo datetime timezone
types.setTypeParser(1114, function(stringValue) {
return new Date(stringValue + '+0000');
});
types.setTypeParser(1184, function(stringValue) {
return new Date(stringValue + '+0000');
});
var logger = require('./../../Common/sources/logger'); var logger = require('./../../Common/sources/logger');
exports.sqlQuery = function (sqlCommand, callbackFunction) { exports.sqlQuery = function(sqlCommand, callbackFunction, opt_noModifyRes) {
pg.connect(connectionString, function (err, connection, done) { co(function *() {
if(err) { var client = null;
logger.error('pool.getConnection error: %s', err); var result = null;
if (callbackFunction) callbackFunction(err, null); var error = null;
return; try {
} client = yield pool.connect();
result = yield client.query(sqlCommand);
connection.query(sqlCommand, function (error, result) { } catch (err) {
//call `done()` to release the client back to the pool error = err;
done(); if (client) {
logger.error('sqlQuery error sqlCommand: %s:\r\n%s', sqlCommand.slice(0, 50), err.stack);
if (error) logger.error('sqlQuery: %s sqlCommand: %s', error.message, sqlCommand.slice(0, 50)); } else {
if (callbackFunction) callbackFunction(error, result ? result.rows : result); logger.error('pool.getConnection error: %s', err);
}); }
}); } finally {
if (client) {
client.release();
}
if (callbackFunction) {
var output = result;
if (result && !opt_noModifyRes) {
if ('SELECT' === result.command) {
output = result.rows;
} else {
output = {affectedRows: result.rowCount};
}
}
callbackFunction(error, output);
}
}
});
};
exports.sqlEscape = function(value) {
//todo parameterized queries
return undefined !== value ? pgEscape.literal(value.toString()) : 'NULL';
};
exports.ignoreStr = '';
exports.doNothingStr = 'ON CONFLICT DO NOTHING';
function getUpsertString(task, opt_updateUserIndex) {
task.completeDefaults();
var dateNow = sqlBase.getDateTime(new Date());
var commandArg = [task.key, task.status, task.statusInfo, dateNow, task.title, task.userIndex, task.changeId];
var commandArgEsc = commandArg.map(function(curVal) {
return exports.sqlEscape(curVal)
});
//http://stackoverflow.com/questions/34762732/how-to-find-out-if-an-upsert-was-an-update-with-postgresql-9-5-upsert
var sql = "INSERT INTO task_result (id, status, status_info, last_open_date, title, user_index, change_id) SELECT " +
commandArgEsc.join(', ') +
" WHERE 'false' = set_config('myapp.isupdate', 'false', true) ON CONFLICT (id) DO UPDATE SET last_open_date = " +
sqlBase.baseConnector.sqlEscape(dateNow);
if (opt_updateUserIndex) {
sql += ', user_index = task_result.user_index + 1';
}
sql +=
" WHERE 'true' = set_config('myapp.isupdate', 'true', true) RETURNING current_setting('myapp.isupdate') as update";
if (opt_updateUserIndex) {
sql += ', user_index';
}
sql += ';';
return sql;
}
exports.upsert = function(task, opt_updateUserIndex) {
return new Promise(function(resolve, reject) {
var sqlCommand = getUpsertString(task, opt_updateUserIndex);
exports.sqlQuery(sqlCommand, function(error, result) {
if (error) {
reject(error);
} else {
if (result && result.rows.length > 0) {
var first = result.rows[0];
result = {affectedRows: 0, insertId: 0};
result.affectedRows = 'true' == first.update ? 2 : 1;
result.insertId = opt_updateUserIndex ? first.user_index : 0;
}
resolve(result);
}
}, true);
});
}; };
exports.sqlEscape = function (value) {
return value.replace( /(\')/g, "\\'" );
};

View File

@ -83,36 +83,8 @@ TaskResultData.prototype.completeDefaults = function() {
} }
}; };
function getUpsertString(task, opt_updateUserIndex) {
task.completeDefaults();
var dateNow = sqlBase.getDateTime(new Date());
var commandArg = [task.key, task.status, task.statusInfo, dateNow, task.title, task.userIndex, task.changeId];
var commandArgEsc = commandArg.map(function(curVal) {
return sqlBase.baseConnector.sqlEscape(curVal)
});
var sql = 'INSERT INTO task_result ( id, status, status_info, last_open_date, title,' +
' user_index, change_id ) VALUES (' + commandArgEsc.join(', ') + ') ON DUPLICATE KEY UPDATE' +
' last_open_date = ' + sqlBase.baseConnector.sqlEscape(dateNow);
if (opt_updateUserIndex) {
//todo LAST_INSERT_ID in posgresql - RETURNING
sql += ', user_index = LAST_INSERT_ID(user_index + 1);';
} else {
sql += ';';
}
return sql;
}
function upsert(task, opt_updateUserIndex) { function upsert(task, opt_updateUserIndex) {
return new Promise(function(resolve, reject) { return sqlBase.baseConnector.upsert(task, opt_updateUserIndex);
var sqlCommand = getUpsertString(task, opt_updateUserIndex);
sqlBase.baseConnector.sqlQuery(sqlCommand, function(error, result) {
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
} }
function getSelectString(docId) { function getSelectString(docId) {
@ -281,7 +253,6 @@ exports.upsert = upsert;
exports.select = select; exports.select = select;
exports.update = update; exports.update = update;
exports.updateIf = updateIf; exports.updateIf = updateIf;
exports.addRandomKey = addRandomKey;
exports.addRandomKeyTask = addRandomKeyTask; exports.addRandomKeyTask = addRandomKeyTask;
exports.remove = remove; exports.remove = remove;
exports.getExpired = getExpired; exports.getExpired = getExpired;

View File

@ -0,0 +1,52 @@
--
-- Create schema onlyoffice
--
-- CREATE DATABASE onlyoffice ENCODING = 'UTF8' CONNECTION LIMIT = -1;
--
-- Drop tables
--
DROP TABLE IF EXISTS "public"."doc_callbacks";
DROP TABLE IF EXISTS "public"."doc_changes";
-- ----------------------------
-- Table structure for doc_callbacks
-- ----------------------------
CREATE TABLE IF NOT EXISTS "public"."doc_callbacks" (
"id" varchar(255) COLLATE "default" NOT NULL,
"callback" text COLLATE "default" NOT NULL,
"baseurl" text COLLATE "default" NOT NULL,
PRIMARY KEY ("id")
)
WITH (OIDS=FALSE);
-- ----------------------------
-- Table structure for doc_changes
-- ----------------------------
CREATE TABLE IF NOT EXISTS "public"."doc_changes" (
"id" varchar(255) COLLATE "default" NOT NULL,
"change_id" int8 NOT NULL,
"user_id" varchar(255) COLLATE "default" NOT NULL,
"user_id_original" varchar(255) COLLATE "default" NOT NULL,
"user_name" varchar(255) COLLATE "default" NOT NULL,
"change_data" text COLLATE "default" NOT NULL,
"change_date" timestamp without time zone NOT NULL,
PRIMARY KEY ("id", "change_id")
)
WITH (OIDS=FALSE);
-- ----------------------------
-- Table structure for task_result
-- ----------------------------
CREATE TABLE IF NOT EXISTS "public"."task_result" (
"id" varchar(255) COLLATE "default" NOT NULL,
"status" int2 NOT NULL,
"status_info" int8 NOT NULL,
"last_open_date" timestamp without time zone NOT NULL,
"title" varchar(255) COLLATE "default" NOT NULL,
"user_index" int8 NOT NULL DEFAULT 1,
"change_id" int8 NOT NULL DEFAULT 0,
PRIMARY KEY ("id")
)
WITH (OIDS=FALSE);

View File

@ -0,0 +1 @@
DROP DATABASE IF EXISTS onlyoffice;