[ds] Bugs fixing in Oracle base connector

This commit is contained in:
Georgii Petrov
2023-07-17 16:55:03 +03:00
parent 3d66727cfa
commit b85dad459a
2 changed files with 92 additions and 92 deletions

View File

@ -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);

View File

@ -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)
); );