diff --git a/lib/formatter.js b/lib/formatter.js index fc46ef11e1..d7831727db 100644 --- a/lib/formatter.js +++ b/lib/formatter.js @@ -171,8 +171,8 @@ class Formatter { // Puts the appropriate wrapper around a value depending on the database // engine, unless it's a knex.raw value, in which case it's left alone. - wrap(value) { - const raw = this.unwrapRaw(value); + wrap(value, isParameter) { + const raw = this.unwrapRaw(value, isParameter); if (raw) return raw; switch (typeof value) { case 'function': diff --git a/lib/query/compiler.js b/lib/query/compiler.js index 89170cb1ee..535d021709 100644 --- a/lib/query/compiler.js +++ b/lib/query/compiler.js @@ -865,7 +865,10 @@ Object.defineProperty(QueryCompiler.prototype, 'tableName', { if (tableName && schemaName) tableName = `${schemaName}.${tableName}`; - this._tableName = tableName ? this.formatter.wrap(tableName) : ''; + this._tableName = tableName + ? // Wrap subQuery with parenthesis, #3485 + this.formatter.wrap(tableName, tableName instanceof QueryBuilder) + : ''; } return this._tableName; }, diff --git a/test/unit/query/builder.js b/test/unit/query/builder.js index 2f91e1bcfc..742fadd9e5 100644 --- a/test/unit/query/builder.js +++ b/test/unit/query/builder.js @@ -8179,6 +8179,37 @@ describe('QueryBuilder', () => { ); }); + it('should always wrap subquery with parenthesis', () => { + const subquery = qb().select(raw('?', ['inner raw select']), 'bar'); + testsql( + qb() + .select(raw('?', ['outer raw select'])) + .from(subquery), + { + mysql: { + sql: 'select ? from (select ?, `bar`)', + bindings: ['outer raw select', 'inner raw select'], + }, + mssql: { + sql: 'select ? from (select ?, [bar])', + bindings: ['outer raw select', 'inner raw select'], + }, + oracledb: { + sql: 'select ? from (select ?, "bar")', + bindings: ['outer raw select', 'inner raw select'], + }, + pg: { + sql: 'select ? from (select ?, "bar")', + bindings: ['outer raw select', 'inner raw select'], + }, + 'pg-redshift': { + sql: 'select ? from (select ?, "bar")', + bindings: ['outer raw select', 'inner raw select'], + }, + } + ); + }); + it('correctly orders parameters when selecting from subqueries, #704', () => { const subquery = qb() .select(raw('? as f', ['inner raw select']))