mirror of
https://github.com/ONLYOFFICE/server.git
synced 2026-02-10 18:05:07 +08:00
[ds] Bugs fixing in Oracle base connector
This commit is contained in:
@ -34,7 +34,7 @@
|
|||||||
|
|
||||||
const oracledb = require('oracledb');
|
const oracledb = require('oracledb');
|
||||||
const config = require('config');
|
const config = require('config');
|
||||||
const connectorUtilities = require("./connectorUtilities");
|
const connectorUtilities = require('./connectorUtilities');
|
||||||
|
|
||||||
const configSql = config.get('services.CoAuthoring.sql');
|
const configSql = config.get('services.CoAuthoring.sql');
|
||||||
const cfgTableResult = configSql.get('tableResult');
|
const cfgTableResult = configSql.get('tableResult');
|
||||||
@ -48,7 +48,6 @@ const connectionConfiguration = {
|
|||||||
poolMax: configSql.get('connectionlimit')
|
poolMax: configSql.get('connectionlimit')
|
||||||
};
|
};
|
||||||
let pool = null;
|
let pool = null;
|
||||||
let affectedRowsTotal = 0;
|
|
||||||
|
|
||||||
oracledb.fetchAsString = [ oracledb.NCLOB, oracledb.CLOB ];
|
oracledb.fetchAsString = [ oracledb.NCLOB, oracledb.CLOB ];
|
||||||
oracledb.autoCommit = true;
|
oracledb.autoCommit = true;
|
||||||
@ -73,12 +72,13 @@ async function sqlQuery(ctx, sqlCommand, callbackFunction, opt_noModifyRes, opt_
|
|||||||
// Query must not have any ';' in oracle connector.
|
// Query must not have any ';' in oracle connector.
|
||||||
const correctedSql = sqlCommand.replace(/;/g, '');
|
const correctedSql = sqlCommand.replace(/;/g, '');
|
||||||
|
|
||||||
|
let connection = null;
|
||||||
try {
|
try {
|
||||||
if (!pool) {
|
if (!pool) {
|
||||||
pool = await oracledb.createPool(connectionConfiguration);
|
pool = await oracledb.createPool(connectionConfiguration);
|
||||||
}
|
}
|
||||||
|
|
||||||
const connection = await pool.getConnection();
|
connection = await pool.getConnection();
|
||||||
|
|
||||||
const handler = (error, result) => {
|
const handler = (error, result) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -91,8 +91,6 @@ async function sqlQuery(ctx, sqlCommand, callbackFunction, opt_noModifyRes, opt_
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
connection.close();
|
|
||||||
|
|
||||||
let output = { rows: [], affectedRows: 0 };
|
let output = { rows: [], affectedRows: 0 };
|
||||||
if (!opt_noModifyRes) {
|
if (!opt_noModifyRes) {
|
||||||
if (result?.rowsAffected) {
|
if (result?.rowsAffected) {
|
||||||
@ -111,13 +109,17 @@ async function sqlQuery(ctx, sqlCommand, callbackFunction, opt_noModifyRes, opt_
|
|||||||
|
|
||||||
const bondedValues = opt_values ?? [];
|
const bondedValues = opt_values ?? [];
|
||||||
const outputFormat = { outFormat: !opt_noModifyRes ? oracledb.OUT_FORMAT_OBJECT : oracledb.OUT_FORMAT_ARRAY };
|
const outputFormat = { outFormat: !opt_noModifyRes ? oracledb.OUT_FORMAT_OBJECT : oracledb.OUT_FORMAT_ARRAY };
|
||||||
connection.execute(correctedSql, bondedValues, outputFormat, handler);
|
await connection.execute(correctedSql, bondedValues, outputFormat, handler);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (!opt_noLog) {
|
if (!opt_noLog) {
|
||||||
ctx.logger.error('sqlQuery error while pool manipulation: %s', error.stack);
|
ctx.logger.error('sqlQuery error while pool manipulation: %s', error.stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
callbackFunction?.(error);
|
callbackFunction?.(error);
|
||||||
|
} finally {
|
||||||
|
if (connection) {
|
||||||
|
connection.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,6 +144,40 @@ function getTableColumns(ctx, tableName) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function makeUpdateSql(dateNow, task, values, opt_updateUserIndex) {
|
||||||
|
const lastOpenDate = addSqlParameter(dateNow, values);
|
||||||
|
|
||||||
|
let callback = '';
|
||||||
|
if (task.callback) {
|
||||||
|
const parameter = addSqlParameter(JSON.stringify(task.callback), values);
|
||||||
|
callback = `, callback = callback || '${connectorUtilities.UserCallback.prototype.delimiter}{"userIndex":' || (user_index + 1) || ',"callback":' || ${parameter} || '}'`;
|
||||||
|
}
|
||||||
|
|
||||||
|
let baseUrl = '';
|
||||||
|
if (task.baseurl) {
|
||||||
|
const parameter = addSqlParameter(task.baseurl, values);
|
||||||
|
baseUrl = `, baseurl = ${parameter}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
let userIndex = '';
|
||||||
|
if (opt_updateUserIndex) {
|
||||||
|
userIndex = ', user_index = user_index + 1';
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateQuery = `last_open_date = ${lastOpenDate}${callback}${baseUrl}${userIndex}`
|
||||||
|
const tenant = addSqlParameter(task.tenant, values);
|
||||||
|
const id = addSqlParameter(task.key, values);
|
||||||
|
const condition = `tenant = ${tenant} AND id = ${id}`
|
||||||
|
|
||||||
|
const returning = addSqlParameter({ type: oracledb.NUMBER, dir: oracledb.BIND_OUT }, values);
|
||||||
|
|
||||||
|
return `UPDATE ${cfgTableResult} SET ${updateQuery} WHERE ${condition} RETURNING user_index INTO ${returning}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getReturnedValue(returned) {
|
||||||
|
return returned?.outBinds?.pop()?.pop();
|
||||||
|
}
|
||||||
|
|
||||||
function upsert(ctx, task, opt_updateUserIndex) {
|
function upsert(ctx, task, opt_updateUserIndex) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
task.completeDefaults();
|
task.completeDefaults();
|
||||||
@ -155,100 +191,61 @@ function upsert(ctx, task, opt_updateUserIndex) {
|
|||||||
|
|
||||||
const dateNow = new Date();
|
const dateNow = new Date();
|
||||||
|
|
||||||
// const values = [];
|
const insertValues = [];
|
||||||
//
|
const insertValuesPlaceholder = [
|
||||||
// const lastOpenDate = addSqlParameter(dateNow, values);
|
addSqlParameter(task.tenant, insertValues),
|
||||||
//
|
addSqlParameter(task.key, insertValues),
|
||||||
// let callback = '';
|
addSqlParameter(task.status, insertValues),
|
||||||
// if (task.callback) {
|
addSqlParameter(task.statusInfo, insertValues),
|
||||||
// const parameter = addSqlParameter(JSON.stringify(task.callback), values);
|
addSqlParameter(dateNow, insertValues),
|
||||||
// callback = `, callback = callback || '${connectorUtilities.UserCallback.prototype.delimiter}{"userIndex":' || (user_index + 1) || ',"callback":' || ${parameter} || '}'`;
|
addSqlParameter(task.userIndex, insertValues),
|
||||||
// }
|
addSqlParameter(task.changeId, insertValues),
|
||||||
//
|
addSqlParameter(cbInsert, insertValues),
|
||||||
// let baseUrl = '';
|
addSqlParameter(task.baseurl, insertValues)
|
||||||
// if (task.baseurl) {
|
|
||||||
// const parameter = addSqlParameter(task.baseurl, values);
|
|
||||||
// baseUrl = `, baseurl = ${parameter}`;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// let userIndex = '';
|
|
||||||
// if (opt_updateUserIndex) {
|
|
||||||
// userIndex = ', user_index = user_index + 1';
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// const updateQuery = `last_open_date = ${lastOpenDate}${callback}${baseUrl}${userIndex}`
|
|
||||||
// const tenant = addSqlParameter(task.tenant, values);
|
|
||||||
// const id = addSqlParameter(task.key, values);
|
|
||||||
// const condition = `tenant = ${tenant} AND id = ${id}`
|
|
||||||
//
|
|
||||||
// const returning = addSqlParameter({ type: oracledb.NUMBER, dir: oracledb.BIND_OUT }, values);
|
|
||||||
// let mergeSqlCommand = `UPDATE ${cfgTableResult} SET ${updateQuery} WHERE ${condition} RETURNING user_index INTO ${returning}`;
|
|
||||||
|
|
||||||
const values = [];
|
|
||||||
const tenant = addSqlParameter(task.tenant, values);
|
|
||||||
const id = addSqlParameter(task.key, values);
|
|
||||||
const lastOpenDate = addSqlParameter(dateNow, values);
|
|
||||||
|
|
||||||
let callback = '';
|
|
||||||
if (task.callback) {
|
|
||||||
const parameter = addSqlParameter(JSON.stringify(task.callback), values);
|
|
||||||
callback = `, callback = callback || '${connectorUtilities.UserCallback.prototype.delimiter}{"userIndex":' || (user_index + 1) || ',"callback":' || ${parameter} || '}'`;
|
|
||||||
}
|
|
||||||
|
|
||||||
let baseUrl = '';
|
|
||||||
if (task.baseurl) {
|
|
||||||
const parameter = addSqlParameter(task.baseurl, values);
|
|
||||||
baseUrl = `, baseurl = ${parameter}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
let userIndex = '';
|
|
||||||
if (opt_updateUserIndex) {
|
|
||||||
userIndex = ', user_index = user_index + 1';
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateQuery = `last_open_date = ${lastOpenDate}${callback}${baseUrl}${userIndex}`
|
|
||||||
const condition = `tenant = ${tenant} AND id = ${id}`
|
|
||||||
|
|
||||||
let mergeSqlCommand = `MERGE INTO ${cfgTableResult} USING DUAL ON (${condition})`
|
|
||||||
+ ` WHEN MATCHED THEN UPDATE SET ${updateQuery}`;
|
|
||||||
|
|
||||||
const valuesPlaceholder = [
|
|
||||||
addSqlParameter(task.tenant, values),
|
|
||||||
addSqlParameter(task.key, values),
|
|
||||||
addSqlParameter(task.status, values),
|
|
||||||
addSqlParameter(task.statusInfo, values),
|
|
||||||
addSqlParameter(dateNow, values),
|
|
||||||
addSqlParameter(task.userIndex, values),
|
|
||||||
addSqlParameter(task.changeId, values),
|
|
||||||
addSqlParameter(cbInsert, values),
|
|
||||||
addSqlParameter(task.baseurl, values)
|
|
||||||
];
|
];
|
||||||
|
|
||||||
mergeSqlCommand += ` WHEN NOT MATCHED THEN INSERT (tenant, id, status, status_info, last_open_date, user_index, change_id, callback, baseurl) VALUES (${valuesPlaceholder.join(', ')})`;
|
const returned = addSqlParameter({ type: oracledb.NUMBER, dir: oracledb.BIND_OUT }, insertValues);
|
||||||
|
let sqlInsertTry = `INSERT INTO ${cfgTableResult} (tenant, id, status, status_info, last_open_date, user_index, change_id, callback, baseurl) `
|
||||||
sqlQuery(ctx, mergeSqlCommand, function(error, result) {
|
+ `VALUES(${insertValuesPlaceholder.join(', ')}) RETURNING user_index INTO ${returned}`;
|
||||||
if (error) {
|
|
||||||
reject(error);
|
sqlQuery(ctx, sqlInsertTry, function (insertError, insertResult) {
|
||||||
|
if (insertResult) {
|
||||||
|
const insertId = getReturnedValue(insertResult);
|
||||||
|
resolve({ affectedRows: insertResult.affectedRows, insertId });
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlQuery(ctx, `SELECT user_index FROM ${cfgTableResult} WHERE tenant = :0 AND id = :1`, function (selectError, selectResult) {
|
if (insertError) {
|
||||||
if (selectError) {
|
if (insertError.code !== 'ORA-00001') {
|
||||||
reject(selectError);
|
reject(insertError);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const row = selectResult.pop();
|
const values = [];
|
||||||
result.insertId = row?.['user_index'] ?? 0;
|
sqlQuery(ctx, makeUpdateSql(dateNow, task, values, opt_updateUserIndex), function (updateError, updateResult) {
|
||||||
resolve(result);
|
if (updateError) {
|
||||||
}, false, false, [task.tenant, task.key]);
|
reject(updateError);
|
||||||
}, false, false, values);
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const insertId = getReturnedValue(updateResult);
|
||||||
|
resolve({ affectedRows: updateResult.affectedRows, insertId });
|
||||||
|
}, true, false, values);
|
||||||
|
}
|
||||||
|
}, true, true, insertValues);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function insertChanges(ctx, tableChanges, startIndex, objChanges, docId, index, user, callback) {
|
function insertChanges(ctx, tableChanges, startIndex, objChanges, docId, index, user, callback) {
|
||||||
|
let affectedRowsTotal = 0;
|
||||||
|
|
||||||
|
return insertChangesClosure.apply({ affectedRowsTotal }, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function insertChangesClosure(ctx, tableChanges, startIndex, objChanges, docId, index, user, callback) {
|
||||||
if (startIndex === objChanges.length) {
|
if (startIndex === objChanges.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -284,23 +281,24 @@ async function insertChanges(ctx, tableChanges, startIndex, objChanges, docId, i
|
|||||||
];
|
];
|
||||||
|
|
||||||
insertAllSqlCommand += `INTO ${tableChanges} VALUES(${valuesPlaceholder.join(',')}) `;
|
insertAllSqlCommand += `INTO ${tableChanges} VALUES(${valuesPlaceholder.join(',')}) `;
|
||||||
|
lengthUtf8Current += lengthUtf8Row;
|
||||||
}
|
}
|
||||||
|
|
||||||
insertAllSqlCommand += 'SELECT 1 FROM DUAL';
|
insertAllSqlCommand += 'SELECT 1 FROM DUAL';
|
||||||
|
|
||||||
sqlQuery(ctx, insertAllSqlCommand, function (error, result) {
|
sqlQuery(ctx, insertAllSqlCommand, (error, result) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
callback(error, null, true);
|
callback(error, null, true);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
affectedRowsTotal += result.affectedRows;
|
this.affectedRowsTotal += result.affectedRows;
|
||||||
if (packetCapacityReached) {
|
if (packetCapacityReached) {
|
||||||
insertChanges(ctx, tableChanges, currentIndex, objChanges, docId, index, user, callback);
|
insertChanges.apply(this, [ctx, tableChanges, currentIndex, objChanges, docId, index, user, callback]);
|
||||||
} else {
|
} else {
|
||||||
result.affectedRows = affectedRowsTotal;
|
result.affectedRows = this.affectedRowsTotal;
|
||||||
affectedRowsTotal = 0;
|
this.affectedRowsTotal = 0;
|
||||||
callback(error, result, true);
|
callback(error, result, true);
|
||||||
}
|
}
|
||||||
}, false, false, values);
|
}, false, false, values);
|
||||||
|
|||||||
@ -16,6 +16,7 @@ CREATE TABLE onlyoffice.doc_changes (
|
|||||||
user_name NVARCHAR2(255) NOT NULL,
|
user_name NVARCHAR2(255) NOT NULL,
|
||||||
change_data NCLOB NOT NULL,
|
change_data NCLOB NOT NULL,
|
||||||
change_date TIMESTAMP NOT NULL,
|
change_date TIMESTAMP NOT NULL,
|
||||||
|
CONSTRAINT doc_changes_unique UNIQUE (tenant, id, change_id),
|
||||||
CONSTRAINT doc_changes_unsigned_int CHECK (change_id between 0 and 4294967295)
|
CONSTRAINT doc_changes_unsigned_int CHECK (change_id between 0 and 4294967295)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -36,5 +37,6 @@ CREATE TABLE onlyoffice.task_result (
|
|||||||
baseurl NCLOB, -- codebase uses '' as default values here, but Oracle treat '' as NULL, so NULL permitted for this value.
|
baseurl NCLOB, -- codebase uses '' as default values here, but Oracle treat '' as NULL, so NULL permitted for this value.
|
||||||
password NCLOB NULL,
|
password NCLOB NULL,
|
||||||
additional NCLOB NULL,
|
additional NCLOB NULL,
|
||||||
|
CONSTRAINT task_result_unique UNIQUE (tenant, id),
|
||||||
CONSTRAINT task_result_unsigned_int CHECK (user_index BETWEEN 0 AND 4294967295 AND change_id BETWEEN 0 AND 4294967295)
|
CONSTRAINT task_result_unsigned_int CHECK (user_index BETWEEN 0 AND 4294967295 AND change_id BETWEEN 0 AND 4294967295)
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user