From cb5e4f30ffcefda9c5991b0c7c96824f865c06c0 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Sat, 18 Jun 2022 20:20:30 +0800 Subject: [PATCH 01/19] fix: handle ? in column name when inserting & updating --- .../db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts | 16 +++++++--------- packages/nocodb/src/lib/models/Model.ts | 7 +++---- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts index d26e1459dd..463bf603ed 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts @@ -1242,7 +1242,7 @@ class BaseModelSqlv2 { await populatePk(this.model, data); // todo: filter based on view - const insertObj = await this.model.mapAliasToColumn(data, sanitize); + const insertObj = await this.model.mapAliasToColumn(data); await this.validate(insertObj); @@ -1275,11 +1275,12 @@ class BaseModelSqlv2 { if (response?.length) { id = response[0]; } else { - id = (await query)[0]; + id = ( + await this.dbDriver.raw(query.toString().replaceAll('\\?', '?')) + )[0].insertId; } if (ai) { - // response = await this.readByPk(id) response = await this.readByPk(id); } else { response = data; @@ -1326,14 +1327,11 @@ class BaseModelSqlv2 { await this.beforeUpdate(data, trx, cookie); - // const driver = trx ? trx : this.dbDriver; - // - // this.validate(data); - // await this._run( - await this.dbDriver(this.tnPath) + const query = this.dbDriver(this.tnPath) .update(updateObj) .where(await this._wherePk(id)); - // ); + + await this.dbDriver.raw(query.toString().replaceAll('\\?', '?')); const response = await this.readByPk(id); await this.afterUpdate(response, trx, cookie); diff --git a/packages/nocodb/src/lib/models/Model.ts b/packages/nocodb/src/lib/models/Model.ts index 5f2e111f81..d9dceedef2 100644 --- a/packages/nocodb/src/lib/models/Model.ts +++ b/packages/nocodb/src/lib/models/Model.ts @@ -399,13 +399,12 @@ export default class Model implements TableType { return true; } - async mapAliasToColumn(data, sanitize = v => v) { + async mapAliasToColumn(data) { const insertObj = {}; for (const col of await this.getColumns()) { if (isVirtualCol(col)) continue; - const val = - data?.[sanitize(col.column_name)] ?? data?.[sanitize(col.title)]; - if (val !== undefined) insertObj[sanitize(col.column_name)] = val; + const val = data?.[col.column_name] ?? data?.[col.title]; + insertObj[col.column_name.replaceAll('?', '\\\\?')] = val; } return insertObj; } From 624f12cd75e21e604d13e1e1fe9f0c9a61b336b5 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 20 Jun 2022 12:55:24 +0800 Subject: [PATCH 02/19] fix: undefined insertId --- .../src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts index 463bf603ed..7f9cebfc13 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts @@ -1277,10 +1277,10 @@ class BaseModelSqlv2 { } else { id = ( await this.dbDriver.raw(query.toString().replaceAll('\\?', '?')) - )[0].insertId; + )[0]?.insertId; } - if (ai) { + if (ai && id) { response = await this.readByPk(id); } else { response = data; From 593da68b0c0d05a2c21b8fd9f7d9c10c71e58316 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 20 Jun 2022 14:30:02 +0800 Subject: [PATCH 03/19] fix: revise sanitize logic --- .../src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts index 7f9cebfc13..f19dd58edb 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts @@ -241,7 +241,6 @@ class BaseModelSqlv2 { if (!ignoreFilterSort) applyPaginate(qb, rest); const proto = await this.getProto(); - const data = await this.extractRawQueryAndExec(qb); return data?.map(d => { @@ -2027,10 +2026,11 @@ class BaseModelSqlv2 { } private async extractRawQueryAndExec(qb: QueryBuilder) { + const query = qb.toQuery().replaceAll('\\?', '?'); return this.isPg - ? qb + ? (await this.dbDriver.raw(query))?.rows : await this.dbDriver.from( - this.dbDriver.raw(qb.toString()).wrap('(', ') __nc_alias') + this.dbDriver.raw(query).wrap('(', ') __nc_alias') ); } } @@ -2167,7 +2167,7 @@ function getCompositePk(primaryKeys: Column[], row) { } export function sanitize(v) { - return v?.replace(/([^\\]|^)([?])/g, '$1\\$2'); + return v?.replaceAll('?', '\\\\?'); } export { BaseModelSqlv2 }; From 7e6684d7ce17d0e3dbbf926f00f1c436049e3f81 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 20 Jun 2022 15:54:43 +0800 Subject: [PATCH 04/19] chore: use nc-help@0.2.64 --- packages/nocodb/package-lock.json | 14 +++++++------- packages/nocodb/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/nocodb/package-lock.json b/packages/nocodb/package-lock.json index 77e77715d0..6ed3a78bfa 100644 --- a/packages/nocodb/package-lock.json +++ b/packages/nocodb/package-lock.json @@ -70,7 +70,7 @@ "mysql2": "^2.2.5", "nanoid": "^3.1.20", "nc-common": "0.0.6", - "nc-help": "0.2.63", + "nc-help": "0.2.64", "nc-lib-gui": "0.91.10", "nc-plugin": "0.1.2", "ncp": "^2.0.0", @@ -16352,9 +16352,9 @@ } }, "node_modules/nc-help": { - "version": "0.2.63", - "resolved": "https://registry.npmjs.org/nc-help/-/nc-help-0.2.63.tgz", - "integrity": "sha512-eB3XRRi4JyCIsCiniyvsSciKeDZovSkkxYxxAOY7JK65pbACfGETKhAhjHBm7BinWOOBVoqaAJFabZcBUHgvcg==", + "version": "0.2.64", + "resolved": "https://registry.npmjs.org/nc-help/-/nc-help-0.2.64.tgz", + "integrity": "sha512-1LwnV4Fo2czAzjTkjMeMFOAPQyqSipuzauK7gs0zbAXyF9QiMzTfQcMJqD85NTRFCJ1d39Bbn8GmuhqYZ28/mQ==", "dependencies": { "@rudderstack/rudder-sdk-node": "^1.1.3", "axios": "^0.21.1", @@ -38040,9 +38040,9 @@ "integrity": "sha512-3AryS9uwa5NfISLxMciUonrH7YfXp+nlahB9T7girXIsLQrmwX4MdnuKs32akduCOGpKmjTJSWmATULbuMkbfw==" }, "nc-help": { - "version": "0.2.63", - "resolved": "https://registry.npmjs.org/nc-help/-/nc-help-0.2.63.tgz", - "integrity": "sha512-eB3XRRi4JyCIsCiniyvsSciKeDZovSkkxYxxAOY7JK65pbACfGETKhAhjHBm7BinWOOBVoqaAJFabZcBUHgvcg==", + "version": "0.2.64", + "resolved": "https://registry.npmjs.org/nc-help/-/nc-help-0.2.64.tgz", + "integrity": "sha512-1LwnV4Fo2czAzjTkjMeMFOAPQyqSipuzauK7gs0zbAXyF9QiMzTfQcMJqD85NTRFCJ1d39Bbn8GmuhqYZ28/mQ==", "requires": { "@rudderstack/rudder-sdk-node": "^1.1.3", "axios": "^0.21.1", diff --git a/packages/nocodb/package.json b/packages/nocodb/package.json index f0ad784972..cedc1adf9c 100644 --- a/packages/nocodb/package.json +++ b/packages/nocodb/package.json @@ -154,7 +154,7 @@ "mysql2": "^2.2.5", "nanoid": "^3.1.20", "nc-common": "0.0.6", - "nc-help": "0.2.63", + "nc-help": "0.2.64", "nc-lib-gui": "0.91.10", "nc-plugin": "0.1.2", "ncp": "^2.0.0", From 04fe0dc619087e0db2f16afdd89aa807b994705d Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 20 Jun 2022 16:37:55 +0800 Subject: [PATCH 05/19] fix: binding in filter --- .../lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts | 5 +++-- .../src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts | 10 ++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts index f19dd58edb..166541850f 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts @@ -308,8 +308,9 @@ class BaseModelSqlv2 { qb.count(this.model.primaryKey?.column_name || '*', { as: 'count' }).first(); - - return ((await qb) as any).count; + return ((await this.dbDriver.raw( + qb.toQuery().replaceAll('\\?', '?') + )) as any)[0][0].count; } async groupBy( diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts index 4828369ecd..c78b29733e 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts @@ -203,16 +203,18 @@ const parseConditionV2 = async ( filter.comparison_op === 'notempty' ) filter.value = ''; - let field = customWhereClause + let field = (customWhereClause ? filter.value : alias ? `${alias}.${column.column_name}` - : column.column_name; + : column.column_name + ).replaceAll('?', '\\\\?'); let val = customWhereClause ? customWhereClause : filter.value; return qb => { switch (filter.comparison_op) { case 'eq': + console.log(qb.toQuery()); qb = qb.where(field, val); break; case 'neq': @@ -221,7 +223,7 @@ const parseConditionV2 = async ( case 'like': if (column.uidt === UITypes.Formula) { [field, val] = [val, field]; - val = `%${val}%`.replace(/^%'([\s\S]*)'%$/, '%$1%') + val = `%${val}%`.replace(/^%'([\s\S]*)'%$/, '%$1%'); } else { val = `%${val}%`; } @@ -234,7 +236,7 @@ const parseConditionV2 = async ( case 'nlike': if (column.uidt === UITypes.Formula) { [field, val] = [val, field]; - val = `%${val}%`.replace(/^%'([\s\S]*)'%$/, '%$1%') + val = `%${val}%`.replace(/^%'([\s\S]*)'%$/, '%$1%'); } else { val = `%${val}%`; } From 303d958042ce714886f15a07f548c725f7eded77 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 20 Jun 2022 16:53:58 +0800 Subject: [PATCH 06/19] refactor: put sanitize to helpers --- .../src/lib/db/sql-data-mapper/lib/sql/helpers/sanitize.ts | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/sanitize.ts diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/sanitize.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/sanitize.ts new file mode 100644 index 0000000000..f52d6666ad --- /dev/null +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/sanitize.ts @@ -0,0 +1,7 @@ +export function sanitize(v) { + return v?.replaceAll('?', '\\\\?'); +} + +export function unsanitize(v) { + return v?.replaceAll('\\?', '?'); +} From b4172c382c47084ab999991457a3000bd5b75e4a Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 20 Jun 2022 16:54:17 +0800 Subject: [PATCH 07/19] fix: binding in sort --- packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/sortV2.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/sortV2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/sortV2.ts index 91a8efe1c6..e17ceb38c8 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/sortV2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/sortV2.ts @@ -8,6 +8,7 @@ import LookupColumn from '../../../../models/LookupColumn'; import formulaQueryBuilderv2 from './formulav2/formulaQueryBuilderv2'; import FormulaColumn from '../../../../models/FormulaColumn'; import { RelationTypes, UITypes } from 'nocodb-sdk'; +import { sanitize } from './helpers/sanitize'; export default async function sortV2( sortList: Sort[], @@ -205,7 +206,7 @@ export default async function sortV2( } break; default: - qb.orderBy(`${column.column_name}`, sort.direction || 'asc'); + qb.orderBy(sanitize(column.column_name), sort.direction || 'asc'); break; } } From c31b5cbc5175426f9d79c8b08e32ed0a607a4f74 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 20 Jun 2022 17:09:57 +0800 Subject: [PATCH 08/19] fix: binding in conditions --- .../lib/db/sql-data-mapper/lib/sql/conditionV2.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts index c78b29733e..31b83f4d7e 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts @@ -10,6 +10,7 @@ import formulaQueryBuilderv2 from './formulav2/formulaQueryBuilderv2'; import FormulaColumn from '../../../../models/FormulaColumn'; import { RelationTypes, UITypes } from 'nocodb-sdk'; // import LookupColumn from '../../../models/LookupColumn'; +import { sanitize } from './helpers/sanitize'; export default async function conditionV2( conditionObj: Filter | Filter[], @@ -203,12 +204,13 @@ const parseConditionV2 = async ( filter.comparison_op === 'notempty' ) filter.value = ''; - let field = (customWhereClause - ? filter.value - : alias - ? `${alias}.${column.column_name}` - : column.column_name - ).replaceAll('?', '\\\\?'); + let field = sanitize( + customWhereClause + ? filter.value + : alias + ? `${alias}.${column.column_name}` + : column.column_name + ); let val = customWhereClause ? customWhereClause : filter.value; return qb => { From 44f9fdeb7cd862f59fd96ddd9c775e5f20556dc1 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 20 Jun 2022 17:10:11 +0800 Subject: [PATCH 09/19] fix: binding in hm & bt --- .../lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts index 166541850f..3b8f97c68b 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts @@ -41,6 +41,7 @@ import { customValidators } from './customValidators'; import { NcError } from '../../../../meta/helpers/catchError'; import { customAlphabet } from 'nanoid'; import DOMPurify from 'isomorphic-dompurify'; +import { sanitize, unsanitize } from './helpers/sanitize'; const GROUP_COL = '__nc_group_id'; @@ -907,7 +908,7 @@ class BaseModelSqlv2 { const proto = await childModel.getProto(); - return (await qb).map(c => { + return (await this.dbDriver.raw(unsanitize(qb.toQuery())))[0].map(c => { c.__proto__ = proto; return c; }); @@ -993,8 +994,7 @@ class BaseModelSqlv2 { applyPaginate(qb, args); const proto = await parentModel.getProto(); - - return (await qb).map(c => { + return (await this.dbDriver.raw(unsanitize(qb.toQuery())))[0].map(c => { c.__proto__ = proto; return c; }); @@ -2167,10 +2167,6 @@ function getCompositePk(primaryKeys: Column[], row) { return primaryKeys.map(c => row[c.title]).join('___'); } -export function sanitize(v) { - return v?.replaceAll('?', '\\\\?'); -} - export { BaseModelSqlv2 }; /** * @copyright Copyright (c) 2021, Xgene Cloud Ltd From dd1b7371eb8849543c737e50a7873a921df0a80a Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 20 Jun 2022 17:26:06 +0800 Subject: [PATCH 10/19] chore: remove debug log --- .../nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts index 31b83f4d7e..063a052bb4 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts @@ -216,7 +216,6 @@ const parseConditionV2 = async ( return qb => { switch (filter.comparison_op) { case 'eq': - console.log(qb.toQuery()); qb = qb.where(field, val); break; case 'neq': From 6357a9e9e7ea1f345f7a141e45628be393c2c3b6 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 20 Jun 2022 17:42:17 +0800 Subject: [PATCH 11/19] fix: res in count --- .../src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts index 3b8f97c68b..4b513f1e79 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts @@ -309,9 +309,10 @@ class BaseModelSqlv2 { qb.count(this.model.primaryKey?.column_name || '*', { as: 'count' }).first(); - return ((await this.dbDriver.raw( + const res = (await this.dbDriver.raw( qb.toQuery().replaceAll('\\?', '?') - )) as any)[0][0].count; + )) as any; + return (this.isPg ? res.rows[0] : res[0][0] ?? res[0]).count; } async groupBy( From 164913218aed3ae9109a83233681a70a3aea58cf Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 20 Jun 2022 19:08:51 +0800 Subject: [PATCH 12/19] refactor: use existing extractRawQueryAndExec function --- .../src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts index 4b513f1e79..d39e459354 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts @@ -909,7 +909,7 @@ class BaseModelSqlv2 { const proto = await childModel.getProto(); - return (await this.dbDriver.raw(unsanitize(qb.toQuery())))[0].map(c => { + return (await this.extractRawQueryAndExec(qb)).map(c => { c.__proto__ = proto; return c; }); @@ -995,7 +995,7 @@ class BaseModelSqlv2 { applyPaginate(qb, args); const proto = await parentModel.getProto(); - return (await this.dbDriver.raw(unsanitize(qb.toQuery())))[0].map(c => { + return (await this.extractRawQueryAndExec(qb)).map(c => { c.__proto__ = proto; return c; }); @@ -2028,7 +2028,7 @@ class BaseModelSqlv2 { } private async extractRawQueryAndExec(qb: QueryBuilder) { - const query = qb.toQuery().replaceAll('\\?', '?'); + const query = unsanitize(qb.toQuery()); return this.isPg ? (await this.dbDriver.raw(query))?.rows : await this.dbDriver.from( From 9ec63d3a1ab9eb63ee287c00b9b7a8639c4acb94 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 20 Jun 2022 22:26:08 +0800 Subject: [PATCH 13/19] fix: insert returning id --- .../sql-data-mapper/lib/sql/BaseModelSqlv2.ts | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts index d39e459354..1205944312 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts @@ -1276,12 +1276,19 @@ class BaseModelSqlv2 { if (response?.length) { id = response[0]; } else { - id = ( - await this.dbDriver.raw(query.toString().replaceAll('\\?', '?')) - )[0]?.insertId; + const res = await this.extractRawQueryAndExec(query); + id = res.id ?? res[0].insertId; } - if (ai && id) { + if (ai) { + if (this.isSqlite) { + // sqlite doesnt return id after insert + id = ( + await this.dbDriver(this.tnPath) + .select(ai.column_name) + .max(ai.column_name, { as: 'id' }) + )[0].id; + } response = await this.readByPk(id); } else { response = data; @@ -1332,7 +1339,7 @@ class BaseModelSqlv2 { .update(updateObj) .where(await this._wherePk(id)); - await this.dbDriver.raw(query.toString().replaceAll('\\?', '?')); + await this.extractRawQueryAndExec(query); const response = await this.readByPk(id); await this.afterUpdate(response, trx, cookie); @@ -2029,11 +2036,14 @@ class BaseModelSqlv2 { private async extractRawQueryAndExec(qb: QueryBuilder) { const query = unsanitize(qb.toQuery()); - return this.isPg - ? (await this.dbDriver.raw(query))?.rows - : await this.dbDriver.from( - this.dbDriver.raw(query).wrap('(', ') __nc_alias') - ); + if (query.slice(0, 6) === 'select') { + return this.isPg + ? (await this.dbDriver.raw(query))?.rows + : await this.dbDriver.from( + this.dbDriver.raw(query).wrap('(', ') __nc_alias') + ); + } + return await this.dbDriver.raw(query); } } From 28fd180c0326f110c486d25c87eb0e6817c32f29 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 20 Jun 2022 22:43:00 +0800 Subject: [PATCH 14/19] fix: handle undefined insertId --- .../nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts index 1205944312..5f44b8fe26 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts @@ -1277,7 +1277,7 @@ class BaseModelSqlv2 { id = response[0]; } else { const res = await this.extractRawQueryAndExec(query); - id = res.id ?? res[0].insertId; + id = res?.id ?? res[0]?.insertId; } if (ai) { From 85ffddd330a37f4c08702d69a5b2b4bff105d10c Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Tue, 21 Jun 2022 01:28:08 +0800 Subject: [PATCH 15/19] fix: revise extractRawQueryAndExec logic --- .../db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts index 5f44b8fe26..e991c5a8ab 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts @@ -2036,14 +2036,13 @@ class BaseModelSqlv2 { private async extractRawQueryAndExec(qb: QueryBuilder) { const query = unsanitize(qb.toQuery()); - if (query.slice(0, 6) === 'select') { - return this.isPg - ? (await this.dbDriver.raw(query))?.rows - : await this.dbDriver.from( - this.dbDriver.raw(query).wrap('(', ') __nc_alias') - ); - } - return await this.dbDriver.raw(query); + return this.isPg + ? (await this.dbDriver.raw(query))?.rows + : query.slice(0, 6) === 'select' + ? await this.dbDriver.from( + this.dbDriver.raw(query).wrap('(', ') __nc_alias') + ) + : await this.dbDriver.raw(query); } } From 4ff1137af5ab447600cc90834e3c9a18180db1d8 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Fri, 24 Jun 2022 23:09:51 +0800 Subject: [PATCH 16/19] fix: avoid using replaceAll --- .../lib/db/sql-data-mapper/lib/sql/helpers/sanitize.ts | 6 ++++-- packages/nocodb/src/lib/models/Model.ts | 8 +++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/sanitize.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/sanitize.ts index f52d6666ad..a98be3b9e7 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/sanitize.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/sanitize.ts @@ -1,7 +1,9 @@ export function sanitize(v) { - return v?.replaceAll('?', '\\\\?'); + return v?.replace(/([^\\]|^)(\?+)/g, (_, m1, m2) => { + return `${m1}${m2.split('?').join('\\?')}`; + }); } export function unsanitize(v) { - return v?.replaceAll('\\?', '?'); + return v?.replace(/\\[?]/g, '?'); } diff --git a/packages/nocodb/src/lib/models/Model.ts b/packages/nocodb/src/lib/models/Model.ts index d9dceedef2..9cbf4f7ebc 100644 --- a/packages/nocodb/src/lib/models/Model.ts +++ b/packages/nocodb/src/lib/models/Model.ts @@ -404,7 +404,13 @@ export default class Model implements TableType { for (const col of await this.getColumns()) { if (isVirtualCol(col)) continue; const val = data?.[col.column_name] ?? data?.[col.title]; - insertObj[col.column_name.replaceAll('?', '\\\\?')] = val; + if (val !== undefined) { + insertObj[ + col.column_name.replace(/([^\\]|^)(\?+)/g, (_, m1, m2) => { + return `${m1}${m2.split('?').join('\\?')}`; + }) + ] = val; + } } return insertObj; } From 3e27b3b0886ce4cd65f9efd97b7a1cd9f44b0de4 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Fri, 24 Jun 2022 23:10:15 +0800 Subject: [PATCH 17/19] fix: mssql & pg knex binding logic --- packages/nocodb/package-lock.json | 14 +++++++------- packages/nocodb/package.json | 2 +- .../db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts | 10 +++++++--- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/packages/nocodb/package-lock.json b/packages/nocodb/package-lock.json index 39f5a9c7a7..ea09eca342 100644 --- a/packages/nocodb/package-lock.json +++ b/packages/nocodb/package-lock.json @@ -70,7 +70,7 @@ "mysql2": "^2.2.5", "nanoid": "^3.1.20", "nc-common": "0.0.6", - "nc-help": "0.2.65", + "nc-help": "0.2.67", "nc-lib-gui": "0.91.10", "nc-plugin": "0.1.2", "ncp": "^2.0.0", @@ -16352,9 +16352,9 @@ } }, "node_modules/nc-help": { - "version": "0.2.65", - "resolved": "https://registry.npmjs.org/nc-help/-/nc-help-0.2.65.tgz", - "integrity": "sha512-Sia+ZhfrCCFu70khjVCUMJ7B8xYlSyfatKt7WERDzqiykC7rOGFxfyhKPfhDzep+X1CDT3R+psd4lTi4d52wdg==", + "version": "0.2.67", + "resolved": "https://registry.npmjs.org/nc-help/-/nc-help-0.2.67.tgz", + "integrity": "sha512-O9eXHrpO0dBdFv6zUZAos+63JZEGhZ2lG+MduGZ+/BL7M5b0qU7d9b95Pmgq6Gd5wO3txT/7x7uPBHZxeSgvHQ==", "dependencies": { "@rudderstack/rudder-sdk-node": "^1.1.3", "axios": "^0.21.1", @@ -38040,9 +38040,9 @@ "integrity": "sha512-3AryS9uwa5NfISLxMciUonrH7YfXp+nlahB9T7girXIsLQrmwX4MdnuKs32akduCOGpKmjTJSWmATULbuMkbfw==" }, "nc-help": { - "version": "0.2.65", - "resolved": "https://registry.npmjs.org/nc-help/-/nc-help-0.2.65.tgz", - "integrity": "sha512-Sia+ZhfrCCFu70khjVCUMJ7B8xYlSyfatKt7WERDzqiykC7rOGFxfyhKPfhDzep+X1CDT3R+psd4lTi4d52wdg==", + "version": "0.2.67", + "resolved": "https://registry.npmjs.org/nc-help/-/nc-help-0.2.67.tgz", + "integrity": "sha512-O9eXHrpO0dBdFv6zUZAos+63JZEGhZ2lG+MduGZ+/BL7M5b0qU7d9b95Pmgq6Gd5wO3txT/7x7uPBHZxeSgvHQ==", "requires": { "@rudderstack/rudder-sdk-node": "^1.1.3", "axios": "^0.21.1", diff --git a/packages/nocodb/package.json b/packages/nocodb/package.json index 1fe2c7e14a..acf28f21e3 100644 --- a/packages/nocodb/package.json +++ b/packages/nocodb/package.json @@ -154,7 +154,7 @@ "mysql2": "^2.2.5", "nanoid": "^3.1.20", "nc-common": "0.0.6", - "nc-help": "0.2.65", + "nc-help": "0.2.67", "nc-lib-gui": "0.91.10", "nc-plugin": "0.1.2", "ncp": "^2.0.0", diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts index e991c5a8ab..f586e30afd 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts @@ -1259,12 +1259,11 @@ class BaseModelSqlv2 { // const driver = trx ? trx : this.dbDriver; const query = this.dbDriver(this.tnPath).insert(insertObj); - if (this.isPg || this.isMssql) { query.returning( `${this.model.primaryKey.column_name} as ${this.model.primaryKey.title}` ); - response = await query; + response = await this.extractRawQueryAndExec(query); } const ai = this.model.columns.find(c => c.ai); @@ -2035,7 +2034,12 @@ class BaseModelSqlv2 { } private async extractRawQueryAndExec(qb: QueryBuilder) { - const query = unsanitize(qb.toQuery()); + let query = qb.toQuery(); + if (!this.isPg && !this.isMssql) { + query = unsanitize(qb.toQuery()); + } else { + query = sanitize(query); + } return this.isPg ? (await this.dbDriver.raw(query))?.rows : query.slice(0, 6) === 'select' From 271fe9ba13055a240e4688ccd77452c5b4cd9742 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Tue, 28 Jun 2022 11:26:55 +0800 Subject: [PATCH 18/19] refactor: revise based on PR comment --- .../src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts | 4 +--- packages/nocodb/src/lib/models/Model.ts | 7 ++----- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts index 5845709f3a..e575d7e54d 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts @@ -314,9 +314,7 @@ class BaseModelSqlv2 { qb.count(this.model.primaryKey?.column_name || '*', { as: 'count' }).first(); - const res = (await this.dbDriver.raw( - qb.toQuery().replaceAll('\\?', '?') - )) as any; + const res = (await this.dbDriver.raw(unsanitize(qb.toQuery()))) as any; return (this.isPg ? res.rows[0] : res[0][0] ?? res[0]).count; } diff --git a/packages/nocodb/src/lib/models/Model.ts b/packages/nocodb/src/lib/models/Model.ts index 9cbf4f7ebc..4ae39940aa 100644 --- a/packages/nocodb/src/lib/models/Model.ts +++ b/packages/nocodb/src/lib/models/Model.ts @@ -20,6 +20,7 @@ import { import View from './View'; import { NcError } from '../meta/helpers/catchError'; import Audit from './Audit'; +import { sanitize } from '../db/sql-data-mapper/lib/sql/helpers/sanitize'; export default class Model implements TableType { copy_enabled: boolean; @@ -405,11 +406,7 @@ export default class Model implements TableType { if (isVirtualCol(col)) continue; const val = data?.[col.column_name] ?? data?.[col.title]; if (val !== undefined) { - insertObj[ - col.column_name.replace(/([^\\]|^)(\?+)/g, (_, m1, m2) => { - return `${m1}${m2.split('?').join('\\?')}`; - }) - ] = val; + insertObj[sanitize(col.column_name)] = val; } } return insertObj; From e20a2dcf833c396da44e7a94d0eedb75e84a3fdb Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Tue, 28 Jun 2022 11:36:19 +0800 Subject: [PATCH 19/19] fix: sanitize column name & unsanitize raw query --- .../nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts index e575d7e54d..fe24eebae1 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts @@ -311,7 +311,7 @@ class BaseModelSqlv2 { ); } - qb.count(this.model.primaryKey?.column_name || '*', { + qb.count(sanitize(this.model.primaryKey?.column_name) || '*', { as: 'count' }).first(); const res = (await this.dbDriver.raw(unsanitize(qb.toQuery()))) as any;