Repository: knex/knex
Pull request #4648 (2021-08-25 13:54:57)

Clean up SQLite DDL handling and move all operations to the parser-based approach

kibertoad: Why was a bunch of tests dropped?
nickrum: The dropped tests were all testing the functionality of `_doReplace()` which I removed as it is no longer needed. The cases that were tested should all be covered by the parser/compiler unit tests.

Patch:
diff --git a/lib/dialects/sqlite3/schema/ddl.js b/lib/dialects/sqlite3/schema/ddl.js
index a160a005..5aaf5694 100644
--- a/lib/dialects/sqlite3/schema/ddl.js
+++ b/lib/dialects/sqlite3/schema/ddl.js
@@ -4,19 +4,12 @@
 // columns and changing datatypes.
 // -------
 
-const find = require('lodash/find');
-const fromPairs = require('lodash/fromPairs');
-const isEmpty = require('lodash/isEmpty');
-const negate = require('lodash/negate');
-const omit = require('lodash/omit');
 const identity = require('lodash/identity');
 const { nanonum } = require('../../../util/nanoid');
-const { COMMA_NO_PAREN_REGEX } = require('../../../constants');
 const {
   createNewTable,
-  copyAllData,
-  dropOriginal,
   copyData,
+  dropOriginal,
   renameTable,
   getTableSql,
 } = require('./internal/sqlite-ddl-operations');
@@ -25,6 +18,7 @@ const {
   compileCreateTable,
   compileCreateIndex,
 } = require('./internal/compiler');
+const { isEqualId, includesId } = require('./internal/utils');
 
 // So altering the schema in SQLite3 is a major pain.
 // We have our own object to deal with the renaming and altering the types
@@ -46,20 +40,6 @@ class SQLite3_DDL {
     return this.formatter(this.tableNameRaw);
   }
 
-  async getColumn(column) {
-    const currentCol = find(this.pragma, (col) => {
-      return (
-        this.client.wrapIdentifier(col.name).toLowerCase() ===
-        this.client.wrapIdentifier(column).toLowerCase()
-      );
-    });
-    if (!currentCol)
-      throw new Error(
-        `The column ${column} is not in the ${this.tableName()} table`
-      );
-    return currentCol;
-  }
-
   getTableSql() {
     const tableName = this.tableName();
 
@@ -83,16 +63,8 @@ class SQLite3_DDL {
     return this.trx.raw(dropOriginal(this.tableName()));
   }
 
-  async copyData(iterator) {
-    const commands = await copyData(
-      this.trx,
-      iterator,
-      this.tableName(),
-      this.alteredName
-    );
-    for (const command of commands) {
-      await this.trx.raw(command);
-    }
+  copyData(columns) {
+    return this.trx.raw(copyData(this.tableName(), this.alteredName, columns));
   }
 
   createNewTable(sql) {
@@ -101,147 +73,7 @@ class SQLite3_DDL {
     );
   }
 
-  _doReplace(sql, from, to) {
-    const oneLineSql = sql.replace(/\s+/g, ' ');
-    const matched = oneLineSql.match(/^CREATE TABLE\s+(\S+)\s*\((.*)\)/);
-
-    const tableName = matched[1];
-    const defs = matched[2];
-
-    if (!defs) {
-      throw new Error('No column definitions in this statement!');
-    }
-
-    let parens = 0,
-      args = [],
-      ptr = 0;
-    let i = 0;
-    const x = defs.length;
-    for (i = 0; i < x; i++) {
-      switch (defs[i]) {
-        case '(':
-          parens++;
-          break;
-        case ')':
-          parens--;
-          break;
-        case ',':
-          if (parens === 0) {
-            args.push(defs.slice(ptr, i));
-            ptr = i + 1;
-          }
-          break;
-        case ' ':
-          if (ptr === i) {
-            ptr = i + 1;
-          }
-          break;
-      }
-    }
-    args.push(defs.slice(ptr, i));
-
-    const fromIdentifier = from.replace(/[`"'[\]]/g, '');
-
-    args = args.map((item) => {
-      let split = item.trim().split(' ');
-
-      // SQLite supports all quoting mechanisms prevalent in all major dialects of SQL
-      // and preserves the original quoting in sqlite_master.
-      //
-      // Also, identifiers are never case sensitive, not even when quoted.
-      //
-      // Ref: https://www.sqlite.org/lang_keywords.html
-      const fromMatchCandidates = [
-        new RegExp(`\`${fromIdentifier}\``, 'i'),
-        new RegExp(`"${fromIdentifier}"`, 'i'),
-        new RegExp(`'${fromIdentifier}'`, 'i'),
-        new RegExp(`\\[${fromIdentifier}\\]`, 'i'),
-      ];
-      if (fromIdentifier.match(/^\S+$/)) {
-        fromMatchCandidates.push(new RegExp(`\\b${fromIdentifier}\\b`, 'i'));
-      }
-
-      const doesMatchFromIdentifier = (target) =>
-        fromMatchCandidates.some((c) => target.match(c));
-
-      const replaceFromIdentifier = (target) =>
-        fromMatchCandidates.reduce(
-          (result, candidate) => result.replace(candidate, to),
-          target
-        );
-
-      if (doesMatchFromIdentifier(split[0])) {
-        // column definition
-        if (to) {
-          split[0] = to;
-          return split.join(' ');
-        }
-        return ''; // for deletions
-      }
-
-      // skip constraint name
-      const idx = /constraint/i.test(split[0]) ? 2 : 0;
-
-      // primary key and unique constraints have one or more
-      // columns from this table listed between (); replace
-      // one if it matches
-      if (/primary|unique/i.test(split[idx])) {
-        const ret = item.replace(/\(.*\)/, replaceFromIdentifier);
-        // If any member columns are dropped then uniqueness/pk constraint
-        // can not be retained
-        if (ret !== item && isEmpty(to)) return '';
-        return ret;
-      }
-
-      // foreign keys have one or more columns from this table
-      // listed between (); replace one if it matches
-      // foreign keys also have a 'references' clause
-      // which may reference THIS table; if it does, replace
-      // column references in that too!
-      if (/foreign/.test(split[idx])) {
-        split = item.split(/ references /i);
-        // the quoted column names save us from having to do anything
-        // other than a straight replace here
-        const replacedKeySpec = replaceFromIdentifier(split[0]);
-
-        if (split[0] !== replacedKeySpec) {
-          // If we are removing one or more columns of a foreign
-          // key, then we should not retain the key at all
-          if (isEmpty(to)) return '';
-          else split[0] = replacedKeySpec;
-        }
-
-        if (split[1].slice(0, tableName.length) === tableName) {
-          // self-referential foreign key
-          const replacedKeyTargetSpec = split[1].replace(
-            /\(.*\)/,
-            replaceFromIdentifier
-          );
-          if (split[1] !== replacedKeyTargetSpec) {
-            // If we are removing one or more columns of a foreign
-            // key, then we should not retain the key at all
-            if (isEmpty(to)) return '';
-            else split[1] = replacedKeyTargetSpec;
-          }
-        }
-        return split.join(' references ');
-      }
-
-      return item;
-    });
-
-    args = args.filter(negate(isEmpty));
-
-    if (args.length === 0) {
-      throw new Error('Unable to drop last column from table');
-    }
-
-    return oneLineSql
-      .replace(/\(.*\)/, () => `(${args.join(', ')})`)
-      .replace(/,\s*([,)])/, '$1');
-  }
-
-  async alterColumn(columns) {
+  alterColumn(columns) {
     return this.client.transaction(
       async (trx) => {
         this.trx = trx;
@@ -251,7 +83,9 @@ class SQLite3_DDL {
         const parsedTable = parseCreateTable(createTable);
 
         parsedTable.columns = parsedTable.columns.map((column) => {
-          const newColumnInfo = columns.find((c) => c.name === column.name);
+          const newColumnInfo = columns.find((c) =>
+            isEqualId(c.name, column.name)
+          );
 
           if (newColumnInfo) {
             column.type = newColumnInfo.type;
@@ -279,62 +113,84 @@ class SQLite3_DDL {
 
         const newTable = compileCreateTable(parsedTable, this.wrap);
 
-        return this.alter(newTable, createIndices, (row) => {
-          return row;
-        });
+        return this.alter(newTable, createIndices);
       },
       { connection: this.connection }
     );
   }
 
-  async dropColumn(columns) {
+  dropColumn(columns) {
     return this.client.transaction(
-      (trx) => {
+      async (trx) => {
         this.trx = trx;
-        return Promise.all(columns.map((column) => this.getColumn(column)))
-          .then(() => this.getTableSql())
-          .then(({ createTable, createIndices }) => {
-            let newSql = createTable.slice();
-            columns.forEach((column) => {
-              const a = this.client.wrapIdentifier(column);
-              newSql = this._doReplace(newSql, a, '');
-            });
-            if (createTable === newSql) {
-              throw new Error('Unable to find the column to change');
-            }
-            const mappedColumns = Object.keys(
-              this.client.postProcessResponse(
-                fromPairs(columns.map((column) => [column, column]))
-              )
-            );
-
-            const newIndices = [];
-            for (const createIndex of createIndices) {
-              const parsedIndex = parseCreateIndex(createIndex);
-
-              parsedIndex.columns = parsedIndex.columns.filter(
-                (newColumn) =>
-                  newColumn.expression ||
-                  !columns.some(
-                    (column) => newColumn.name === this.formatter(column)
-                  )
-              );
 
-              if (parsedIndex.columns.length > 0) {
-                newIndices.push(compileCreateIndex(parsedIndex, this.wrap));
-              }
+        const { createTable, createIndices } = await this.getTableSql();
+
+        const parsedTable = parseCreateTable(createTable);
+
+        parsedTable.columns = parsedTable.columns.filter(
+          (parsedColumn) =>
+            parsedColumn.expression || !includesId(columns, parsedColumn.name)
+        );
+
+        if (parsedTable.columns.length === 0) {
+          throw new Error('Unable to drop last column from table');
+        }
+
+        parsedTable.constraints = parsedTable.constraints.filter(
+          (constraint) => {
+            if (
+              constraint.type === 'PRIMARY KEY' ||
+              constraint.type === 'UNIQUE'
+            ) {
+              return constraint.columns.every(
+                (constraintColumn) =>
+                  constraintColumn.expression ||
+                  !includesId(columns, constraintColumn.name)
+              );
+            } else if (constraint.type === 'FOREIGN KEY') {
+              return (
+                constraint.columns.every(
+                  (constraintColumnName) =>
+                    !includesId(columns, constraintColumnName)
+                ) &&
+                (constraint.references.table !== parsedTable.table ||
+                  constraint.references.columns.every(
+                    (referenceColumnName) =>
+                      !includesId(columns, referenceColumnName)
+                  ))
+              );
+            } else {
+              return true;
             }
+          }
+        );
+
+        const newColumns = parsedTable.columns.map((column) => column.name);
 
-            return this.alter(newSql, newIndices, (row) =>
-              omit(row, ...mappedColumns)
-            );
-          });
+        const newTable = compileCreateTable(parsedTable, this.wrap);
+
+        const newIndices = [];
+        for (const createIndex of createIndices) {
+          const parsedIndex = parseCreateIndex(createIndex);
+
+          parsedIndex.columns = parsedIndex.columns.filter(
+            (parsedColumn) =>
+              parsedColumn.expression || !includesId(columns, parsedColumn.name)
+          );
+
+          if (parsedIndex.columns.length > 0) {
+            newIndices.push(compileCreateIndex(parsedIndex, this.wrap));
+          }
+        }
+
+        return this.alter(newTable, newIndices, newColumns);
       },
       { connection: this.connection }
     );
   }
 
-  async dropForeign(columns, foreignKeyName) {
+  dropForeign(columns, foreignKeyName) {
     return this.client.transaction(
       async (trx) => {
         this.trx = trx;
@@ -346,7 +202,7 @@ class SQLite3_DDL {
         if (!foreignKeyName) {
           parsedTable.columns = parsedTable.columns.map((column) => ({
             ...column,
-            references: columns.includes(column.name)
+            references: includesId(columns, column.name)
               ? null
               : column.references,
           }));
@@ -354,181 +210,143 @@ class SQLite3_DDL {
 
         parsedTable.constraints = parsedTable.constraints.filter(
           (constraint) => {
-            if (foreignKeyName) {
-              return constraint.name !== foreignKeyName;
-            }
+            if (constraint.type === 'FOREIGN KEY') {
+              if (foreignKeyName) {
+                return (
+                  !constraint.name ||
+                  !isEqualId(constraint.name, foreignKeyName)
+                );
+              }
 
-            return (
-              constraint.columns.some((column) => columns.includes(column)) ===
-              false
-            );
+              return constraint.columns.every(
+                (constraintColumnName) =>
+                  !includesId(columns, constraintColumnName)
+              );
+            } else {
+              return true;
+            }
           }
         );
 
         const newTable = compileCreateTable(parsedTable, this.wrap);
 
-        return this.alter(newTable, createIndices, (row) => {
-          return row;
-        });
+        return this.alter(newTable, createIndices);
       },
       { connection: this.connection }
     );
   }
 
-  async dropPrimary(constraintName) {
+  dropPrimary(constraintName) {
     return this.client.transaction(
       async (trx) => {
         this.trx = trx;
 
         const { createTable, createIndices } = await this.getTableSql();
 
-        const oneLineSql = createTable.replace(/\s+/g, ' ');
-        const matched = oneLineSql.match(/^CREATE TABLE\s+(\S+)\s*\((.*)\)/);
-
-        const defs = matched[2];
+        const parsedTable = parseCreateTable(createTable);
 
-        if (!defs) {
-          throw new Error('No column definitions in this statement!');
-        }
+        parsedTable.columns = parsedTable.columns.map((column) => ({
+          ...column,
+          primary: null,
+        }));
 
-        const updatedDefs = defs
-          .split(COMMA_NO_PAREN_REGEX)
-          .map((line) => line.trim())
-          .filter((defLine) => {
-            if (
-              defLine.startsWith('constraint') === false &&
-              defLine.includes('primary key') === false
-            )
-              return true;
-
-            if (constraintName) {
-              if (defLine.includes(constraintName)) return false;
-              return true;
+        parsedTable.constraints = parsedTable.constraints.filter(
+          (constraint) => {
+            if (constraint.type === 'PRIMARY KEY') {
+              if (constraintName) {
+                return (
+                  !constraint.name ||
+                  !isEqualId(constraint.name, constraintName)
+                );
+              } else {
+                return false;
+              }
             } else {
               return true;
             }
-          })
-          .join(', ');
+          }
+        );
 
-        const newSql = oneLineSql.replace(defs, updatedDefs);
+        const newTable = compileCreateTable(parsedTable, this.wrap);
 
-        return this.alter(newSql, createIndices, (row) => {
-          return row;
-        });
+        return this.alter(newTable, createIndices);
       },
       { connection: this.connection }
     );
   }
 
-  async primary(columns, constraintName) {
+  primary(columns, constraintName) {
     return this.client.transaction(
       async (trx) => {
         this.trx = trx;
 
         const { createTable, createIndices } = await this.getTableSql();
 
-        const oneLineSql = createTable.replace(/\s+/g, ' ');
-        const matched = oneLineSql.match(/^CREATE TABLE\s+(\S+)\s*\((.*)\)/);
-
-        const columnDefinitions = matched[2];
+        const parsedTable = parseCreateTable(createTable);
 
-        if (!columnDefinitions) {
-          throw new Error('No column definitions in this statement!');
-        }
+        parsedTable.columns = parsedTable.columns.map((column) => ({
+          ...column,
+          primary: null,
+        }));
 
-        const primaryKeyDef = `primary key(${columns.join(',')})`;
-        const constraintDef = constraintName
-          ? `constraint ${constraintName} ${primaryKeyDef}`
-          : primaryKeyDef;
-
-        const newColumnDefinitions = [
-          ...columnDefinitions
-            .split(COMMA_NO_PAREN_REGEX)
-            .map((line) => line.trim())
-            .filter((line) => line.startsWith('primary') === false)
-            .map((line) => line.replace(/primary key/i, '')),
-          constraintDef,
-        ].join(', ');
-
-        const newSQL = oneLineSql.replace(
-          columnDefinitions,
-          newColumnDefinitions
+        parsedTable.constraints = parsedTable.constraints.filter(
+          (constraint) => constraint.type !== 'PRIMARY KEY'
         );
 
-        return this.alter(newSQL, createIndices, (row) => {
-          return row;
+        parsedTable.constraints.push({
+          type: 'PRIMARY KEY',
+          name: constraintName || null,
+          columns: columns.map((column) => ({
+            name: column,
+            expression: false,
+            collation: null,
+            order: null,
+          })),
+          conflict: null,
         });
+
+        const newTable = compileCreateTable(parsedTable, this.wrap);
+
+        return this.alter(newTable, createIndices);
       },
       { connection: this.connection }
     );
   }
 
-  async foreign(foreignInfo) {
+  foreign(foreignInfo) {
     return this.client.transaction(
       async (trx) => {
         this.trx = trx;
 
         const { createTable, createIndices } = await this.getTableSql();
 
-        const oneLineSql = createTable.replace(/\s+/g, ' ');
-        const matched = oneLineSql.match(/^CREATE TABLE\s+(\S+)\s*\((.*)\)/);
-
-        const columnDefinitions = matched[2];
-
-        if (!columnDefinitions) {
-          throw new Error('No column definitions in this statement!');
-        }
-
-        const newColumnDefinitions = columnDefinitions
-          .split(COMMA_NO_PAREN_REGEX)
-          .map((line) => line.trim());
-
-        let newForeignSQL = '';
-
-        if (foreignInfo.keyName) {
-          newForeignSQL += `CONSTRAINT ${foreignInfo.keyName}`;
-        }
-
-        newForeignSQL += ` FOREIGN KEY (${foreignInfo.column.join(', ')}) `;
-        newForeignSQL += ` REFERENCES ${foreignInfo.inTable} (${foreignInfo.references})`;
-
-        if (foreignInfo.onUpdate) {
-          newForeignSQL += ` ON UPDATE ${foreignInfo.onUpdate}`;
-        }
-
-        if (foreignInfo.onDelete) {
-          newForeignSQL += ` ON DELETE ${foreignInfo.onDelete}`;
-        }
+        const parsedTable = parseCreateTable(createTable);
 
-        newColumnDefinitions.push(newForeignSQL);
+        parsedTable.constraints.push({
+          type: 'FOREIGN KEY',
+          name: foreignInfo.keyName || null,
+          columns: foreignInfo.column,
+          references: {
+            table: foreignInfo.inTable,
+            columns: foreignInfo.references,
+            delete: foreignInfo.onDelete || null,
+            update: foreignInfo.onUpdate || null,
+            match: null,
+            deferrable: null,
+          },
+        });
 
-        const newSQL = oneLineSql.replace(
-          columnDefinitions,
-          newColumnDefinitions.join(', ')
-        );
+        const newTable = compileCreateTable(parsedTable, this.wrap);
 
-        return await this.generateAlterCommands(
-          newSQL,
-          createIndices,
-          (row) => {
-            return row;
-          }
-        );
+        return this.generateAlterCommands(newTable, createIndices);
       },
       { connection: this.connection }
     );
   }
 
-  /**
-   * @fixme
-   *
-   * There's a bunch of overlap between renameColumn/dropColumn/dropForeign/primary/foreign.
-   * It'll be helpful to refactor this file heavily to combine/optimize some of these calls
-   */
-
-  async alter(newSql, createIndices, mapRow) {
+  async alter(newSql, createIndices, columns) {
     await this.createNewTable(newSql);
-    await this.copyData(mapRow);
+    await this.copyData(columns);
     await this.dropOriginal();
     await this.renameTable();
 
@@ -537,11 +355,11 @@ class SQLite3_DDL {
     }
   }
 
-  async generateAlterCommands(newSql, createIndices, mapRow) {
+  generateAlterCommands(newSql, createIndices, columns) {
     const result = [];
 
     result.push(createNewTable(newSql, this.tableName(), this.alteredName));
-    result.push(copyAllData(this.tableName(), this.alteredName));
+    result.push(copyData(this.tableName(), this.alteredName, columns));
     result.push(dropOriginal(this.tableName()));
     result.push(renameTable(this.alteredName, this.tableName()));
 
diff --git a/lib/dialects/sqlite3/schema/internal/parser.js b/lib/dialects/sqlite3/schema/internal/parser.js
index 82f72b5f..535faf7b 100644
--- a/lib/dialects/sqlite3/schema/internal/parser.js
+++ b/lib/dialects/sqlite3/schema/internal/parser.js
@@ -2,7 +2,8 @@ const { tokenize } = require('./tokenizer');
 const { s, a, m, o, l, n, t, e, f } = require('./parser-combinator');
 
 const TOKENS = {
-  keyword: /(?:ABORT|ACTION|ADD|AFTER|ALL|ALTER|ALWAYS|ANALYZE|AND|AS|ASC|ATTACH|AUTOINCREMENT|BEFORE|BEGIN|BETWEEN|BY|CASCADE|CASE|CAST|CHECK|COLLATE|COLUMN|COMMIT|CONFLICT|CONSTRAINT|CREATE|CROSS|CURRENT|CURRENT_DATE|CURRENT_TIME|CURRENT_TIMESTAMP|DATABASE|DEFAULT|DEFERRED|DEFERRABLE|DELETE|DESC|DETACH|DISTINCT|DO|DROP|END|EACH|ELSE|ESCAPE|EXCEPT|EXCLUSIVE|EXCLUDE|EXISTS|EXPLAIN|FAIL|FILTER|FIRST|FOLLOWING|FOR|FOREIGN|FROM|FULL|GENERATED|GLOB|GROUP|GROUPS|HAVING|IF|IGNORE|IMMEDIATE|IN|INDEX|INDEXED|INITIALLY|INNER|INSERT|INSTEAD|INTERSECT|INTO|IS|ISNULL|JOIN|KEY|LAST|LEFT|LIKE|LIMIT|MATCH|MATERIALIZED|NATURAL|NO|NOT|NOTHING|NOTNULL|NULL|NULLS|OF|OFFSET|ON|OR|ORDER|OTHERS|OUTER|OVER|PARTITION|PLAN|PRAGMA|PRECEDING|PRIMARY|QUERY|RAISE|RANGE|RECURSIVE|REFERENCES|REGEXP|REINDEX|RELEASE|RENAME|REPLACE|RESTRICT|RETURNING|RIGHT|ROLLBACK|ROW|ROWS|SAVEPOINT|SELECT|SET|TABLE|TEMP|TEMPORARY|THEN|TIES|TO|TRANSACTION|TRIGGER|UNBOUNDED|UNION|UNIQUE|UPDATE|USING|VACUUM|VALUES|VIEW|VIRTUAL|WHEN|WHERE|WINDOW|WITH|WITHOUT)(?=\s+|-|\(|\)|;|\+|\*|\/|%|==|=|<=|<>|<<|<|>=|>>|>|!=|,|&|~|\|\||\||\.)/,
+  keyword:
+    /(?:ABORT|ACTION|ADD|AFTER|ALL|ALTER|ALWAYS|ANALYZE|AND|AS|ASC|ATTACH|AUTOINCREMENT|BEFORE|BEGIN|BETWEEN|BY|CASCADE|CASE|CAST|CHECK|COLLATE|COLUMN|COMMIT|CONFLICT|CONSTRAINT|CREATE|CROSS|CURRENT|CURRENT_DATE|CURRENT_TIME|CURRENT_TIMESTAMP|DATABASE|DEFAULT|DEFERRED|DEFERRABLE|DELETE|DESC|DETACH|DISTINCT|DO|DROP|END|EACH|ELSE|ESCAPE|EXCEPT|EXCLUSIVE|EXCLUDE|EXISTS|EXPLAIN|FAIL|FILTER|FIRST|FOLLOWING|FOR|FOREIGN|FROM|FULL|GENERATED|GLOB|GROUP|GROUPS|HAVING|IF|IGNORE|IMMEDIATE|IN|INDEX|INDEXED|INITIALLY|INNER|INSERT|INSTEAD|INTERSECT|INTO|IS|ISNULL|JOIN|KEY|LAST|LEFT|LIKE|LIMIT|MATCH|MATERIALIZED|NATURAL|NO|NOT|NOTHING|NOTNULL|NULL|NULLS|OF|OFFSET|ON|OR|ORDER|OTHERS|OUTER|OVER|PARTITION|PLAN|PRAGMA|PRECEDING|PRIMARY|QUERY|RAISE|RANGE|RECURSIVE|REFERENCES|REGEXP|REINDEX|RELEASE|RENAME|REPLACE|RESTRICT|RETURNING|RIGHT|ROLLBACK|ROW|ROWS|SAVEPOINT|SELECT|SET|TABLE|TEMP|TEMPORARY|THEN|TIES|TO|TRANSACTION|TRIGGER|UNBOUNDED|UNION|UNIQUE|UPDATE|USING|VACUUM|VALUES|VIEW|VIRTUAL|WHEN|WHERE|WINDOW|WITH|WITHOUT)(?=\s+|-|\(|\)|;|\+|\*|\/|%|==|=|<=|<>|<<|<|>=|>>|>|!=|,|&|~|\|\||\||\.)/,
   id: /"[^"]*(?:""[^"]*)*"|`[^`]*(?:``[^`]*)*`|\[[^[\]]*\]|[a-z_][a-z0-9_$]*/,
   string: /'[^']*(?:''[^']*)*'/,
   blob: /x'(?:[0-9a-f][0-9a-f])+'/,
@@ -591,10 +592,8 @@ function expression(ctx) {
 }
 
 function identifier(ctx) {
-  return t({ type: 'id' }, (v) =>
-    /^["`[][^]*["`\]]$/.test(v.text)
-      ? v.text.substring(1, v.text.length - 1)
-      : v.text
+  return a([t({ type: 'id' }), t({ type: 'string' })], (v) =>
+    /^["`['][^]*["`\]']$/.test(v) ? v.substring(1, v.length - 1) : v
   )(ctx);
 }
 
@@ -615,6 +614,7 @@ function literalValue(ctx) {
   return a([
     t({ type: 'numeric' }),
     t({ type: 'string' }),
+    t({ type: 'id' }),
     t({ type: 'blob' }),
     t({ text: 'NULL' }),
     t({ text: 'TRUE' }),
diff --git a/lib/dialects/sqlite3/schema/internal/sqlite-ddl-operations.js b/lib/dialects/sqlite3/schema/internal/sqlite-ddl-operations.js
index ad1d1596..16a7057d 100644
--- a/lib/dialects/sqlite3/schema/internal/sqlite-ddl-operations.js
+++ b/lib/dialects/sqlite3/schema/internal/sqlite-ddl-operations.js
@@ -1,30 +1,13 @@
-const identity = require('lodash/identity');
-const chunk = require('lodash/chunk');
-
-function insertChunked(trx, chunkSize, target, iterator, existingData) {
-  const result = [];
-  iterator = iterator || identity;
-  const chunked = chunk(existingData, chunkSize);
-  for (const batch of chunked) {
-    result.push(
-      trx.queryBuilder().table(target).insert(batch.map(iterator)).toQuery()
-    );
-  }
-  return result;
-}
-
 function createNewTable(sql, tablename, alteredName) {
   return sql.replace(tablename, alteredName);
 }
 
-// ToDo To be removed
-async function copyData(trx, iterator, tableName, alteredName) {
-  const existingData = await trx.raw(`SELECT * FROM "${tableName}"`);
-  return insertChunked(trx, 20, alteredName, iterator, existingData);
-}
-
-function copyAllData(sourceTable, targetTable) {
-  return `INSERT INTO ${targetTable} SELECT * FROM ${sourceTable};`;
+function copyData(sourceTable, targetTable, columns) {
+  return `INSERT INTO ${targetTable} SELECT ${
+    columns === undefined
+      ? '*'
+      : columns.map((column) => `"${column}"`).join(', ')
+  } FROM ${sourceTable};`;
 }
 
 function dropOriginal(tableName) {
@@ -40,10 +23,9 @@ function getTableSql(tableName) {
 }
 
 module.exports = {
-  copyAllData,
   createNewTable,
-  dropOriginal,
   copyData,
+  dropOriginal,
   renameTable,
   getTableSql,
 };
diff --git a/lib/dialects/sqlite3/schema/internal/utils.js b/lib/dialects/sqlite3/schema/internal/utils.js
new file mode 100644
index 00000000..ff6774b8
--- /dev/null
+++ b/lib/dialects/sqlite3/schema/internal/utils.js
@@ -0,0 +1,12 @@
+function isEqualId(first, second) {
+  return first.toLowerCase() === second.toLowerCase();
+}
+
+function includesId(list, id) {
+  return list.some((item) => isEqualId(item, id));
+}
+
+module.exports = {
+  isEqualId,
+  includesId,
+};
diff --git a/lib/dialects/sqlite3/schema/sqlite-tablecompiler.js b/lib/dialects/sqlite3/schema/sqlite-tablecompiler.js
index 24a087eb..f339e896 100644
--- a/lib/dialects/sqlite3/schema/sqlite-tablecompiler.js
+++ b/lib/dialects/sqlite3/schema/sqlite-tablecompiler.js
@@ -81,6 +81,12 @@ class TableCompiler_SQLite3 extends TableCompiler {
   dropForeign(columns, indexName) {
     const compiler = this;
 
+    columns = Array.isArray(columns) ? columns : [columns];
+    columns = columns.map((column) =>
+      this.client.customWrapIdentifier(column, identity)
+    );
+    indexName = this.client.customWrapIdentifier(indexName, identity);
+
     this.pushQuery({
       sql: `PRAGMA table_info(${this.tableName()})`,
       output(pragma) {
@@ -95,6 +101,8 @@ class TableCompiler_SQLite3 extends TableCompiler {
   dropPrimary(constraintName) {
     const compiler = this;
 
+    constraintName = this.client.customWrapIdentifier(constraintName, identity);
+
     this.pushQuery({
       sql: `PRAGMA table_info(${this.tableName()})`,
       output(pragma) {
@@ -146,8 +154,11 @@ class TableCompiler_SQLite3 extends TableCompiler {
   primary(columns, constraintName) {
     const compiler = this;
 
-    columns = this.formatter.columnize(columns);
     columns = Array.isArray(columns) ? columns : [columns];
+    columns = columns.map((column) =>
+      this.client.customWrapIdentifier(column, identity)
+    );
+    constraintName = this.client.customWrapIdentifier(constraintName, identity);
 
     if (this.method !== 'create' && this.method !== 'createIfNot') {
       this.pushQuery({
@@ -170,7 +181,7 @@ class TableCompiler_SQLite3 extends TableCompiler {
    * @param {object} foreignInfo - Information about the current column foreign setup
    * @param {string | string[]} [foreignInfo.column] - Column in the current constraint
    * @param {string | undefined} foreignInfo.keyName - Name of the foreign key constraint
-   * @param {string} foreignInfo.references - What column it references in the other table
+   * @param {string | string[]} foreignInfo.references - What column it references in the other table
    * @param {string} foreignInfo.inTable - What table is referenced in this constraint
    * @param {string} [foreignInfo.onUpdate] - What to do on updates
    * @param {string} [foreignInfo.onDelete] - What to do on deletions
@@ -179,12 +190,22 @@ class TableCompiler_SQLite3 extends TableCompiler {
     const compiler = this;
 
     if (this.method !== 'create' && this.method !== 'createIfNot') {
-      foreignInfo.column = this.formatter.columnize(foreignInfo.column);
       foreignInfo.column = Array.isArray(foreignInfo.column)
         ? foreignInfo.column
         : [foreignInfo.column];
-      foreignInfo.inTable = this.formatter.columnize(foreignInfo.inTable);
-      foreignInfo.references = this.formatter.columnize(foreignInfo.references);
+      foreignInfo.column = foreignInfo.column.map((column) =>
+        this.client.customWrapIdentifier(column, identity)
+      );
+      foreignInfo.inTable = this.client.customWrapIdentifier(
+        foreignInfo.inTable,
+        identity
+      );
+      foreignInfo.references = Array.isArray(foreignInfo.references)
+        ? foreignInfo.references
+        : [foreignInfo.references];
+      foreignInfo.references = foreignInfo.references.map((column) =>
+        this.client.customWrapIdentifier(column, identity)
+      );
 
       this.pushQuery({
         sql: `PRAGMA table_info(${this.tableName()})`,
@@ -247,12 +268,17 @@ class TableCompiler_SQLite3 extends TableCompiler {
   dropColumn() {
     const compiler = this;
     const columns = values(arguments);
+
+    const columnsWrapped = columns.map((column) =>
+      this.client.customWrapIdentifier(column, identity)
+    );
+
     this.pushQuery({
       sql: `PRAGMA table_info(${this.tableName()})`,
       output(pragma) {
         return compiler.client
           .ddl(compiler, pragma, this.connection)
-          .dropColumn(columns);
+          .dropColumn(columnsWrapped);
       },
     });
   }


Test patch:
diff --git a/test/db-less-test-suite.js b/test/db-less-test-suite.js
index 7df1de1e..ed5a5935 100644
--- a/test/db-less-test-suite.js
+++ b/test/db-less-test-suite.js
@@ -44,13 +44,6 @@ if (config.postgres) {
   require('./unit/dialects/postgres');
 }
 
-if (config.sqlite3) {
-  describe('Sqlite driver tests', function () {
-    this.timeout(process.env.KNEX_TEST_TIMEOUT || 5000);
-    require('./unit/dialects/sqlite3');
-  });
-}
-
 describe('CLI tests', function () {
   this.timeout(process.env.KNEX_TEST_TIMEOUT || 5000);
   require('./cli/help.spec');
diff --git a/test/integration/schema/index.js b/test/integration/schema/index.js
index deb45252..1fea4d8a 100644
--- a/test/integration/schema/index.js
+++ b/test/integration/schema/index.js
@@ -1331,6 +1331,9 @@ module.exports = (knex) => {
 
         context('when table is created using raw create table', () => {
           beforeEach(async () => {
+            await knex.schema.raw(`create table bar(
+              \`i3\` integer primary key
+            )`);
             await knex.schema.raw(`create table TEST(
               "i0" integer,
               'i1' integer,
@@ -1364,33 +1367,33 @@ module.exports = (knex) => {
             expect(await hasCol('i0')).to.equal(false);
             // Constraint i0 should be unaffected:
             expect(await getCreateTableExpr()).to.equal(
-              'CREATE TABLE "TEST"(\'i1\' integer, [i2] integer, `i3` integer, i4 ' +
-                'integer, I5 integer, unique(i4, i5), constraint i0 primary ' +
-                'key([i3], "i4"), unique([i2]), foreign key (i1) references bar ' +
-                '("i3") )'
+              'CREATE TABLE "TEST" (`i1` integer, `i2` integer, `i3` integer, `i4` ' +
+                'integer, `I5` integer, UNIQUE (`i4`, `i5`), CONSTRAINT `i0` PRIMARY ' +
+                'KEY (`i3`, `i4`), UNIQUE (`i2`), FOREIGN KEY (`i1`) REFERENCES `bar` ' +
+                '(`i3`))'
             );
             await dropCol('i1');
             expect(await hasCol('i1')).to.equal(false);
             // Foreign key on i1 should also be dropped:
             expect(await getCreateTableExpr()).to.equal(
-              'CREATE TABLE "TEST"([i2] integer, `i3` integer, i4 integer, I5 integer, ' +
-                'unique(i4, i5), constraint i0 primary key([i3], "i4"), unique([i2]))'
+              'CREATE TABLE "TEST" (`i2` integer, `i3` integer, `i4` integer, `I5` integer, ' +
+                'UNIQUE (`i4`, `i5`), CONSTRAINT `i0` PRIMARY KEY (`i3`, `i4`), UNIQUE (`i2`))'
             );
             await dropCol('i2');
             expect(await hasCol('i2')).to.equal(false);
             expect(await getCreateTableExpr()).to.equal(
-              'CREATE TABLE "TEST"(`i3` integer, i4 integer, I5 integer, ' +
-                'unique(i4, i5), constraint i0 primary key([i3], "i4"))'
+              'CREATE TABLE "TEST" (`i3` integer, `i4` integer, `I5` integer, ' +
+                'UNIQUE (`i4`, `i5`), CONSTRAINT `i0` PRIMARY KEY (`i3`, `i4`))'
             );
             await dropCol('i3');
             expect(await hasCol('i3')).to.equal(false);
             expect(await getCreateTableExpr()).to.equal(
-              'CREATE TABLE "TEST"(i4 integer, I5 integer, unique(i4, i5))'
+              'CREATE TABLE "TEST" (`i4` integer, `I5` integer, UNIQUE (`i4`, `i5`))'
             );
             await dropCol('i4');
             expect(await hasCol('i4')).to.equal(false);
             expect(await getCreateTableExpr()).to.equal(
-              'CREATE TABLE "TEST"(I5 integer)'
+              'CREATE TABLE "TEST" (`I5` integer)'
             );
             let lastColDeletionError;
             await knex.schema
diff --git a/test/integration2/schema/foreign-keys.spec.js b/test/integration2/schema/foreign-keys.spec.js
index 3006edf4..b8f7538b 100644
--- a/test/integration2/schema/foreign-keys.spec.js
+++ b/test/integration2/schema/foreign-keys.spec.js
@@ -66,7 +66,7 @@ describe('Schema', () => {
 
             if (isSQLite(knex)) {
               expect(queries.sql).to.eql([
-                'CREATE TABLE `_knex_temp_alter111` (`id` integer not null primary key autoincrement, `fkey_two` integer not null, `fkey_three` integer not null, CONSTRAINT fk_fkey_threeee FOREIGN KEY (`fkey_three`)  REFERENCES `foreign_keys_table_three` (`id`))',
+                'CREATE TABLE `_knex_temp_alter111` (`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, `fkey_two` integer NOT NULL, `fkey_three` integer NOT NULL, CONSTRAINT `fk_fkey_threeee` FOREIGN KEY (`fkey_three`) REFERENCES `foreign_keys_table_three` (`id`))',
                 'INSERT INTO _knex_temp_alter111 SELECT * FROM foreign_keys_table_one;',
                 'DROP TABLE "foreign_keys_table_one"',
                 'ALTER TABLE "_knex_temp_alter111" RENAME TO "foreign_keys_table_one"',
@@ -77,8 +77,7 @@ describe('Schema', () => {
               expect(queries.sql).to.eql([
                 {
                   bindings: [],
-                  sql:
-                    'alter table "foreign_keys_table_one" add constraint "fk_fkey_threeee" foreign key ("fkey_three") references "foreign_keys_table_three" ("id")',
+                  sql: 'alter table "foreign_keys_table_one" add constraint "fk_fkey_threeee" foreign key ("fkey_three") references "foreign_keys_table_three" ("id")',
                 },
               ]);
             }
@@ -103,7 +102,7 @@ describe('Schema', () => {
             const queries = await builder.generateDdlCommands();
 
             expect(queries.sql).to.eql([
-              'CREATE TABLE `_knex_temp_alter111` (`id` integer not null primary key autoincrement, `fkey_two` integer not null, `fkey_three` integer not null, CONSTRAINT fk_fkey_threeee FOREIGN KEY (`fkey_three`)  REFERENCES `foreign_keys_table_three` (`id`) ON DELETE CASCADE)',
+              'CREATE TABLE `_knex_temp_alter111` (`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, `fkey_two` integer NOT NULL, `fkey_three` integer NOT NULL, CONSTRAINT `fk_fkey_threeee` FOREIGN KEY (`fkey_three`) REFERENCES `foreign_keys_table_three` (`id`) ON DELETE CASCADE)',
               'INSERT INTO _knex_temp_alter111 SELECT * FROM foreign_keys_table_one;',
               'DROP TABLE "foreign_keys_table_one"',
               'ALTER TABLE "_knex_temp_alter111" RENAME TO "foreign_keys_table_one"',
@@ -129,7 +128,7 @@ describe('Schema', () => {
             const queries = await builder.generateDdlCommands();
 
             expect(queries.sql).to.eql([
-              'CREATE TABLE `_knex_temp_alter111` (`id` integer not null primary key autoincrement, `fkey_two` integer not null, `fkey_three` integer not null, CONSTRAINT fk_fkey_threeee FOREIGN KEY (`fkey_three`)  REFERENCES `foreign_keys_table_three` (`id`) ON UPDATE CASCADE)',
+              'CREATE TABLE `_knex_temp_alter111` (`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, `fkey_two` integer NOT NULL, `fkey_three` integer NOT NULL, CONSTRAINT `fk_fkey_threeee` FOREIGN KEY (`fkey_three`) REFERENCES `foreign_keys_table_three` (`id`) ON UPDATE CASCADE)',
               'INSERT INTO _knex_temp_alter111 SELECT * FROM foreign_keys_table_one;',
               'DROP TABLE "foreign_keys_table_one"',
               'ALTER TABLE "_knex_temp_alter111" RENAME TO "foreign_keys_table_one"',
diff --git a/test/integration2/schema/index.spec.js b/test/integration2/schema/index.spec.js
index e1aba4d5..81d8ae0a 100644
--- a/test/integration2/schema/index.spec.js
+++ b/test/integration2/schema/index.spec.js
@@ -171,15 +171,13 @@ describe('Schema', () => {
                   type: 'index',
                   name: 'index_table_one_column_one_index',
                   tbl_name: 'index_table_one',
-                  sql:
-                    'CREATE INDEX `index_table_one_column_one_index` on `index_table_one` (`column_one`)',
+                  sql: 'CREATE INDEX `index_table_one_column_one_index` on `index_table_one` (`column_one`)',
                 },
                 {
                   type: 'index',
                   name: 'index_table_one_column_two_column_three_index',
                   tbl_name: 'index_table_one',
-                  sql:
-                    'CREATE INDEX `index_table_one_column_two_column_three_index` on `index_table_one` (`column_three`)',
+                  sql: 'CREATE INDEX `index_table_one_column_two_column_three_index` on `index_table_one` (`column_three`)',
                 },
               ];
               const indicesTwoBeforeWithoutIndex = [
@@ -187,15 +185,13 @@ describe('Schema', () => {
                   type: 'index',
                   name: 'index_table_two_column_one_unique',
                   tbl_name: 'index_table_two',
-                  sql:
-                    'CREATE UNIQUE INDEX `index_table_two_column_one_unique` on `index_table_two` (`column_one`)',
+                  sql: 'CREATE UNIQUE INDEX `index_table_two_column_one_unique` on `index_table_two` (`column_one`)',
                 },
                 {
                   type: 'index',
                   name: 'index_table_two_column_two_column_three_unique',
                   tbl_name: 'index_table_two',
-                  sql:
-                    'CREATE UNIQUE INDEX `index_table_two_column_two_column_three_unique` on `index_table_two` (`column_three`)',
+                  sql: 'CREATE UNIQUE INDEX `index_table_two_column_two_column_three_unique` on `index_table_two` (`column_three`)',
                 },
               ];
 
@@ -254,7 +250,7 @@ describe('Schema', () => {
               );
 
               await knex.schema.alterTable('index_table_one', (table) => {
-                table.dropPrimary('id');
+                table.dropPrimary();
               });
 
               const indicesAfter = await knex.raw(QUERY_TABLE_ONE_INDICES);
diff --git a/test/unit/dialects/sqlite3.js b/test/unit/dialects/sqlite3.js
deleted file mode 100644
index d732a87a..00000000
--- a/test/unit/dialects/sqlite3.js
+++ /dev/null
@@ -1,102 +0,0 @@
-'use strict';
-
-const { expect } = require('chai');
-
-const sinon = require('sinon');
-const DDL = require('../../../lib/dialects/sqlite3/schema/ddl');
-
-it('[backwards compatible] can rename column with double quotes', function () {
-  const client = sinon.stub();
-  const tableCompiler = sinon.stub();
-  const pragma = sinon.stub();
-  const connection = sinon.stub();
-  const ddl = new DDL(client, tableCompiler, pragma, connection);
-
-  const sql =
-    'CREATE TABLE "accounts" ("id" varchar(24) not null primary key, "about" varchar(24))';
-
-  const newSql = ddl._doReplace(sql, '`about`', '`about_me`');
-  expect(newSql).to.eql(
-    'CREATE TABLE "accounts" ("id" varchar(24) not null primary key, `about_me` varchar(24))'
-  );
-});
-
-it('[backwards compatible] can rename column with double quotes', function () {
-  const client = sinon.stub();
-  const tableCompiler = sinon.stub();
-  const pragma = sinon.stub();
-  const connection = sinon.stub();
-  const ddl = new DDL(client, tableCompiler, pragma, connection);
-
-  const sql =
-    'CREATE TABLE "accounts" ("id" varchar(24) not null primary key, "about" varchar(24))';
-
-  const newSql = ddl._doReplace(sql, '"about"', '"about_me"');
-  expect(newSql).to.eql(
-    'CREATE TABLE "accounts" ("id" varchar(24) not null primary key, "about_me" varchar(24))'
-  );
-});
-
-it('[backwards compatible] can rename column with double quotes', function () {
-  const client = sinon.stub();
-  const tableCompiler = sinon.stub();
-  const pragma = sinon.stub();
-  const connection = sinon.stub();
-  const ddl = new DDL(client, tableCompiler, pragma, connection);
-
-  const sql =
-    'CREATE TABLE "accounts" ("id" varchar(24) not null primary key, "about" varchar(24))';
-
-  const newSql = ddl._doReplace(sql, '"about"', '`about_me`');
-  expect(newSql).to.eql(
-    'CREATE TABLE "accounts" ("id" varchar(24) not null primary key, `about_me` varchar(24))'
-  );
-});
-
-it('can rename column with back sticks', function () {
-  const client = sinon.stub();
-  const tableCompiler = sinon.stub();
-  const pragma = sinon.stub();
-  const connection = sinon.stub();
-  const ddl = new DDL(client, tableCompiler, pragma, connection);
-
-  const sql =
-    'CREATE TABLE `accounts` (`id` varchar(24) not null primary key, `about` varchar(24))';
-
-  const newSql = ddl._doReplace(sql, '`about`', '`about_me`');
-  expect(newSql).to.eql(
-    'CREATE TABLE `accounts` (`id` varchar(24) not null primary key, `about_me` varchar(24))'
-  );
-});
-
-it('can rename column with multiline and tabulated sql statement', function () {
-  const client = sinon.stub();
-  const tableCompiler = sinon.stub();
-  const pragma = sinon.stub();
-  const connection = sinon.stub();
-  const ddl = new DDL(client, tableCompiler, pragma, connection);
-
-  const sql =
-    'CREATE TABLE `accounts` (\n\n`id`\tvarchar(24) not null primary key,\r\n`about`\t \t\t \tvarchar(24)\n\n)';
-
-  const newSql = ddl._doReplace(sql, '`about`', '`about_me`');
-  expect(newSql).to.eql(
-    'CREATE TABLE `accounts` (`id` varchar(24) not null primary key, `about_me` varchar(24))'
-  );
-});
-
-it('can drop column with multiline and tabulated sql statement', function () {
-  const client = sinon.stub();
-  const tableCompiler = sinon.stub();
-  const pragma = sinon.stub();
-  const connection = sinon.stub();
-  const ddl = new DDL(client, tableCompiler, pragma, connection);
-
-  const sql =
-    'CREATE TABLE `accounts` (\n\n`id`\tvarchar(24) not null primary key,\r\n`about`\t \tvarchar(24)\n)';
-
-  const newSql = ddl._doReplace(sql, '`about`', '');
-  expect(newSql).to.eql(
-    'CREATE TABLE `accounts` (`id` varchar(24) not null primary key)'
-  );
-});
diff --git a/test/unit/schema-builder/sqlite3.js b/test/unit/schema-builder/sqlite3.js
index 487c172d..08bde609 100644
--- a/test/unit/schema-builder/sqlite3.js
+++ b/test/unit/schema-builder/sqlite3.js
@@ -7,7 +7,6 @@ let tableSql;
 const sinon = require('sinon');
 const SQLite3_Client = require('../../../lib/dialects/sqlite3');
 const client = new SQLite3_Client({ client: 'sqlite3' });
-const SQLite3_DDL = require('../../../lib/dialects/sqlite3/schema/ddl');
 const {
   parseCreateTable,
   parseCreateIndex,
@@ -724,35 +723,6 @@ describe('SQLite SchemaBuilder', function () {
     );
   });
 
-  describe('SQLite3_DDL.prototype._doReplace', function () {
-    it('should not change a query that has no matches', function () {
-      return client
-        .schemaBuilder()
-        .table('foo', function () {
-          const doReplace = SQLite3_DDL.prototype._doReplace;
-
-          const sql1 =
-            'CREATE TABLE `foo` (`id` integer not null primary key autoincrement, ' +
-            '"parent_id_test" integer, foreign key("parent_id") references `foo`(`id`))';
-          const sql2 =
-            'CREATE TABLE `foo` (`id` integer not null primary key autoincrement, ' +
-            '"parent_id_test" integer, foreign key("parent_id") references `bar`(`id`))';
-
-          const sql1b =
-            'CREATE TABLE `foo` ("id_foo" integer not null primary key autoincrement, ' +
-            '"parent_id_test" integer, foreign key("parent_id") references `foo`("id_foo"))';
-          const sql2b =
-            'CREATE TABLE `foo` ("id_foo" integer not null primary key autoincrement, ' +
-            '"parent_id_test" integer, foreign key("parent_id") references `bar`(`id`))';
-
-          expect(doReplace(sql1, '`bar`', '"lar"')).to.equal(sql1);
-          expect(doReplace(sql1, '`id`', '"id_foo"')).to.equal(sql1b);
-          expect(doReplace(sql2, '`id`', '"id_foo"')).to.equal(sql2b);
-        })
-        .toSQL();
-    });
-  });
-
   describe('queryContext', function () {
     let spy;
     let originalWrapIdentifier;
@@ -3974,9 +3944,9 @@ describe('SQLite parser and compiler', function () {
 
     it('wrap', function () {
       const sql =
-        'CREATE TABLE "schema".users (`foo`, [bar], CONSTRAINT [foreign_constraint] FOREIGN KEY (foo, `bar`) REFERENCES other ([baz], "bar"))';
+        'CREATE TABLE "schema".users (`foo`, [bar], \'baz\' DEFAULT "lar", CONSTRAINT [foreign_constraint] FOREIGN KEY (foo, `bar`) REFERENCES other ([baz], "bar"))';
       const newSql =
-        'CREATE TABLE "schema"."users" ("foo", "bar", CONSTRAINT "foreign_constraint" FOREIGN KEY ("foo", "bar") REFERENCES "other" ("baz", "bar"))';
+        'CREATE TABLE "schema"."users" ("foo", "bar", "baz" DEFAULT "lar", CONSTRAINT "foreign_constraint" FOREIGN KEY ("foo", "bar") REFERENCES "other" ("baz", "bar"))';
 
       const parsedSql = compileCreateTable(parseCreateTable(sql), wrap);
 
@@ -4277,9 +4247,9 @@ describe('SQLite parser and compiler', function () {
 
     it('wrap', function () {
       const sql =
-        'CREATE INDEX "schema".[users index] on `users` ("foo " ASC, [b a z] DESC, ` bar`)';
+        'CREATE INDEX "schema".[users index] on `users` ("foo " ASC, [b a z] DESC, ` bar`, \'lar\')';
       const newSql =
-        'CREATE INDEX "schema"."users index" on "users" ("foo " ASC, "b a z" DESC, " bar")';
+        'CREATE INDEX "schema"."users index" on "users" ("foo " ASC, "b a z" DESC, " bar", "lar")';
 
       const parsedSql = compileCreateIndex(parseCreateIndex(sql), wrap);