mirror of
https://github.com/ONLYOFFICE/server.git
synced 2026-02-10 18:05:07 +08:00
[bug] Fix sql for oracle NCLOB type; Fix bug 77666
This commit is contained in:
@ -439,6 +439,17 @@ function getTableColumns(ctx, tableName) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate SQL condition to check if a field is not empty (fallback implementation)
|
||||
* Database-specific connectors can override this function
|
||||
* @param {string} fieldName - Name of the field to check
|
||||
* @returns {string} SQL condition string
|
||||
*/
|
||||
function getNotEmptyConditionFallback(fieldName) {
|
||||
// Default implementation for most databases: check both NULL and empty string
|
||||
return `${fieldName} IS NOT NULL AND ${fieldName} != ''`;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
insertChangesPromise,
|
||||
deleteChangesPromise,
|
||||
@ -454,5 +465,7 @@ module.exports = {
|
||||
getTableColumns,
|
||||
getDateTime: _getDateTime2,
|
||||
...connectorUtilities,
|
||||
...dbInstance
|
||||
...dbInstance,
|
||||
// Use connector-specific implementation if available, otherwise use fallback
|
||||
getNotEmptyCondition: dbInstance.getNotEmptyCondition || getNotEmptyConditionFallback
|
||||
};
|
||||
|
||||
@ -445,6 +445,16 @@ async function insertChangesAsync(ctx, tableChanges, startIndex, objChanges, doc
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate SQL condition to check if a field is not empty
|
||||
* Oracle-specific: NCLOB cannot be compared with != operator, and empty strings are NULL
|
||||
* @param {string} fieldName - Name of the field to check
|
||||
* @returns {string} SQL condition string
|
||||
*/
|
||||
function getNotEmptyCondition(fieldName) {
|
||||
return `${fieldName} IS NOT NULL`;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
sqlQuery,
|
||||
closePool,
|
||||
@ -456,5 +466,6 @@ module.exports = {
|
||||
getDocumentsWithChanges,
|
||||
getExpired,
|
||||
upsert,
|
||||
insertChanges
|
||||
insertChanges,
|
||||
getNotEmptyCondition
|
||||
};
|
||||
|
||||
@ -135,7 +135,7 @@ function select(ctx, docId) {
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Convert task object to SQL update/condition array
|
||||
* Generate SQL SET/WHERE clauses from task object
|
||||
* @param {TaskResultData} task - Task data object
|
||||
* @param {boolean} updateTime - Whether to update last_open_date
|
||||
* @param {boolean} isMask - Whether this is for WHERE clause (mask mode)
|
||||
@ -145,7 +145,7 @@ function select(ctx, docId) {
|
||||
*
|
||||
* Special mask values:
|
||||
* - Use 'NOT_EMPTY' as field value in mask mode to check for non-empty callback
|
||||
* - Example: {callback: 'NOT_EMPTY'} generates "callback IS NOT NULL AND callback != ''"
|
||||
* - Uses baseConnector.getNotEmptyCondition() for database-specific SQL generation
|
||||
*/
|
||||
function toUpdateArray(task, updateTime, isMask, values, setPassword) {
|
||||
const res = [];
|
||||
@ -177,7 +177,8 @@ function toUpdateArray(task, updateTime, isMask, values, setPassword) {
|
||||
}
|
||||
// Add callback non-empty check for mask
|
||||
if (isMask && task.callback === 'NOT_EMPTY') {
|
||||
res.push(`callback IS NOT NULL AND callback != ''`);
|
||||
// Use database-specific condition (Oracle NCLOB needs special handling)
|
||||
res.push(sqlBase.getNotEmptyCondition('callback'));
|
||||
}
|
||||
if (null != task.baseurl) {
|
||||
const sqlParam = addSqlParam(task.baseurl, values);
|
||||
|
||||
@ -210,7 +210,14 @@ afterAll(async () => {
|
||||
const updateIfIds = Object.values(updateIfCases);
|
||||
|
||||
const tableChangesIds = [...emptyCallbacksCase, ...documentsWithChangesCase, ...changesIds, ...insertIds];
|
||||
const tableResultIds = [...emptyCallbacksCase, ...documentsWithChangesCase, ...getExpiredCase, ...getCountWithStatusCase, ...upsertIds, ...updateIfIds];
|
||||
const tableResultIds = [
|
||||
...emptyCallbacksCase,
|
||||
...documentsWithChangesCase,
|
||||
...getExpiredCase,
|
||||
...getCountWithStatusCase,
|
||||
...upsertIds,
|
||||
...updateIfIds
|
||||
];
|
||||
|
||||
const deletionPool = [
|
||||
deleteRowsByIds(cfgTableChanges, tableChangesIds),
|
||||
@ -292,17 +299,23 @@ describe('Base database connector', () => {
|
||||
|
||||
describe('Add changes', () => {
|
||||
for (const testCase in insertCases) {
|
||||
test(`${testCase} rows inserted`, async () => {
|
||||
const docId = insertCases[testCase];
|
||||
const objChanges = createChanges(+testCase, date);
|
||||
// Increase timeout for large inserts (5000+ rows can take longer on some databases)
|
||||
const timeout = +testCase >= 5000 ? 15000 : 5000;
|
||||
test(
|
||||
`${testCase} rows inserted`,
|
||||
async () => {
|
||||
const docId = insertCases[testCase];
|
||||
const objChanges = createChanges(+testCase, date);
|
||||
|
||||
await noRowsExistenceCheck(cfgTableChanges, docId);
|
||||
await noRowsExistenceCheck(cfgTableChanges, docId);
|
||||
|
||||
await baseConnector.insertChangesPromise(ctx, objChanges, docId, index, user);
|
||||
const result = await getRowsCountById(cfgTableChanges, docId);
|
||||
await baseConnector.insertChangesPromise(ctx, objChanges, docId, index, user);
|
||||
const result = await getRowsCountById(cfgTableChanges, docId);
|
||||
|
||||
expect(result).toEqual(objChanges.length);
|
||||
});
|
||||
expect(result).toEqual(objChanges.length);
|
||||
},
|
||||
timeout
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@ -482,10 +495,7 @@ describe('Base database connector', () => {
|
||||
const taskEmptyCallback = createTask(updateIfCases.emptyCallback, '');
|
||||
|
||||
// Insert two rows: one with callback, one without
|
||||
await Promise.all([
|
||||
insertIntoResultTable(date, taskWithCallback),
|
||||
insertIntoResultTable(date, taskEmptyCallback)
|
||||
]);
|
||||
await Promise.all([insertIntoResultTable(date, taskWithCallback), insertIntoResultTable(date, taskEmptyCallback)]);
|
||||
|
||||
// Update mask: only update rows with non-empty callback and status=None
|
||||
const mask = new taskResult.TaskResultData();
|
||||
|
||||
Reference in New Issue
Block a user