Repository: knex/knex
Pull request #4914 (2021-12-29 09:06:18)

Bump actions/setup-node from 2.4.1 to 2.5.1
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 2.4.1 to 2.5.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/actions/setup-node/releases">actions/setup-node's releases</a>.</em></p>
<blockquote>
<h2>Fix logic of error handling for npm warning and uncaught exception</h2>
<p>In scope of this release we fix logic of error handling related to caching (<a href="https://github-redirect.dependabot.com/actions/setup-node/pull/358">actions/setup-node#358</a>) and (<a href="https://github-redirect.dependabot.com/actions/setup-node/pull/359">actions/setup-node#359</a>).</p>
<p>In the previous behaviour we relied on <code>stderr</code> output to throw error. The warning messages from package managers can be written to the stderr's output. For now the action will throw an error only if exit code differs from zero. Besides, we add logic to сatch and log unhandled exceptions.</p>
<h2>Adding Node.js version file support</h2>
<p>In scope of this release we add the <code>node-version-file</code> input and update <code>actions/cache</code> dependency to the latest version.</p>
<h2>Adding Node.js version file support</h2>
<p>The new input (<code>node-version-file</code>) provides functionality to specify the path to the file containing Node.js's version with such behaviour:</p>
<ul>
<li>If the file does not exist the action will throw an error.</li>
<li>If you specify both <code>node-version</code> and <code>node-version-file</code> inputs, the action will use value from the <code>node-version</code> input and throw the following warning: <code>Both node-version and node-version-file inputs are specified, only node-version will be used</code>.</li>
<li>For now the action does not support all of the variety of values for Node.js version files. The action can handle values according to the <a href="https://github.com/actions/setup-node#supported-version-syntax">documentation</a> and values with <code>v</code> prefix (<code>v14</code>)</li>
</ul>
<pre lang="yaml"><code>steps:
  - uses: actions/checkout@v2
  - name: Setup node from node version file
    uses: actions/setup-node@v2
    with:
      node-version-file: '.nvmrc'
  - run: npm install
  - run: npm test
</code></pre>
<h2>Update actions/cache dependency to 1.0.8 version.</h2>
<p>We updated actions/cache dependency to the latest version (1.0.8). For more information please refer to the <a href="https://github.com/actions/toolkit/blob/main/packages/cache/RELEASES.md">toolkit/cache</a>.</p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/actions/setup-node/commit/1f8c6b94b26d0feae1e387ca63ccbdc44d27b561"><code>1f8c6b9</code></a> Pass to warning uncaught exceptions (<a href="https://github-redirect.dependabot.com/actions/setup-node/issues/359">#359</a>)</li>
<li><a href="https://github.com/actions/setup-node/commit/9a74eb4e6473f91fbde564f97c2662fd1dc4875c"><code>9a74eb4</code></a> Throw error only if exit code is note zero.  (<a href="https://github-redirect.dependabot.com/actions/setup-node/issues/358">#358</a>)</li>
<li><a href="https://github.com/actions/setup-node/commit/04c56d2f954f1e4c69436aa54cfef261a018f458"><code>04c56d2</code></a> update cache to 1.0.8 (<a href="https://github-redirect.dependabot.com/actions/setup-node/issues/367">#367</a>)</li>
<li><a href="https://github.com/actions/setup-node/commit/d08cf222111d5c1d21b3cd4b958937f818d10d9a"><code>d08cf22</code></a> Adding Node.js version file support (<a href="https://github-redirect.dependabot.com/actions/setup-node/issues/338">#338</a>)</li>
<li><a href="https://github.com/actions/setup-node/commit/360ab8b75b056fc18d368ee27a78d34e29c0b2d9"><code>360ab8b</code></a> Fix typo in the <code>bug_report</code> template (<a href="https://github-redirect.dependabot.com/actions/setup-node/issues/353">#353</a>)</li>
<li><a href="https://github.com/actions/setup-node/commit/fd4bd829f2dd6b6c1420bd94a93449c54612ffc2"><code>fd4bd82</code></a> Add issue and pull request templates (<a href="https://github-redirect.dependabot.com/actions/setup-node/issues/344">#344</a>)</li>
<li><a href="https://github.com/actions/setup-node/commit/a4b8ed2f4e9dd97eeae325f6967ce23d5478bd53"><code>a4b8ed2</code></a> Update dependencies (<a href="https://github-redirect.dependabot.com/actions/setup-node/issues/346">#346</a>)</li>
<li>See full diff in <a href="https://github.com/actions/setup-node/compare/v2.4.1...v2.5.1">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/setup-node&package-manager=github_actions&previous-version=2.4.1&new-version=2.5.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml
index d23c62a1..3df58f04 100644
--- a/.github/workflows/coverage.yml
+++ b/.github/workflows/coverage.yml
@@ -24,7 +24,7 @@ jobs:
           fetch-depth: 1
 
       - name: Setup Node ${{ matrix.node-version }}
-        uses: actions/setup-node@v2.4.1
+        uses: actions/setup-node@v2.5.1
         with:
           always-auth: false
           node-version: ${{ matrix.node-version }}
diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml
index 0bbf1cd2..9a8432e2 100644
--- a/.github/workflows/linting.yml
+++ b/.github/workflows/linting.yml
@@ -26,7 +26,7 @@ jobs:
           fetch-depth: 1
 
       - name: Setup Node ${{ matrix.node-version }}
-        uses: actions/setup-node@v2.4.1
+        uses: actions/setup-node@v2.5.1
         with:
           always-auth: false
           node-version: ${{ matrix.node-version }}
diff --git a/.gitignore b/.gitignore
index 9115dca3..b0d47e0f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,3 +28,5 @@ test/coverage/*
 #VsCode workspace
 .vscode
 /coverage/
+
+test/integration/migrate/migration/
diff --git a/lib/dialects/cockroachdb/crdb-tablecompiler.js b/lib/dialects/cockroachdb/crdb-tablecompiler.js
index 6991c301..5b5995d5 100644
--- a/lib/dialects/cockroachdb/crdb-tablecompiler.js
+++ b/lib/dialects/cockroachdb/crdb-tablecompiler.js
@@ -7,6 +7,25 @@ class TableCompiler_CRDB extends TableCompiler {
     super(client, tableBuilder);
   }
 
+  addColumns(columns, prefix, colCompilers) {
+    if (prefix === this.alterColumnsPrefix) {
+      // alter columns
+      for (const col of colCompilers) {
+        this.client.logger.warn(
+          'Experimental alter column in use, see issue: https://github.com/cockroachdb/cockroach/issues/49329'
+        );
+        this.pushQuery({
+          sql: 'SET enable_experimental_alter_column_type_general = true',
+          bindings: [],
+        });
+        super._addColumn(col);
+      }
+    } else {
+      // base class implementation for normal add
+      super.addColumns(columns, prefix);
+    }
+  }
+
   dropUnique(columns, indexName) {
     indexName = indexName
       ? this.formatter.wrap(indexName)
diff --git a/lib/dialects/mssql/index.js b/lib/dialects/mssql/index.js
index a918182e..29f28a44 100644
--- a/lib/dialects/mssql/index.js
+++ b/lib/dialects/mssql/index.js
@@ -1,8 +1,6 @@
 // MSSQL Client
 // -------
-const flatten = require('lodash/flatten');
 const map = require('lodash/map');
-const values = require('lodash/values');
 const isNil = require('lodash/isNil');
 
 const Client = require('../../client');
@@ -472,15 +470,6 @@ class Client_MSSQL extends Client {
           if (query.returning === '@@rowcount') {
             return response[0][''];
           }
-
-          if (
-            (Array.isArray(query.returning) && query.returning.length > 1) ||
-            query.returning[0] === '*'
-          ) {
-            return response;
-          }
-          // return an array with values if only one returning value was specified
-          return flatten(map(response, values));
         }
         return response;
       default:
diff --git a/lib/dialects/mssql/schema/mssql-columncompiler.js b/lib/dialects/mssql/schema/mssql-columncompiler.js
index 4f6e10bf..5c7bb588 100644
--- a/lib/dialects/mssql/schema/mssql-columncompiler.js
+++ b/lib/dialects/mssql/schema/mssql-columncompiler.js
@@ -3,11 +3,13 @@
 const ColumnCompiler = require('../../../schema/columncompiler');
 const { toNumber } = require('../../../util/helpers');
 const { formatDefault } = require('../../../formatter/formatterUtils');
+const { operator: operator_ } = require('../../../formatter/wrappingFormatter');
 
 class ColumnCompiler_MSSQL extends ColumnCompiler {
   constructor(client, tableCompiler, columnBuilder) {
     super(client, tableCompiler, columnBuilder);
     this.modifiers = ['nullable', 'defaultTo', 'first', 'after', 'comment'];
+    this._addCheckModifiers();
   }
 
   // Types
@@ -126,12 +128,42 @@ class ColumnCompiler_MSSQL extends ColumnCompiler {
     });
     return '';
   }
+
+  checkLength(operator, length, constraintName) {
+    return this._check(
+      `LEN(${this.formatter.wrap(this.getColumnName())}) ${operator_(
+        operator,
+        this.columnBuilder,
+        this.bindingsHolder
+      )} ${toNumber(length)}`,
+      constraintName
+    );
+  }
+
+  checkRegex(regex, constraintName) {
+    return this._check(
+      `${this.formatter.wrap(
+        this.getColumnName()
+      )} LIKE ${this.client._escapeBinding('%' + regex + '%')}`,
+      constraintName
+    );
+  }
+
+  increments(options = { primaryKey: true }) {
+    return (
+      'int identity(1,1) not null' +
+      (this.tableCompiler._canBeAddPrimaryKey(options) ? ' primary key' : '')
+    );
+  }
+
+  bigincrements(options = { primaryKey: true }) {
+    return (
+      'bigint identity(1,1) not null' +
+      (this.tableCompiler._canBeAddPrimaryKey(options) ? ' primary key' : '')
+    );
+  }
 }
 
-ColumnCompiler_MSSQL.prototype.increments = ({ primaryKey = true } = {}) =>
-  'int identity(1,1) not null' + (primaryKey ? ' primary key' : '');
-ColumnCompiler_MSSQL.prototype.bigincrements = ({ primaryKey = true } = {}) =>
-  'bigint identity(1,1) not null' + (primaryKey ? ' primary key' : '');
 ColumnCompiler_MSSQL.prototype.bigint = 'bigint';
 ColumnCompiler_MSSQL.prototype.mediumint = 'int';
 ColumnCompiler_MSSQL.prototype.smallint = 'smallint';
diff --git a/lib/dialects/mssql/schema/mssql-tablecompiler.js b/lib/dialects/mssql/schema/mssql-tablecompiler.js
index c4470954..a4d09594 100644
--- a/lib/dialects/mssql/schema/mssql-tablecompiler.js
+++ b/lib/dialects/mssql/schema/mssql-tablecompiler.js
@@ -28,6 +28,7 @@ class TableCompiler_MSSQL extends TableCompiler {
         this.tableName() +
         (this._formatting ? ' (\n    ' : ' (') +
         columns.sql.join(this._formatting ? ',\n    ' : ', ') +
+        this._addChecks() +
         ')';
     }
 
diff --git a/lib/dialects/mysql/schema/mysql-columncompiler.js b/lib/dialects/mysql/schema/mysql-columncompiler.js
index c44af84f..c9bd9162 100644
--- a/lib/dialects/mysql/schema/mysql-columncompiler.js
+++ b/lib/dialects/mysql/schema/mysql-columncompiler.js
@@ -18,6 +18,7 @@ class ColumnCompiler_MySQL extends ColumnCompiler {
       'first',
       'after',
     ];
+    this._addCheckModifiers();
   }
 
   // Types
@@ -152,13 +153,39 @@ class ColumnCompiler_MySQL extends ColumnCompiler {
   collate(collation) {
     return collation && `collate '${collation}'`;
   }
+
+  checkRegex(regex, constraintName) {
+    return this._check(
+      `${this.formatter.wrap(
+        this.getColumnName()
+      )} REGEXP ${this.client._escapeBinding(regex)}`,
+      constraintName
+    );
+  }
+
+  increments(options = { primaryKey: true }) {
+    return (
+      'int unsigned not null' +
+      // In MySQL autoincrement are always a primary key. If you already have a primary key, we
+      // initialize this column as classic int column then modify it later in table compiler
+      (this.tableCompiler._canBeAddPrimaryKey(options)
+        ? ' auto_increment primary key'
+        : '')
+    );
+  }
+
+  bigincrements(options = { primaryKey: true }) {
+    return (
+      'bigint unsigned not null' +
+      // In MySQL autoincrement are always a primary key. If you already have a primary key, we
+      // initialize this column as classic int column then modify it later in table compiler
+      (this.tableCompiler._canBeAddPrimaryKey(options)
+        ? ' auto_increment primary key'
+        : '')
+    );
+  }
 }
 
-ColumnCompiler_MySQL.prototype.increments = ({ primaryKey = true } = {}) =>
-  'int unsigned not null auto_increment' + (primaryKey ? ' primary key' : '');
-ColumnCompiler_MySQL.prototype.bigincrements = ({ primaryKey = true } = {}) =>
-  'bigint unsigned not null auto_increment' +
-  (primaryKey ? ' primary key' : '');
 ColumnCompiler_MySQL.prototype.bigint = 'bigint';
 ColumnCompiler_MySQL.prototype.mediumint = 'mediumint';
 ColumnCompiler_MySQL.prototype.smallint = 'smallint';
diff --git a/lib/dialects/mysql/schema/mysql-tablecompiler.js b/lib/dialects/mysql/schema/mysql-tablecompiler.js
index d3b512b3..1e39710b 100644
--- a/lib/dialects/mysql/schema/mysql-tablecompiler.js
+++ b/lib/dialects/mysql/schema/mysql-tablecompiler.js
@@ -19,7 +19,7 @@ class TableCompiler_MySQL extends TableCompiler {
       : 'create table ';
     const { client } = this;
     let conn = {};
-    const columnsSql = ' (' + columns.sql.join(', ') + ')';
+    const columnsSql = ' (' + columns.sql.join(', ') + this._addChecks() + ')';
     let sql =
       createStatement +
       this.tableName() +
@@ -253,11 +253,31 @@ class TableCompiler_MySQL extends TableCompiler {
     constraintName = constraintName
       ? this.formatter.wrap(constraintName)
       : this.formatter.wrap(`${this.tableNameRaw}_pkey`);
+
+    const primaryCols = columns;
+    let incrementsCols = [];
+    if (this.grouped.columns) {
+      incrementsCols = this._getIncrementsColumnNames();
+      if (incrementsCols) {
+        incrementsCols.forEach((c) => {
+          if (!primaryCols.includes(c)) {
+            primaryCols.unshift(c);
+          }
+        });
+      }
+    }
     this.pushQuery(
       `alter table ${this.tableName()} add primary key ${constraintName}(${this.formatter.columnize(
-        columns
+        primaryCols
       )})`
     );
+    if (incrementsCols.length) {
+      this.pushQuery(
+        `alter table ${this.tableName()} modify column ${this.formatter.columnize(
+          incrementsCols
+        )} int unsigned not null auto_increment`
+      );
+    }
   }
 
   unique(columns, indexName) {
diff --git a/lib/dialects/oracle/schema/internal/trigger.js b/lib/dialects/oracle/schema/internal/trigger.js
index 859862a6..d84ff933 100644
--- a/lib/dialects/oracle/schema/internal/trigger.js
+++ b/lib/dialects/oracle/schema/internal/trigger.js
@@ -64,7 +64,7 @@ const trigger = {
       `PK_NAME VARCHAR(200); ` +
       `BEGIN` +
       `  EXECUTE IMMEDIATE ('CREATE SEQUENCE ${schemaQuoted}${sequenceNameQuoted}');` +
-      `  SELECT cols.column_name INTO PK_NAME` +
+      `  SELECT cols.column_name INTO PK_NAME` + // TODO : support autoincrement on table with multiple primary keys
       `  FROM all_constraints cons, all_cons_columns cols` +
       `  WHERE cons.constraint_type = 'P'` +
       `  AND cons.constraint_name = cols.constraint_name` +
diff --git a/lib/dialects/oracle/schema/oracle-columncompiler.js b/lib/dialects/oracle/schema/oracle-columncompiler.js
index 8482c12f..589301b4 100644
--- a/lib/dialects/oracle/schema/oracle-columncompiler.js
+++ b/lib/dialects/oracle/schema/oracle-columncompiler.js
@@ -15,14 +15,20 @@ class ColumnCompiler_Oracle extends ColumnCompiler {
     this.modifiers = ['defaultTo', 'checkIn', 'nullable', 'comment'];
   }
 
-  increments({ primaryKey = true } = {}) {
+  increments(options = { primaryKey: true }) {
     createAutoIncrementTriggerAndSequence(this);
-    return 'integer not null' + (primaryKey ? ' primary key' : '');
+    return (
+      'integer not null' +
+      (this.tableCompiler._canBeAddPrimaryKey(options) ? ' primary key' : '')
+    );
   }
 
-  bigincrements({ primaryKey = true } = {}) {
+  bigincrements(options = { primaryKey: true }) {
     createAutoIncrementTriggerAndSequence(this);
-    return 'number(20, 0) not null' + (primaryKey ? ' primary key' : '');
+    return (
+      'number(20, 0) not null' +
+      (this.tableCompiler._canBeAddPrimaryKey(options) ? ' primary key' : '')
+    );
   }
 
   floating(precision) {
diff --git a/lib/dialects/oracle/schema/oracle-tablecompiler.js b/lib/dialects/oracle/schema/oracle-tablecompiler.js
index 2dbe6944..fb704a9d 100644
--- a/lib/dialects/oracle/schema/oracle-tablecompiler.js
+++ b/lib/dialects/oracle/schema/oracle-tablecompiler.js
@@ -57,7 +57,7 @@ class TableCompiler_Oracle extends TableCompiler {
     const columnsSql =
       like && this.tableNameLike()
         ? ' as (select * from ' + this.tableNameLike() + ' where 0=1)'
-        : ' (' + columns.sql.join(', ') + ')';
+        : ' (' + columns.sql.join(', ') + this._addChecks() + ')';
     const sql = `create table ${this.tableName()}${columnsSql}`;
 
     this.pushQuery({
@@ -85,10 +85,6 @@ class TableCompiler_Oracle extends TableCompiler {
     );
   }
 
-  changeType() {
-    // alter table + table + ' modify ' + wrapped + '// type';
-  }
-
   _indexCommand(type, tableName, columns) {
     return this.formatter.wrap(
       utils.generateCombinedName(this.client.logger, type, tableName, columns)
@@ -104,9 +100,21 @@ class TableCompiler_Oracle extends TableCompiler {
     constraintName = constraintName
       ? this.formatter.wrap(constraintName)
       : this.formatter.wrap(`${this.tableNameRaw}_pkey`);
+    const primaryCols = columns;
+    let incrementsCols = [];
+    if (this.grouped.columns) {
+      incrementsCols = this._getIncrementsColumnNames();
+      if (incrementsCols) {
+        incrementsCols.forEach((c) => {
+          if (!primaryCols.includes(c)) {
+            primaryCols.unshift(c);
+          }
+        });
+      }
+    }
     this.pushQuery(
       `alter table ${this.tableName()} add constraint ${constraintName} primary key (${this.formatter.columnize(
-        columns
+        primaryCols
       )})${deferrable}`
     );
   }
diff --git a/lib/dialects/oracledb/index.js b/lib/dialects/oracledb/index.js
index a1c3777e..cba691d8 100644
--- a/lib/dialects/oracledb/index.js
+++ b/lib/dialects/oracledb/index.js
@@ -4,7 +4,6 @@ const each = require('lodash/each');
 const flatten = require('lodash/flatten');
 const isEmpty = require('lodash/isEmpty');
 const map = require('lodash/map');
-const values = require('lodash/values');
 
 const Formatter = require('../../formatter');
 const QueryCompiler = require('./query/oracledb-querycompiler');
@@ -288,9 +287,6 @@ class Client_Oracledb extends Client_Oracle {
       case 'update':
       case 'counter':
         if (obj.returning && !isEmpty(obj.returning)) {
-          if (obj.returning.length === 1 && obj.returning[0] !== '*') {
-            return flatten(map(response, values));
-          }
           return response;
         } else if (obj.rowsAffected !== undefined) {
           return obj.rowsAffected;
diff --git a/lib/dialects/oracledb/schema/oracledb-columncompiler.js b/lib/dialects/oracledb/schema/oracledb-columncompiler.js
index 136bf729..117a74f4 100644
--- a/lib/dialects/oracledb/schema/oracledb-columncompiler.js
+++ b/lib/dialects/oracledb/schema/oracledb-columncompiler.js
@@ -4,6 +4,8 @@ const { isObject } = require('../../../util/is');
 class ColumnCompiler_Oracledb extends ColumnCompiler_Oracle {
   constructor() {
     super(...arguments);
+    this.modifiers = ['defaultTo', 'nullable', 'comment'];
+    this._addCheckModifiers();
   }
 
   datetime(withoutTz) {
@@ -26,6 +28,15 @@ class ColumnCompiler_Oracledb extends ColumnCompiler_Oracle {
     return useTz ? 'timestamp with local time zone' : 'timestamp';
   }
 
+  checkRegex(regex, constraintName) {
+    return this._check(
+      `REGEXP_LIKE(${this.formatter.wrap(
+        this.getColumnName()
+      )},${this.client._escapeBinding(regex)})`,
+      constraintName
+    );
+  }
+
   json() {
     return `varchar2(4000) check (${this.formatter.columnize(
       this.getColumnName()
diff --git a/lib/dialects/postgres/index.js b/lib/dialects/postgres/index.js
index 6834bdaa..97576e7f 100644
--- a/lib/dialects/postgres/index.js
+++ b/lib/dialects/postgres/index.js
@@ -246,12 +246,7 @@ class Client_PG extends Client {
       const returns = [];
       for (let i = 0, l = resp.rows.length; i < l; i++) {
         const row = resp.rows[i];
-        if (returning === '*' || Array.isArray(returning)) {
-          returns[i] = row;
-        } else {
-          // Pluck the only column in the row.
-          returns[i] = row[Object.keys(row)[0]];
-        }
+        returns[i] = row;
       }
       return returns;
     }
diff --git a/lib/dialects/postgres/query/pg-querycompiler.js b/lib/dialects/postgres/query/pg-querycompiler.js
index 3e1dac3b..779ce5c3 100644
--- a/lib/dialects/postgres/query/pg-querycompiler.js
+++ b/lib/dialects/postgres/query/pg-querycompiler.js
@@ -40,7 +40,7 @@ class QueryCompiler_PG extends QueryCompiler {
     if (returning) sql += this._returning(returning);
 
     return {
-      sql: sql,
+      sql,
       returning,
     };
   }
diff --git a/lib/dialects/postgres/schema/pg-columncompiler.js b/lib/dialects/postgres/schema/pg-columncompiler.js
index 5fb7fa25..569c0172 100644
--- a/lib/dialects/postgres/schema/pg-columncompiler.js
+++ b/lib/dialects/postgres/schema/pg-columncompiler.js
@@ -10,6 +10,7 @@ class ColumnCompiler_PG extends ColumnCompiler {
   constructor(client, tableCompiler, columnBuilder) {
     super(client, tableCompiler, columnBuilder);
     this.modifiers = ['nullable', 'defaultTo', 'comment'];
+    this._addCheckModifiers();
   }
 
   // Types
@@ -64,6 +65,15 @@ class ColumnCompiler_PG extends ColumnCompiler {
     return jsonColumn(this.client, true);
   }
 
+  checkRegex(regex, constraintName) {
+    return this._check(
+      `${this.formatter.wrap(
+        this.getColumnName()
+      )} ~ ${this.client._escapeBinding(regex)}`,
+      constraintName
+    );
+  }
+
   datetime(withoutTz = false, precision) {
     let useTz;
     if (isObject(withoutTz)) {
@@ -100,12 +110,22 @@ class ColumnCompiler_PG extends ColumnCompiler {
       );
     }, comment);
   }
+
+  increments(options = { primaryKey: true }) {
+    return (
+      'serial' +
+      (this.tableCompiler._canBeAddPrimaryKey(options) ? ' primary key' : '')
+    );
+  }
+
+  bigincrements(options = { primaryKey: true }) {
+    return (
+      'bigserial' +
+      (this.tableCompiler._canBeAddPrimaryKey(options) ? ' primary key' : '')
+    );
+  }
 }
 
-ColumnCompiler_PG.prototype.bigincrements = ({ primaryKey = true } = {}) =>
-  'bigserial' + (primaryKey ? ' primary key' : '');
-ColumnCompiler_PG.prototype.increments = ({ primaryKey = true } = {}) =>
-  'serial' + (primaryKey ? ' primary key' : '');
 ColumnCompiler_PG.prototype.bigint = 'bigint';
 ColumnCompiler_PG.prototype.binary = 'bytea';
 ColumnCompiler_PG.prototype.bool = 'boolean';
diff --git a/lib/dialects/postgres/schema/pg-tablecompiler.js b/lib/dialects/postgres/schema/pg-tablecompiler.js
index d9223bde..0a29b75a 100644
--- a/lib/dialects/postgres/schema/pg-tablecompiler.js
+++ b/lib/dialects/postgres/schema/pg-tablecompiler.js
@@ -44,7 +44,7 @@ class TableCompiler_PG extends TableCompiler {
     const createStatement = ifNot
       ? 'create table if not exists '
       : 'create table ';
-    const columnsSql = ' (' + columns.sql.join(', ') + ')';
+    const columnsSql = ' (' + columns.sql.join(', ') + this._addChecks() + ')';
     let sql =
       createStatement +
       this.tableName() +
@@ -69,51 +69,7 @@ class TableCompiler_PG extends TableCompiler {
     if (prefix === this.alterColumnsPrefix) {
       // alter columns
       for (const col of colCompilers) {
-        const quotedTableName = this.tableName();
-        const type = col.getColumnType();
-        // We'd prefer to call this.formatter.wrapAsIdentifier here instead, however the context passed to
-        // `this` instance is not that of the column, but of the table. Thus, we unfortunately have to call
-        // `wrapIdentifier` here as well (it is already called once on the initial column operation) to give
-        // our `alter` operation the correct `queryContext`. Refer to issue #2606 and PR #2612.
-        const colName = this.client.wrapIdentifier(
-          col.getColumnName(),
-          col.columnBuilder.queryContext()
-        );
-
-        // To alter enum columns they must be cast to text first
-        const isEnum = col.type === 'enu';
-
-        this.pushQuery({
-          sql: `alter table ${quotedTableName} alter column ${colName} drop default`,
-          bindings: [],
-        });
-        this.pushQuery({
-          sql: `alter table ${quotedTableName} alter column ${colName} drop not null`,
-          bindings: [],
-        });
-        this.pushQuery({
-          sql: `alter table ${quotedTableName} alter column ${colName} type ${type} using (${colName}${
-            isEnum ? '::text::' : '::'
-          }${type})`,
-          bindings: [],
-        });
-
-        const defaultTo = col.modified['defaultTo'];
-        if (defaultTo) {
-          const modifier = col.defaultTo.apply(col, defaultTo);
-          this.pushQuery({
-            sql: `alter table ${quotedTableName} alter column ${colName} set ${modifier}`,
-            bindings: [],
-          });
-        }
-
-        const nullable = col.modified['nullable'];
-        if (nullable && nullable[0] === false) {
-          this.pushQuery({
-            sql: `alter table ${quotedTableName} alter column ${colName} set not null`,
-            bindings: [],
-          });
-        }
+        this._addColumn(col);
       }
     } else {
       // base class implementation for normal add
@@ -121,6 +77,54 @@ class TableCompiler_PG extends TableCompiler {
     }
   }
 
+  _addColumn(col) {
+    const quotedTableName = this.tableName();
+    const type = col.getColumnType();
+    // We'd prefer to call this.formatter.wrapAsIdentifier here instead, however the context passed to
+    // `this` instance is not that of the column, but of the table. Thus, we unfortunately have to call
+    // `wrapIdentifier` here as well (it is already called once on the initial column operation) to give
+    // our `alter` operation the correct `queryContext`. Refer to issue #2606 and PR #2612.
+    const colName = this.client.wrapIdentifier(
+      col.getColumnName(),
+      col.columnBuilder.queryContext()
+    );
+
+    // To alter enum columns they must be cast to text first
+    const isEnum = col.type === 'enu';
+
+    this.pushQuery({
+      sql: `alter table ${quotedTableName} alter column ${colName} drop default`,
+      bindings: [],
+    });
+    this.pushQuery({
+      sql: `alter table ${quotedTableName} alter column ${colName} drop not null`,
+      bindings: [],
+    });
+    this.pushQuery({
+      sql: `alter table ${quotedTableName} alter column ${colName} type ${type} using (${colName}${
+        isEnum ? '::text::' : '::'
+      }${type})`,
+      bindings: [],
+    });
+
+    const defaultTo = col.modified['defaultTo'];
+    if (defaultTo) {
+      const modifier = col.defaultTo.apply(col, defaultTo);
+      this.pushQuery({
+        sql: `alter table ${quotedTableName} alter column ${colName} set ${modifier}`,
+        bindings: [],
+      });
+    }
+
+    const nullable = col.modified['nullable'];
+    if (nullable && nullable[0] === false) {
+      this.pushQuery({
+        sql: `alter table ${quotedTableName} alter column ${colName} set not null`,
+        bindings: [],
+      });
+    }
+  }
+
   // Compiles the comment on the table.
   comment(comment) {
     this.pushQuery(
diff --git a/lib/dialects/redshift/schema/redshift-tablecompiler.js b/lib/dialects/redshift/schema/redshift-tablecompiler.js
index 67308b6b..9ba76642 100644
--- a/lib/dialects/redshift/schema/redshift-tablecompiler.js
+++ b/lib/dialects/redshift/schema/redshift-tablecompiler.js
@@ -30,7 +30,7 @@ class TableCompiler_Redshift extends TableCompiler_PG {
     const createStatement = ifNot
       ? 'create table if not exists '
       : 'create table ';
-    const columnsSql = ' (' + columns.sql.join(', ') + ')';
+    const columnsSql = ' (' + columns.sql.join(', ') + this._addChecks() + ')';
     let sql =
       createStatement +
       this.tableName() +
diff --git a/lib/dialects/sqlite3/index.js b/lib/dialects/sqlite3/index.js
index 82653b8c..0fed4b0f 100644
--- a/lib/dialects/sqlite3/index.js
+++ b/lib/dialects/sqlite3/index.js
@@ -162,7 +162,7 @@ class Client_SQLite3 extends Client {
   // Ensures the response is returned in the same format as other clients.
   processResponse(obj, runner) {
     const ctx = obj.context;
-    const { response } = obj;
+    const { response, returning } = obj;
     if (obj.output) return obj.output.call(runner, response);
     switch (obj.method) {
       case 'select':
@@ -171,14 +171,26 @@ class Client_SQLite3 extends Client {
         return response[0];
       case 'pluck':
         return map(response, obj.pluck);
-      case 'insert':
+      case 'insert': {
+        if (returning) {
+          if (response) {
+            return response;
+          }
+
+          // ToDo Implement after https://github.com/microsoft/vscode-node-sqlite3/issues/15 is resolved
+          this.logger.warn(
+            'node-sqlite3 does not currently support RETURNING clause'
+          );
+        }
         return [ctx.lastID];
+      }
       case 'del':
       case 'update':
       case 'counter':
         return ctx.changes;
-      default:
+      default: {
         return response;
+      }
     }
   }
 
diff --git a/lib/dialects/sqlite3/query/sqlite-querycompiler.js b/lib/dialects/sqlite3/query/sqlite-querycompiler.js
index 97e155ca..6096eab5 100644
--- a/lib/dialects/sqlite3/query/sqlite-querycompiler.js
+++ b/lib/dialects/sqlite3/query/sqlite-querycompiler.js
@@ -20,14 +20,6 @@ class QueryCompiler_SQLite3 extends QueryCompiler {
   constructor(client, builder, formatter) {
     super(client, builder, formatter);
 
-    const { returning } = this.single;
-
-    if (returning) {
-      this.client.logger.warn(
-        '.returning() is not supported by sqlite3 and will not have any effect.'
-      );
-    }
-
     // The locks are not applicable in SQLite3
     this.forShare = emptyStr;
     this.forKeyShare = emptyStr;
@@ -50,20 +42,28 @@ class QueryCompiler_SQLite3 extends QueryCompiler {
         insertValues[0] &&
         isEmpty(insertValues[0])
       ) {
-        return sql + this._emptyInsertValue;
+        return {
+          sql: sql + this._emptyInsertValue,
+        };
       }
     } else if (typeof insertValues === 'object' && isEmpty(insertValues)) {
-      return sql + this._emptyInsertValue;
+      return {
+        sql: sql + this._emptyInsertValue,
+      };
     }
 
     const insertData = this._prepInsert(insertValues);
 
     if (isString(insertData)) {
-      return sql + insertData;
+      return {
+        sql: sql + insertData,
+      };
     }
 
     if (insertData.columns.length === 0) {
-      return '';
+      return {
+        sql: '',
+      };
     }
 
     sql += `(${this.formatter.columnize(insertData.columns)})`;
@@ -99,7 +99,15 @@ class QueryCompiler_SQLite3 extends QueryCompiler {
         if (wheres) sql += ` ${wheres}`;
       }
 
-      return sql;
+      const { returning } = this.single;
+      if (returning) {
+        sql += this._returning(returning);
+      }
+
+      return {
+        sql,
+        returning,
+      };
     }
 
     const blocks = [];
@@ -132,7 +140,13 @@ class QueryCompiler_SQLite3 extends QueryCompiler {
         ' where true' + this._merge(merge.updates, onConflict, insertValues);
     }
 
-    return sql;
+    const { returning } = this.single;
+    if (returning) sql += this._returning(returning);
+
+    return {
+      sql,
+      returning,
+    };
   }
 
   _ignore(columns) {
@@ -188,6 +202,10 @@ class QueryCompiler_SQLite3 extends QueryCompiler {
     }
   }
 
+  _returning(value) {
+    return value ? ` returning ${this.formatter.columnize(value)}` : '';
+  }
+
   // Compile a truncate table statement into SQL.
   truncate() {
     const { table } = this.single;
diff --git a/lib/dialects/sqlite3/schema/ddl.js b/lib/dialects/sqlite3/schema/ddl.js
index 0e2a9db8..5bec4d48 100644
--- a/lib/dialects/sqlite3/schema/ddl.js
+++ b/lib/dialects/sqlite3/schema/ddl.js
@@ -7,7 +7,6 @@
 const identity = require('lodash/identity');
 const { nanonum } = require('../../../util/nanoid');
 const {
-  createNewTable,
   copyData,
   dropOriginal,
   renameTable,
@@ -88,14 +87,11 @@ class SQLite3_DDL {
     return trx.raw(copyData(this.tableName(), this.alteredName, columns));
   }
 
-  createNewTable(trx, sql) {
-    return trx.raw(createNewTable(sql, this.tableName(), this.alteredName));
-  }
-
   async alterColumn(columns) {
     const { createTable, createIndices } = await this.getTableSql();
 
     const parsedTable = parseCreateTable(createTable);
+    parsedTable.table = this.alteredName;
 
     parsedTable.columns = parsedTable.columns.map((column) => {
       const newColumnInfo = columns.find((c) => isEqualId(c.name, column.name));
@@ -133,6 +129,7 @@ class SQLite3_DDL {
     const { createTable, createIndices } = await this.getTableSql();
 
     const parsedTable = parseCreateTable(createTable);
+    parsedTable.table = this.alteredName;
 
     parsedTable.columns = parsedTable.columns.filter(
       (parsedColumn) =>
@@ -190,6 +187,7 @@ class SQLite3_DDL {
     const { createTable, createIndices } = await this.getTableSql();
 
     const parsedTable = parseCreateTable(createTable);
+    parsedTable.table = this.alteredName;
 
     if (!foreignKeyName) {
       parsedTable.columns = parsedTable.columns.map((column) => ({
@@ -223,6 +221,7 @@ class SQLite3_DDL {
     const { createTable, createIndices } = await this.getTableSql();
 
     const parsedTable = parseCreateTable(createTable);
+    parsedTable.table = this.alteredName;
 
     parsedTable.columns = parsedTable.columns.map((column) => ({
       ...column,
@@ -252,6 +251,7 @@ class SQLite3_DDL {
     const { createTable, createIndices } = await this.getTableSql();
 
     const parsedTable = parseCreateTable(createTable);
+    parsedTable.table = this.alteredName;
 
     parsedTable.columns = parsedTable.columns.map((column) => ({
       ...column,
@@ -283,6 +283,7 @@ class SQLite3_DDL {
     const { createTable, createIndices } = await this.getTableSql();
 
     const parsedTable = parseCreateTable(createTable);
+    parsedTable.table = this.alteredName;
 
     parsedTable.constraints.push({
       type: 'FOREIGN KEY',
@@ -307,6 +308,8 @@ class SQLite3_DDL {
     const { createTable, createIndices } = await this.getTableSql();
 
     const parsedTable = parseCreateTable(createTable);
+    parsedTable.table = this.alteredName;
+
     const parsedColumn = parsedTable.columns.find((c) =>
       isEqualId(column, c.name)
     );
@@ -340,7 +343,7 @@ class SQLite3_DDL {
     try {
       await this.client.transaction(
         async (trx) => {
-          await this.createNewTable(trx, newSql);
+          await trx.raw(newSql);
           await this.copyData(trx, columns);
           await this.dropOriginal(trx);
           await this.renameTable(trx);
@@ -372,7 +375,7 @@ class SQLite3_DDL {
     const post = [];
     let check = null;
 
-    sql.push(createNewTable(newSql, this.tableName(), this.alteredName));
+    sql.push(newSql);
     sql.push(copyData(this.tableName(), this.alteredName, columns));
     sql.push(dropOriginal(this.tableName()));
     sql.push(renameTable(this.alteredName, this.tableName()));
diff --git a/lib/dialects/sqlite3/schema/internal/sqlite-ddl-operations.js b/lib/dialects/sqlite3/schema/internal/sqlite-ddl-operations.js
index c51a7611..4a66f1ae 100644
--- a/lib/dialects/sqlite3/schema/internal/sqlite-ddl-operations.js
+++ b/lib/dialects/sqlite3/schema/internal/sqlite-ddl-operations.js
@@ -1,21 +1,17 @@
-function createNewTable(sql, tablename, alteredName) {
-  return sql.replace(tablename, alteredName);
-}
-
 function copyData(sourceTable, targetTable, columns) {
-  return `INSERT INTO ${targetTable} SELECT ${
+  return `INSERT INTO "${targetTable}" SELECT ${
     columns === undefined
       ? '*'
       : columns.map((column) => `"${column}"`).join(', ')
-  } FROM ${sourceTable};`;
+  } FROM "${sourceTable}";`;
 }
 
 function dropOriginal(tableName) {
-  return `DROP TABLE '${tableName}'`;
+  return `DROP TABLE "${tableName}"`;
 }
 
 function renameTable(tableName, alteredName) {
-  return `ALTER TABLE '${tableName}' RENAME TO '${alteredName}'`;
+  return `ALTER TABLE "${tableName}" RENAME TO "${alteredName}"`;
 }
 
 function getTableSql(tableName) {
@@ -35,7 +31,6 @@ function executeForeignCheck() {
 }
 
 module.exports = {
-  createNewTable,
   copyData,
   dropOriginal,
   renameTable,
diff --git a/lib/dialects/sqlite3/schema/sqlite-columncompiler.js b/lib/dialects/sqlite3/schema/sqlite-columncompiler.js
index 787830ba..0ef4394d 100644
--- a/lib/dialects/sqlite3/schema/sqlite-columncompiler.js
+++ b/lib/dialects/sqlite3/schema/sqlite-columncompiler.js
@@ -7,6 +7,7 @@ class ColumnCompiler_SQLite3 extends ColumnCompiler {
   constructor() {
     super(...arguments);
     this.modifiers = ['nullable', 'defaultTo'];
+    this._addCheckModifiers();
   }
 
   // Types
@@ -17,6 +18,21 @@ class ColumnCompiler_SQLite3 extends ColumnCompiler {
       this.args[0]
     )} in ('${allowed.join("', '")}'))`;
   }
+
+  _pushAlterCheckQuery(checkPredicate, constraintName) {
+    throw new Error(
+      `Alter table with to add constraints is not permitted in SQLite`
+    );
+  }
+
+  checkRegex(regexes, constraintName) {
+    return this._check(
+      `${this.formatter.wrap(
+        this.getColumnName()
+      )} REGEXP ${this.client._escapeBinding(regexes)}`,
+      constraintName
+    );
+  }
 }
 
 ColumnCompiler_SQLite3.prototype.json = 'json';
@@ -26,5 +42,9 @@ ColumnCompiler_SQLite3.prototype.double =
   ColumnCompiler_SQLite3.prototype.floating =
     'float';
 ColumnCompiler_SQLite3.prototype.timestamp = 'datetime';
+// autoincrement without primary key is a syntax error in SQLite, so it's necessary
+ColumnCompiler_SQLite3.prototype.increments =
+  ColumnCompiler_SQLite3.prototype.bigincrements =
+    'integer not null primary key autoincrement';
 
 module.exports = ColumnCompiler_SQLite3;
diff --git a/lib/dialects/sqlite3/schema/sqlite-compiler.js b/lib/dialects/sqlite3/schema/sqlite-compiler.js
index 49fc0505..282ca01f 100644
--- a/lib/dialects/sqlite3/schema/sqlite-compiler.js
+++ b/lib/dialects/sqlite3/schema/sqlite-compiler.js
@@ -17,7 +17,7 @@ class SchemaCompiler_SQLite3 extends SchemaCompiler {
     const sql =
       `select * from sqlite_master ` +
       `where type = 'table' and name = ${this.client.parameter(
-        tableName,
+        this.formatter.wrap(tableName).replace(/`/g, ''),
         this.builder,
         this.bindingsHolder
       )}`;
diff --git a/lib/dialects/sqlite3/schema/sqlite-tablecompiler.js b/lib/dialects/sqlite3/schema/sqlite-tablecompiler.js
index 2c8271f3..930693f1 100644
--- a/lib/dialects/sqlite3/schema/sqlite-tablecompiler.js
+++ b/lib/dialects/sqlite3/schema/sqlite-tablecompiler.js
@@ -27,6 +27,7 @@ class TableCompiler_SQLite3 extends TableCompiler {
       sql += ' (' + columns.sql.join(', ');
       sql += this.foreignKeys() || '';
       sql += this.primaryKeys() || '';
+      sql += this._addChecks();
       sql += ')';
     }
     this.pushQuery(sql);
@@ -261,9 +262,14 @@ class TableCompiler_SQLite3 extends TableCompiler {
       if (constraintName) {
         constraintName = ' constraint ' + this.formatter.wrap(constraintName);
       }
-      return `,${constraintName} primary key (${this.formatter.columnize(
-        columns
-      )})`;
+      const needUniqueCols =
+        this.grouped.columns.filter((t) => t.builder._type === 'increments')
+          .length > 0;
+      // SQLite dont support autoincrement columns and composite primary keys (autoincrement is always primary key).
+      // You need to add unique index instead when you have autoincrement columns (https://stackoverflow.com/a/6154876/1535159)
+      return `,${constraintName} ${
+        needUniqueCols ? 'unique' : 'primary key'
+      } (${this.formatter.columnize(columns)})`;
     }
   }
 
diff --git a/lib/dialects/sqlite3/schema/sqlite-viewcompiler.js b/lib/dialects/sqlite3/schema/sqlite-viewcompiler.js
index 1359d77e..77f42244 100644
--- a/lib/dialects/sqlite3/schema/sqlite-viewcompiler.js
+++ b/lib/dialects/sqlite3/schema/sqlite-viewcompiler.js
@@ -1,11 +1,40 @@
 /* eslint max-len: 0 */
 
 const ViewCompiler = require('../../../schema/viewcompiler.js');
+const {
+  columnize: columnize_,
+} = require('../../../formatter/wrappingFormatter');
 
-class ViewCompiler_PG extends ViewCompiler {
+class ViewCompiler_SQLite3 extends ViewCompiler {
   constructor(client, viewCompiler) {
     super(client, viewCompiler);
   }
+  createOrReplace() {
+    const columns = this.columns;
+    const selectQuery = this.selectQuery.toString();
+    const viewName = this.viewName();
+
+    const columnList = columns
+      ? ' (' +
+        columnize_(
+          columns,
+          this.viewBuilder,
+          this.client,
+          this.bindingsHolder
+        ) +
+        ')'
+      : '';
+
+    const dropSql = `drop view if exists ${viewName}`;
+    const createSql = `create view ${viewName}${columnList} as ${selectQuery}`;
+
+    this.pushQuery({
+      sql: dropSql,
+    });
+    this.pushQuery({
+      sql: createSql,
+    });
+  }
 }
 
-module.exports = ViewCompiler_PG;
+module.exports = ViewCompiler_SQLite3;
diff --git a/lib/migrations/migrate/stub/knexfile-ts.stub b/lib/migrations/migrate/stub/knexfile-ts.stub
index 42d283f9..76618108 100644
--- a/lib/migrations/migrate/stub/knexfile-ts.stub
+++ b/lib/migrations/migrate/stub/knexfile-ts.stub
@@ -1,7 +1,8 @@
-// Update with your config settings.
+import type { Knex } from "knex";
 
-module.exports = {
+// Update with your config settings.
 
+const config: { [key: string]: Knex.Config } = {
   development: {
     client: "sqlite3",
     connection: {
@@ -42,3 +43,5 @@ module.exports = {
   }
 
 };
+
+module.exports = config;
diff --git a/lib/schema/columnbuilder.js b/lib/schema/columnbuilder.js
index da0e871a..83fffaf3 100644
--- a/lib/schema/columnbuilder.js
+++ b/lib/schema/columnbuilder.js
@@ -42,6 +42,14 @@ const modifiers = [
   'after',
   'comment',
   'collate',
+  'check',
+  'checkPositive',
+  'checkNegative',
+  'checkIn',
+  'checkNotIn',
+  'checkBetween',
+  'checkLength',
+  'checkRegex',
 ];
 
 // Aliases for convenience.
diff --git a/lib/schema/columncompiler.js b/lib/schema/columncompiler.js
index 56a35adf..c0a7635f 100644
--- a/lib/schema/columncompiler.js
+++ b/lib/schema/columncompiler.js
@@ -9,6 +9,7 @@ const has = require('lodash/has');
 const tail = require('lodash/tail');
 const { toNumber } = require('../util/helpers');
 const { formatDefault } = require('../formatter/formatterUtils');
+const { operator: operator_ } = require('../formatter/wrappingFormatter');
 
 class ColumnCompiler {
   constructor(client, tableCompiler, columnBuilder) {
@@ -29,6 +30,21 @@ class ColumnCompiler {
 
     this.sequence = [];
     this.modifiers = [];
+
+    this.checksCount = 0;
+  }
+
+  _addCheckModifiers() {
+    this.modifiers.push(
+      'check',
+      'checkPositive',
+      'checkNegative',
+      'checkIn',
+      'checkNotIn',
+      'checkBetween',
+      'checkLength',
+      'checkRegex'
+    );
   }
 
   defaults(label) {
@@ -134,6 +150,120 @@ class ColumnCompiler {
   defaultTo(value) {
     return `default ${formatDefault(value, this.type, this.client)}`;
   }
+
+  increments(options = { primaryKey: true }) {
+    return (
+      'integer not null' +
+      (this.tableCompiler._canBeAddPrimaryKey(options) ? ' primary key' : '') +
+      ' autoincrement'
+    );
+  }
+
+  bigincrements(options = { primaryKey: true }) {
+    return this.increments(options);
+  }
+
+  _pushAlterCheckQuery(checkPredicate, constraintName) {
+    let checkName = constraintName;
+    if (!checkName) {
+      this.checksCount++;
+      checkName =
+        this.tableCompiler.tableNameRaw +
+        '_' +
+        this.getColumnName() +
+        '_' +
+        this.checksCount;
+    }
+    this.pushAdditional(function () {
+      this.pushQuery(
+        `alter table ${this.tableCompiler.tableName()} add constraint ${checkName} check(${checkPredicate})`
+      );
+    });
+  }
+
+  _checkConstraintName(constraintName) {
+    return constraintName ? `constraint ${constraintName} ` : '';
+  }
+
+  _check(checkPredicate, constraintName) {
+    if (this.columnBuilder._method === 'alter') {
+      this._pushAlterCheckQuery(checkPredicate, constraintName);
+      return '';
+    }
+    return `${this._checkConstraintName(
+      constraintName
+    )}check (${checkPredicate})`;
+  }
+
+  checkPositive(constraintName) {
+    return this._check(
+      `${this.formatter.wrap(this.getColumnName())} ${operator_(
+        '>',
+        this.columnBuilder,
+        this.bindingsHolder
+      )} 0`,
+      constraintName
+    );
+  }
+
+  checkNegative(constraintName) {
+    return this._check(
+      `${this.formatter.wrap(this.getColumnName())} ${operator_(
+        '<',
+        this.columnBuilder,
+        this.bindingsHolder
+      )} 0`,
+      constraintName
+    );
+  }
+
+  _checkIn(values, constraintName, not) {
+    return this._check(
+      `${this.formatter.wrap(this.getColumnName())} ${
+        not ? 'not ' : ''
+      }in (${values.map((v) => this.client._escapeBinding(v)).join(',')})`,
+      constraintName
+    );
+  }
+
+  checkIn(values, constraintName) {
+    return this._checkIn(values, constraintName);
+  }
+
+  checkNotIn(values, constraintName) {
+    return this._checkIn(values, constraintName, true);
+  }
+
+  checkBetween(intervals, constraintName) {
+    if (
+      intervals.length === 2 &&
+      !Array.isArray(intervals[0]) &&
+      !Array.isArray(intervals[1])
+    ) {
+      intervals = [intervals];
+    }
+    const intervalChecks = intervals
+      .map((interval) => {
+        return `${this.formatter.wrap(
+          this.getColumnName()
+        )} between ${this.client._escapeBinding(
+          interval[0]
+        )} and ${this.client._escapeBinding(interval[1])}`;
+      })
+      .join(' or ');
+    return this._check(intervalChecks, constraintName);
+  }
+
+  checkLength(operator, length, constraintName) {
+    return this._check(
+      `length(${this.formatter.wrap(this.getColumnName())}) ${operator_(
+        operator,
+        this.columnBuilder,
+        this.bindingsHolder
+      )} ${toNumber(length)}`,
+      constraintName
+    );
+  }
 }
 
 ColumnCompiler.prototype.binary = 'blob';
@@ -149,10 +279,6 @@ ColumnCompiler.prototype.enu = 'varchar';
 ColumnCompiler.prototype.bit = ColumnCompiler.prototype.json = 'text';
 ColumnCompiler.prototype.uuid = ({ useBinaryUuid = false } = {}) =>
   useBinaryUuid ? 'binary(16)' : 'char(36)';
-ColumnCompiler.prototype.increments = ({ primaryKey = true } = {}) =>
-  'integer not null' + (primaryKey ? ' primary key' : '') + ' autoincrement';
-ColumnCompiler.prototype.bigincrements = ({ primaryKey = true } = {}) =>
-  'integer not null' + (primaryKey ? ' primary key' : '') + ' autoincrement';
 ColumnCompiler.prototype.integer =
   ColumnCompiler.prototype.smallint =
   ColumnCompiler.prototype.mediumint =
diff --git a/lib/schema/tablebuilder.js b/lib/schema/tablebuilder.js
index b77f9ece..b52c031e 100644
--- a/lib/schema/tablebuilder.js
+++ b/lib/schema/tablebuilder.js
@@ -146,6 +146,14 @@ class TableBuilder {
     };
     return returnObj;
   }
+
+  check(checkPredicate, bindings, constraintName) {
+    this._statements.push({
+      grouping: 'checks',
+      args: [checkPredicate, bindings, constraintName],
+    });
+    return this;
+  }
 }
 
 [
@@ -312,6 +320,22 @@ const AlterMethods = {
     return this;
   },
 
+  check(checkPredicate, bindings, constraintName) {
+    this._statements.push({
+      grouping: 'alterTable',
+      method: 'check',
+      args: [checkPredicate, bindings, constraintName],
+    });
+  },
+
+  dropChecks() {
+    this._statements.push({
+      grouping: 'alterTable',
+      method: 'dropChecks',
+      args: toArray(arguments),
+    });
+  },
+
   dropNullable(column) {
     this._statements.push({
       grouping: 'alterTable',
diff --git a/lib/schema/tablecompiler.js b/lib/schema/tablecompiler.js
index bd4dd733..591e1e55 100644
--- a/lib/schema/tablecompiler.js
+++ b/lib/schema/tablecompiler.js
@@ -12,6 +12,7 @@ const groupBy = require('lodash/groupBy');
 const indexOf = require('lodash/indexOf');
 const isEmpty = require('lodash/isEmpty');
 const tail = require('lodash/tail');
+const { normalizeArr } = require('../util/helpers');
 
 class TableCompiler {
   constructor(client, tableBuilder) {
@@ -32,6 +33,8 @@ class TableCompiler {
 
     this.sequence = [];
     this._formatting = client.config && client.config.formatting;
+
+    this.checksCount = 0;
   }
 
   // Convert the tableCompiler toSQL
@@ -346,6 +349,43 @@ class TableCompiler {
     return this._setNullableState(column, false);
   }
 
+  dropChecks(checkConstraintNames) {
+    if (checkConstraintNames === undefined) return '';
+    checkConstraintNames = normalizeArr(checkConstraintNames);
+    const tableName = this.tableName();
+    const sql = `alter table ${tableName} ${checkConstraintNames
+      .map((constraint) => `drop constraint ${constraint}`)
+      .join(', ')}`;
+    this.pushQuery(sql);
+  }
+
+  check(checkPredicate, bindings, constraintName) {
+    const tableName = this.tableName();
+    let checkConstraint = constraintName;
+    if (!checkConstraint) {
+      this.checksCount++;
+      checkConstraint = tableName + '_' + this.checksCount;
+    }
+    const sql = `alter table ${tableName} add constraint ${checkConstraint} check(${checkPredicate})`;
+    this.pushQuery(sql);
+  }
+
+  _addChecks() {
+    if (this.grouped.checks) {
+      return (
+        ', ' +
+        this.grouped.checks
+          .map((c) => {
+            return `${
+              c.args[2] ? 'constraint ' + c.args[2] + ' ' : ''
+            }check (${this.client.raw(c.args[0], c.args[1])})`;
+          })
+          .join(', ')
+      );
+    }
+    return '';
+  }
+
   // If no name was specified for this index, we will create one using a basic
   // convention of the table name, followed by the columns, followed by an
   // index type, such as primary or index, which makes the index unique.
@@ -361,6 +401,23 @@ class TableCompiler {
     ).toLowerCase();
     return this.formatter.wrap(indexName);
   }
+
+  _getPrimaryKeys() {
+    return (this.grouped.alterTable || [])
+      .filter((a) => a.method === 'primary')
+      .flatMap((a) => a.args)
+      .flat();
+  }
+
+  _canBeAddPrimaryKey(options) {
+    return options.primaryKey && this._getPrimaryKeys().length === 0;
+  }
+
+  _getIncrementsColumnNames() {
+    return this.grouped.columns
+      .filter((c) => c.builder._type === 'increments')
+      .map((c) => c.builder._args[0]);
+  }
 }
 
 TableCompiler.prototype.pushQuery = pushQuery;
diff --git a/lib/schema/viewcompiler.js b/lib/schema/viewcompiler.js
index ea2efa23..19a9a017 100644
--- a/lib/schema/viewcompiler.js
+++ b/lib/schema/viewcompiler.js
@@ -52,8 +52,8 @@ class ViewCompiler {
     const createStatement =
       'create ' +
       (materialized ? 'materialized ' : '') +
-      'view ' +
-      (replace ? 'or replace ' : '');
+      (replace ? 'or replace ' : '') +
+      'view ';
     const columnList = columns
       ? ' (' +
         columnize_(
diff --git a/package.json b/package.json
index 6dd2671a..3e081ca0 100644
--- a/package.json
+++ b/package.json
@@ -98,9 +98,9 @@
     ]
   },
   "devDependencies": {
-    "@types/node": "^16.11.6",
+    "@types/node": "^16.11.19",
     "@vscode/sqlite3": "^5.0.7",
-    "better-sqlite3": "^7.4.5",
+    "better-sqlite3": "^7.4.6",
     "chai": "^4.3.4",
     "chai-as-promised": "^7.1.1",
     "chai-subset-in-order": "^3.1.0",
@@ -115,25 +115,25 @@
     "jake": "^8.1.1",
     "JSONStream": "^1.3.5",
     "lint-staged": "^11.1.2",
-    "mocha": "^9.1.3",
+    "mocha": "^9.1.4",
     "mock-fs": "^5.1.2",
     "mysql": "^2.18.1",
-    "mysql2": "^2.3.0",
+    "mysql2": "^2.3.3",
     "nyc": "^15.1.0",
-    "oracledb": "^5.2.0",
+    "oracledb": "^5.3.0",
     "pg": "^8.7.1",
     "pg-query-stream": "^4.2.1",
     "prettier": "2.4.1",
     "rimraf": "^3.0.2",
     "sinon": "^12.0.1",
     "sinon-chai": "^3.7.0",
-    "source-map-support": "^0.5.20",
+    "source-map-support": "^0.5.21",
     "tap-spec": "^5.0.0",
-    "tape": "^5.3.1",
+    "tape": "^5.4.0",
     "tedious": "^12.2.0",
     "toxiproxy-node-client": "^2.0.6",
     "ts-node": "^10.4.0",
-    "tsd": "^0.19.0",
+    "tsd": "^0.19.1",
     "typescript": "4.5.4"
   },
   "buildDependencies": [
diff --git a/scripts/docker-compose.yml b/scripts/docker-compose.yml
index df573779..daffdf0e 100644
--- a/scripts/docker-compose.yml
+++ b/scripts/docker-compose.yml
@@ -85,7 +85,7 @@ services:
       - 'until /usr/local/bin/psql postgres://testuser:knextest@postgres/knex_test -c "SELECT 1"; do sleep 5; done'
 
   cockroachdb:
-    image: cockroachdb/cockroach:latest-v21.1
+    image: cockroachdb/cockroach:latest-v21.2
     container_name: crdb
     hostname: crdb
     command: start-single-node --cluster-name=example-single-node --insecure
diff --git a/types/index.d.ts b/types/index.d.ts
index 89cd1a11..d9bf6e51 100644
--- a/types/index.d.ts
+++ b/types/index.d.ts
@@ -328,7 +328,7 @@ interface DMLOptions {
   includeTriggerModifications?: boolean;
 }
 
-export interface Knex<TRecord extends {} = any, TResult = unknown[]>
+export interface Knex<TRecord extends {} = any, TResult = Record<string, any>[]>
   extends Knex.QueryInterface<TRecord, TResult>, events.EventEmitter {
   <TTable extends Knex.TableNames>(
     tableName: TTable,
@@ -2148,11 +2148,13 @@ export declare namespace Knex {
       columns: readonly string[],
       foreignKeyName?: string
     ): MultikeyForeignConstraintBuilder;
+    check(checkPredicate: string, bindings?: Record<string, any>, constraintName?: string): TableBuilder;
     dropForeign(columnNames: string | readonly string[], foreignKeyName?: string): TableBuilder;
     dropUnique(columnNames: readonly (string | Raw)[], indexName?: string): TableBuilder;
     dropPrimary(constraintName?: string): TableBuilder;
     dropIndex(columnNames: string | readonly (string | Raw)[], indexName?: string): TableBuilder;
     dropTimestamps(useCamelCase?: boolean): TableBuilder;
+    dropChecks(checkConstraintNames: string | string[]): TableBuilder;
     queryContext(context: any): TableBuilder;
   }
 
@@ -2185,6 +2187,7 @@ export declare namespace Knex {
 
   type deferrableType = 'not deferrable' | 'immediate' | 'deferred';
   type storageEngineIndexType = 'hash' | 'btree';
+  type lengthOperator = '>' | '<' | '<=' | '>=' | '!=' | '=';
 
   interface ColumnBuilder {
     index(indexName?: string): ColumnBuilder;
@@ -2205,7 +2208,15 @@ export declare namespace Knex {
     queryContext(context: any): ColumnBuilder;
     after(columnName: string): ColumnBuilder;
     first(): ColumnBuilder;
+    checkPositive(constraintName?: string): ColumnBuilder;
+    checkNegative(constraintName?: string): ColumnBuilder;
+    checkIn(values: string[], constraintName?: string): ColumnBuilder;
+    checkNotIn(values: string[], constraintName?: string): ColumnBuilder;
+    checkBetween(values: any[] | any[][], constraintName?: string): ColumnBuilder;
+    checkLength(operator: lengthOperator, length: number, constraintName?: string): ColumnBuilder;
+    checkRegex(regex: string, constraintName?: string): ColumnBuilder;
   }
+
   interface ForeignConstraintBuilder {
     references(columnName: string): ReferencingColumnBuilder;
   }


Test patch:
diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml
index 81c7c107..f9506b3f 100644
--- a/.github/workflows/integration-tests.yml
+++ b/.github/workflows/integration-tests.yml
@@ -28,7 +28,7 @@ jobs:
           fetch-depth: 1
 
       - name: Setup Node ${{ matrix.node-version }}
-        uses: actions/setup-node@v2.4.1
+        uses: actions/setup-node@v2.5.1
         with:
           always-auth: false
           node-version: ${{ matrix.node-version }}
diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml
index 5c9c40a3..b069edd0 100644
--- a/.github/workflows/unit-tests.yml
+++ b/.github/workflows/unit-tests.yml
@@ -26,7 +26,7 @@ jobs:
           fetch-depth: 1
 
       - name: Setup Node ${{ matrix.node-version }}
-        uses: actions/setup-node@v2.4.1
+        uses: actions/setup-node@v2.5.1
         with:
           always-auth: false
           node-version: ${{ matrix.node-version }}
diff --git a/test/integration/execution/transaction.js b/test/integration/execution/transaction.js
index 36e0150a..8524ef9b 100644
--- a/test/integration/execution/transaction.js
+++ b/test/integration/execution/transaction.js
@@ -123,7 +123,9 @@ module.exports = function (knex) {
               return knex('test_table_two')
                 .transacting(t)
                 .insert({
-                  account_id: constid ? ++fkid : (id = resp[0]),
+                  account_id: constid
+                    ? ++fkid
+                    : (id = !isNaN(resp[0]) ? resp[0] : resp[0].id),
                   details: '',
                   status: 1,
                 });
@@ -164,7 +166,9 @@ module.exports = function (knex) {
               return knex('test_table_two')
                 .transacting(t)
                 .insert({
-                  account_id: constid ? ++fkid : (id = resp[0]),
+                  account_id: constid
+                    ? ++fkid
+                    : (id = !isNaN(resp[0]) ? resp[0] : resp[0].id),
                   details: '',
                   status: 1,
                 });
@@ -199,7 +203,9 @@ module.exports = function (knex) {
             })
             .then(function (resp) {
               return trx('test_table_two').insert({
-                account_id: constid ? ++fkid : (id = resp[0]),
+                account_id: constid
+                  ? ++fkid
+                  : (id = !isNaN(resp[0]) ? resp[0] : resp[0].id),
                 details: '',
                 status: 1,
               });
@@ -240,7 +246,9 @@ module.exports = function (knex) {
             .then(function (resp) {
               return trx
                 .insert({
-                  account_id: constid ? ++fkid : (id = resp[0]),
+                  account_id: constid
+                    ? ++fkid
+                    : (id = !isNaN(resp[0]) ? resp[0] : resp[0].id),
                   details: '',
                   status: 1,
                 })
@@ -329,7 +337,9 @@ module.exports = function (knex) {
               })
               .then(function (resp) {
                 return trx('test_table_two').insert({
-                  account_id: constid ? ++fkid : (id = resp[0]),
+                  account_id: constid
+                    ? ++fkid
+                    : (id = !isNaN(resp[0]) ? resp[0] : resp[0].id),
                   details: '',
                   status: 1,
                 });
@@ -577,7 +587,7 @@ module.exports = function (knex) {
               updated_at: new Date(),
             })
             .then(function (res0) {
-              insertedId = res0[0];
+              insertedId = !isNaN(res0[0]) ? res0[0] : res0[0].id;
             });
         }
 
diff --git a/test/integration/query/trigger-deletes.js b/test/integration/query/trigger-deletes.js
index d9bd144e..ffdb21e5 100644
--- a/test/integration/query/trigger-deletes.js
+++ b/test/integration/query/trigger-deletes.js
@@ -130,7 +130,7 @@ module.exports = function (knex) {
               ['id'],
               triggerOptions
             );
-            insertSecondary[secondaryLink] = primaryId[0];
+            insertSecondary[secondaryLink] = primaryId[0].id;
 
             // Insert to table with trigger to test delete
             insertedId = (
@@ -139,7 +139,7 @@ module.exports = function (knex) {
                 ['id'],
                 triggerOptions
               )
-            )[0];
+            )[0].id;
           }
 
           async function deleteTriggerTable() {
@@ -148,7 +148,7 @@ module.exports = function (knex) {
               await knex(secondaryTable)
                 .whereRaw(`id = ${insertedId}`)
                 .delete(['id'], triggerOptions)
-            )[0];
+            )[0].id;
           }
 
           await insertWithReturn();
@@ -184,7 +184,7 @@ module.exports = function (knex) {
               ['id'],
               triggerOptions
             );
-            insertSecondary[secondaryLink] = primaryId[0];
+            insertSecondary[secondaryLink] = primaryId[0].id;
 
             // Insert to table with trigger to test delete
             insertedId = (
@@ -193,7 +193,7 @@ module.exports = function (knex) {
                 ['id'],
                 triggerOptions
               )
-            )[0];
+            )[0].id;
           }
 
           async function deleteTriggerTable() {
@@ -203,7 +203,7 @@ module.exports = function (knex) {
                 .whereRaw(`id = ${insertedId}`)
                 .returning(['id'], triggerOptions)
                 .delete()
-            )[0];
+            )[0].id;
           }
 
           await insertWithReturn();
diff --git a/test/integration/query/trigger-inserts.js b/test/integration/query/trigger-inserts.js
index b253cc05..7a827625 100644
--- a/test/integration/query/trigger-inserts.js
+++ b/test/integration/query/trigger-inserts.js
@@ -135,7 +135,7 @@ module.exports = function (knex) {
               ['id'],
               insertTriggerOptions
             );
-            insertSecondary[secondaryLink] = primaryId[0];
+            insertSecondary[secondaryLink] = primaryId[0].id;
 
             // Test retrieve with trigger
             insertResults = (
@@ -144,7 +144,7 @@ module.exports = function (knex) {
                 ['id'],
                 insertTriggerOptions
               )
-            )[0];
+            )[0].id;
           }
 
           await insertWithReturn();
@@ -175,14 +175,14 @@ module.exports = function (knex) {
             const primaryId = await knex(primaryTable)
               .returning(['id'], insertTriggerOptions)
               .insert([insertPrimary]);
-            insertSecondary[secondaryLink] = primaryId[0];
+            insertSecondary[secondaryLink] = primaryId[0].id;
 
             // Test retrieve with trigger
             insertResults = (
               await knex(secondaryTable)
                 .returning(['id'], insertTriggerOptions)
                 .insert([insertSecondary])
-            )[0];
+            )[0].id;
           }
 
           await insertWithReturn();
@@ -245,7 +245,7 @@ module.exports = function (knex) {
                 1,
                 TEST_TIMESTAMP,
               ],
-              ['1']
+              [{ id: 1 }]
             );
             tester(
               'pg-redshift',
@@ -290,7 +290,7 @@ module.exports = function (knex) {
                   return v.toString() === '[object ReturningHelper:id]';
                 },
               ],
-              ['1']
+              [{ id: 1 }]
             );
             tester(
               'mssql',
@@ -304,7 +304,7 @@ module.exports = function (knex) {
                 1,
                 TEST_TIMESTAMP,
               ],
-              ['1']
+              [{ id: '1' }]
             );
           });
       });
@@ -466,7 +466,7 @@ module.exports = function (knex) {
                 2,
                 TEST_TIMESTAMP,
               ],
-              ['1', '2']
+              [{ id: '1' }, { id: '2' }]
             );
           });
       });
@@ -686,7 +686,7 @@ module.exports = function (knex) {
                 2,
                 TEST_TIMESTAMP,
               ],
-              ['1', '2']
+              [{ id: '1' }, { id: '2' }]
             );
           });
       });
@@ -850,7 +850,7 @@ module.exports = function (knex) {
                 2,
                 TEST_TIMESTAMP,
               ],
-              ['1']
+              [{ id: '1' }]
             );
             tester(
               'pg-redshift',
@@ -909,7 +909,7 @@ module.exports = function (knex) {
                 2,
                 TEST_TIMESTAMP,
               ],
-              ['1']
+              [{ id: '1' }]
             );
           });
       });
@@ -937,7 +937,7 @@ module.exports = function (knex) {
                   'pg',
                   'insert into "trigger_retest_insert" default values returning "id"',
                   [],
-                  [1]
+                  [{ id: 1 }]
                 );
                 tester(
                   'pg-redshift',
@@ -959,13 +959,13 @@ module.exports = function (knex) {
                       return v.toString() === '[object ReturningHelper:id]';
                     },
                   ],
-                  ['1']
+                  [{ id: 1 }]
                 );
                 tester(
                   'mssql',
                   'select top(0) [t].[id] into #out from [trigger_retest_insert] as t left join [trigger_retest_insert] on 0=1;insert into [trigger_retest_insert] output inserted.[id] into #out default values; select [id] from #out; drop table #out;',
                   [],
-                  [1]
+                  [{ id: 1 }]
                 );
               });
           });
@@ -994,7 +994,7 @@ module.exports = function (knex) {
                   'pg',
                   'insert into "trigger_retest_insert2" default values returning "id"',
                   [],
-                  [1]
+                  [{ id: '1' }]
                 );
                 tester(
                   'pg-redshift',
@@ -1022,7 +1022,7 @@ module.exports = function (knex) {
                   'mssql',
                   'select top(0) [t].[id] into #out from [trigger_retest_insert2] as t left join [trigger_retest_insert2] on 0=1;insert into [trigger_retest_insert2] output inserted.[id] into #out default values; select [id] from #out; drop table #out;',
                   [],
-                  [1]
+                  [{ id: '1' }]
                 );
               });
           });
diff --git a/test/integration/query/trigger-updates.js b/test/integration/query/trigger-updates.js
index 5cc7f145..b97e8f60 100644
--- a/test/integration/query/trigger-updates.js
+++ b/test/integration/query/trigger-updates.js
@@ -128,10 +128,10 @@ module.exports = function (knex) {
                 ['id'],
                 triggerOptions
               )
-            )[0];
+            )[0].id;
 
             const updateSecondary = {};
-            updateSecondary[secondaryLink] = primaryId[0];
+            updateSecondary[secondaryLink] = primaryId[0].id;
 
             updateResults = await knex(secondaryTable)
               .where('id', '=', secondaryId)
@@ -140,7 +140,7 @@ module.exports = function (knex) {
 
           await updateWithReturn();
 
-          expect(Number.parseInt(updateResults)).to.be.finite;
+          expect(Number.parseInt(updateResults[0].id)).to.be.finite;
 
           reachedEnd = true;
         });
@@ -176,10 +176,10 @@ module.exports = function (knex) {
                 ['id'],
                 triggerOptions
               )
-            )[0];
+            )[0].id;
 
             const updateSecondary = {};
-            updateSecondary[secondaryLink] = primaryId[0];
+            updateSecondary[secondaryLink] = primaryId[0].id;
 
             updateResults = await knex(secondaryTable)
               .where('id', '=', secondaryId)
@@ -189,7 +189,7 @@ module.exports = function (knex) {
 
           await updateWithReturn();
 
-          expect(Number.parseInt(updateResults)).to.be.finite;
+          expect(Number.parseInt(updateResults[0].id)).to.be.finite;
 
           reachedEnd = true;
         });
diff --git a/test/integration2/migrate/migration-integration.spec.js b/test/integration2/migrate/migration-integration.spec.js
index 2c138ea4..599c0f3e 100644
--- a/test/integration2/migrate/migration-integration.spec.js
+++ b/test/integration2/migrate/migration-integration.spec.js
@@ -247,9 +247,18 @@ describe('Migrations', function () {
                     .del();
                 }
                 return knex('knex_migrations')
-                  .where('id', migration1[0])
-                  .orWhere('id', migration2[0])
-                  .orWhere('id', migration3[0])
+                  .where(
+                    'id',
+                    !isNaN(migration1[0]) ? migration1[0] : migration1[0].id
+                  )
+                  .orWhere(
+                    'id',
+                    !isNaN(migration2[0]) ? migration2[0] : migration2[0].id
+                  )
+                  .orWhere(
+                    'id',
+                    !isNaN(migration3[0]) ? migration3[0] : migration3[0].id
+                  )
                   .del();
               });
           });
diff --git a/test/integration2/query/insert/inserts.spec.js b/test/integration2/query/insert/inserts.spec.js
index ad44c66a..e722edc9 100644
--- a/test/integration2/query/insert/inserts.spec.js
+++ b/test/integration2/query/insert/inserts.spec.js
@@ -98,7 +98,7 @@ describe('Inserts', function () {
                 1,
                 TEST_TIMESTAMP,
               ],
-              ['1']
+              [{ id: '1' }]
             );
             tester(
               'pg-redshift',
@@ -116,7 +116,7 @@ describe('Inserts', function () {
             );
             tester(
               'sqlite3',
-              'insert into `accounts` (`about`, `created_at`, `email`, `first_name`, `last_name`, `logins`, `updated_at`) values (?, ?, ?, ?, ?, ?, ?)',
+              'insert into `accounts` (`about`, `created_at`, `email`, `first_name`, `last_name`, `logins`, `updated_at`) values (?, ?, ?, ?, ?, ?, ?) returning `id`',
               [
                 'Lorem ipsum Dolore labore incididunt enim.',
                 TEST_TIMESTAMP,
@@ -143,7 +143,7 @@ describe('Inserts', function () {
                   return v.toString() === '[object ReturningHelper:id]';
                 },
               ],
-              ['1']
+              [{ id: 1 }]
             );
             tester(
               'mssql',
@@ -157,7 +157,7 @@ describe('Inserts', function () {
                 1,
                 TEST_TIMESTAMP,
               ],
-              ['1']
+              [{ id: '1' }]
             );
           });
       });
@@ -228,7 +228,7 @@ describe('Inserts', function () {
                 2,
                 TEST_TIMESTAMP,
               ],
-              ['1', '2']
+              [{ id: '1' }, { id: '2' }]
             );
             tester(
               'pg-redshift',
@@ -253,7 +253,7 @@ describe('Inserts', function () {
             );
             tester(
               'sqlite3',
-              'insert into `accounts` (`about`, `created_at`, `email`, `first_name`, `last_name`, `logins`, `updated_at`) select ? as `about`, ? as `created_at`, ? as `email`, ? as `first_name`, ? as `last_name`, ? as `logins`, ? as `updated_at` union all select ? as `about`, ? as `created_at`, ? as `email`, ? as `first_name`, ? as `last_name`, ? as `logins`, ? as `updated_at`',
+              'insert into `accounts` (`about`, `created_at`, `email`, `first_name`, `last_name`, `logins`, `updated_at`) select ? as `about`, ? as `created_at`, ? as `email`, ? as `first_name`, ? as `last_name`, ? as `logins`, ? as `updated_at` union all select ? as `about`, ? as `created_at`, ? as `email`, ? as `first_name`, ? as `last_name`, ? as `logins`, ? as `updated_at` returning `id`',
               [
                 'Lorem ipsum Dolore labore incididunt enim.',
                 TEST_TIMESTAMP,
@@ -297,7 +297,7 @@ describe('Inserts', function () {
                   return v.toString() === '[object ReturningHelper:id]';
                 },
               ],
-              ['1', '2']
+              [{ id: 1 }, { id: 2 }]
             );
             tester(
               'mssql',
@@ -318,7 +318,7 @@ describe('Inserts', function () {
                 2,
                 TEST_TIMESTAMP,
               ],
-              ['1', '2']
+              [{ id: '1' }, { id: '2' }]
             );
           });
       });
@@ -446,7 +446,7 @@ describe('Inserts', function () {
                 2,
                 TEST_TIMESTAMP,
               ],
-              ['1', '2']
+              [{ id: '1' }, { id: '2' }]
             );
             tester(
               'pg-redshift',
@@ -471,7 +471,7 @@ describe('Inserts', function () {
             );
             tester(
               'sqlite3',
-              'insert into `accounts` (`about`, `created_at`, `email`, `first_name`, `last_name`, `logins`, `updated_at`) select ? as `about`, ? as `created_at`, ? as `email`, ? as `first_name`, ? as `last_name`, ? as `logins`, ? as `updated_at` union all select ? as `about`, ? as `created_at`, ? as `email`, ? as `first_name`, ? as `last_name`, ? as `logins`, ? as `updated_at`',
+              'insert into `accounts` (`about`, `created_at`, `email`, `first_name`, `last_name`, `logins`, `updated_at`) select ? as `about`, ? as `created_at`, ? as `email`, ? as `first_name`, ? as `last_name`, ? as `logins`, ? as `updated_at` union all select ? as `about`, ? as `created_at`, ? as `email`, ? as `first_name`, ? as `last_name`, ? as `logins`, ? as `updated_at` returning `id`',
               [
                 'Lorem ipsum Dolore labore incididunt enim.',
                 TEST_TIMESTAMP,
@@ -515,7 +515,7 @@ describe('Inserts', function () {
                   return v.toString() === '[object ReturningHelper:id]';
                 },
               ],
-              ['1', '2']
+              [{ id: 1 }, { id: 2 }]
             );
             tester(
               'mssql',
@@ -536,7 +536,7 @@ describe('Inserts', function () {
                 2,
                 TEST_TIMESTAMP,
               ],
-              ['1', '2']
+              [{ id: '1' }, { id: '2' }]
             );
           });
       });
@@ -602,7 +602,7 @@ describe('Inserts', function () {
             );
             tester(
               'sqlite3',
-              'insert into `accounts` (`about`, `created_at`, `email`, `first_name`, `last_name`, `logins`, `updated_at`) values (?, ?, ?, ?, ?, ?, ?)',
+              'insert into `accounts` (`about`, `created_at`, `email`, `first_name`, `last_name`, `logins`, `updated_at`) values (?, ?, ?, ?, ?, ?, ?) returning `id`',
               [
                 'Lorem ipsum Dolore labore incididunt enim.',
                 TEST_TIMESTAMP,
@@ -696,7 +696,7 @@ describe('Inserts', function () {
                 2,
                 TEST_TIMESTAMP,
               ],
-              ['1']
+              [{ id: '1' }]
             );
             tester(
               'pg-redshift',
@@ -714,7 +714,7 @@ describe('Inserts', function () {
             );
             tester(
               'sqlite3',
-              'insert into `accounts` (`about`, `created_at`, `email`, `first_name`, `last_name`, `logins`, `updated_at`) values (?, ?, ?, ?, ?, ?, ?)',
+              'insert into `accounts` (`about`, `created_at`, `email`, `first_name`, `last_name`, `logins`, `updated_at`) values (?, ?, ?, ?, ?, ?, ?) returning `id`',
               [
                 'Lorem ipsum Dolore labore incididunt enim.',
                 TEST_TIMESTAMP,
@@ -741,7 +741,7 @@ describe('Inserts', function () {
                   return v.toString() === '[object ReturningHelper:id]';
                 },
               ],
-              ['1']
+              [[{ id: 1 }]]
             );
             tester(
               'mssql',
@@ -755,7 +755,7 @@ describe('Inserts', function () {
                 2,
                 TEST_TIMESTAMP,
               ],
-              ['1']
+              [{ id: '1' }]
             );
           });
       });
@@ -883,7 +883,7 @@ describe('Inserts', function () {
                   'pg',
                   'insert into "test_default_table" default values returning "id"',
                   [],
-                  [1]
+                  [{ id: 1 }]
                 );
                 tester(
                   'pg-redshift',
@@ -905,13 +905,13 @@ describe('Inserts', function () {
                       return v.toString() === '[object ReturningHelper:id]';
                     },
                   ],
-                  ['1']
+                  [{ id: 1 }]
                 );
                 tester(
                   'mssql',
                   'insert into [test_default_table] output inserted.[id] default values',
                   [],
-                  [1]
+                  [{ id: 1 }]
                 );
               });
           });
@@ -939,7 +939,7 @@ describe('Inserts', function () {
                   'pg',
                   'insert into "test_default_table2" default values returning "id"',
                   [],
-                  [1]
+                  [{ id: 1 }]
                 );
                 tester(
                   'pg-redshift',
@@ -961,13 +961,13 @@ describe('Inserts', function () {
                       return v.toString() === '[object ReturningHelper:id]';
                     },
                   ],
-                  ['1']
+                  [{ id: 1 }]
                 );
                 tester(
                   'mssql',
                   'insert into [test_default_table2] output inserted.[id] default values',
                   [],
-                  [1]
+                  [{ id: 1 }]
                 );
               });
           });
@@ -1021,7 +1021,7 @@ describe('Inserts', function () {
             );
             tester(
               'sqlite3',
-              'insert into `test_table_two` (`account_id`, `details`, `status`) values (?, ?, ?)',
+              'insert into `test_table_two` (`account_id`, `details`, `status`) values (?, ?, ?) returning `account_id`, `details`',
               [
                 10,
                 'Lorem ipsum Minim nostrud Excepteur consectetur enim ut qui sint in veniam in nulla anim do cillum sunt voluptate Duis non incididunt.',
@@ -1382,7 +1382,7 @@ describe('Inserts', function () {
               );
               tester(
                 'sqlite3',
-                'insert into `upsert_tests` (`email`, `name`) values (?, ?) on conflict (`email`) do nothing',
+                'insert into `upsert_tests` (`email`, `name`) values (?, ?) on conflict (`email`) do nothing returning `email`',
                 ['ignoretest1@example.com', 'AFTER']
               );
             });
@@ -1444,7 +1444,7 @@ describe('Inserts', function () {
               );
               tester(
                 'sqlite3',
-                'insert into `upsert_tests` (`email`, `name`) values (?, ?) on conflict do nothing',
+                'insert into `upsert_tests` (`email`, `name`) values (?, ?) on conflict do nothing returning `email`',
                 ['ignoretest1@example.com', 'AFTER']
               );
             });
@@ -1512,7 +1512,7 @@ describe('Inserts', function () {
               );
               tester(
                 'sqlite3',
-                'insert into `upsert_composite_key_tests` (`email`, `name`, `org`) values (?, ?, ?) on conflict (`org`, `email`) do nothing',
+                'insert into `upsert_composite_key_tests` (`email`, `name`, `org`) values (?, ?, ?) on conflict (`org`, `email`) do nothing returning `email`',
                 ['ignoretest1@example.com', 'AFTER', 'acme-inc']
               );
             });
@@ -1571,7 +1571,7 @@ describe('Inserts', function () {
               );
               tester(
                 'sqlite3',
-                'insert into `upsert_tests` (`email`, `name`) values (?, ?) on conflict (`email`) do update set `email` = excluded.`email`, `name` = excluded.`name`',
+                'insert into `upsert_tests` (`email`, `name`) values (?, ?) on conflict (`email`) do update set `email` = excluded.`email`, `name` = excluded.`name` returning `email`',
                 ['mergetest1@example.com', 'AFTER']
               );
             });
@@ -1628,7 +1628,7 @@ describe('Inserts', function () {
               );
               tester(
                 'sqlite3',
-                'insert into `upsert_tests` (`email`, `name`) values (?, ?) on conflict (`email`) do update set `email` = excluded.`email`, `name` = excluded.`name` where `upsert_tests`.`role` = ?',
+                'insert into `upsert_tests` (`email`, `name`) values (?, ?) on conflict (`email`) do update set `email` = excluded.`email`, `name` = excluded.`name` where `upsert_tests`.`role` = ? returning `email`',
                 ['mergetest1@example.com', 'AFTER', 'tester']
               );
             });
@@ -1694,7 +1694,7 @@ describe('Inserts', function () {
               );
               tester(
                 'sqlite3',
-                'insert into `upsert_tests` (`email`, `name`) values (?, ?) on conflict (`email`) do update set `email` = excluded.`email`, `name` = excluded.`name` where `upsert_tests`.`role` = ?',
+                'insert into `upsert_tests` (`email`, `name`) values (?, ?) on conflict (`email`) do update set `email` = excluded.`email`, `name` = excluded.`name` where `upsert_tests`.`role` = ? returning `email`',
                 ['mergetest1@example.com', 'AFTER', 'fake-role']
               );
             });
@@ -1770,7 +1770,7 @@ describe('Inserts', function () {
               );
               tester(
                 'sqlite3',
-                "insert into `upsert_tests` (`email`, `name`) values (?, (SELECT name FROM (SELECT * FROM upsert_tests) AS t WHERE email = 'mergesource@example.com')) on conflict (`email`) do update set `email` = excluded.`email`, `name` = excluded.`name`",
+                "insert into `upsert_tests` (`email`, `name`) values (?, (SELECT name FROM (SELECT * FROM upsert_tests) AS t WHERE email = 'mergesource@example.com')) on conflict (`email`) do update set `email` = excluded.`email`, `name` = excluded.`name` returning `email`",
                 ['mergedest@example.com']
               );
             });
@@ -1838,7 +1838,7 @@ describe('Inserts', function () {
               );
               tester(
                 'sqlite3',
-                'insert into `upsert_tests` (`email`, `name`) values (?, ?) on conflict (`email`) do update set `name` = (SELECT name FROM upsert_value_source)',
+                'insert into `upsert_tests` (`email`, `name`) values (?, ?) on conflict (`email`) do update set `name` = (SELECT name FROM upsert_value_source) returning `email`',
                 ['mergedest@example.com', 'SHOULD NOT BE USED']
               );
             });
@@ -1906,7 +1906,7 @@ describe('Inserts', function () {
               );
               tester(
                 'sqlite3',
-                'insert into `upsert_tests` (`email`, `name`) values (?, ?) on conflict (`email`) do update set `name` = excluded.`name`',
+                'insert into `upsert_tests` (`email`, `name`) values (?, ?) on conflict (`email`) do update set `name` = excluded.`name` returning `email`',
                 ['mergedest@example.com', 'SHOULD BE USED']
               );
             });
@@ -1971,7 +1971,7 @@ describe('Inserts', function () {
               );
               tester(
                 'sqlite3',
-                'insert into `upsert_tests` (`email`, `name`) select ? as `email`, ? as `name` union all select ? as `email`, ? as `name` where true on conflict (`email`) do update set `email` = excluded.`email`, `name` = excluded.`name`',
+                'insert into `upsert_tests` (`email`, `name`) select ? as `email`, ? as `name` union all select ? as `email`, ? as `name` where true on conflict (`email`) do update set `email` = excluded.`email`, `name` = excluded.`name` returning `email`',
                 ['two@example.com', 'AFTER', 'three@example.com', 'AFTER']
               );
             });
diff --git a/test/integration2/query/misc/additional.spec.js b/test/integration2/query/misc/additional.spec.js
index 6ff33337..2bb9e6ab 100644
--- a/test/integration2/query/misc/additional.spec.js
+++ b/test/integration2/query/misc/additional.spec.js
@@ -20,6 +20,7 @@ const {
   isPgBased,
   isPgNative,
   isCockroachDB,
+  isBetterSQLite3,
 } = require('../../../util/db-helpers');
 const { DRIVER_NAMES: drivers } = require('../../../util/constants');
 const {
@@ -53,11 +54,6 @@ describe('Additional', function () {
         await createTestTableTwo(knex);
       });
 
-      beforeEach(async () => {
-        await knex('accounts').truncate();
-        await insertAccounts(knex);
-      });
-
       after(async () => {
         await knex.destroy();
       });
@@ -148,16 +144,23 @@ describe('Additional', function () {
         });
 
         it('should process response done through a stream', (done) => {
-          let response;
-          const stream = knex('accounts').limit(1).stream();
+          knex('accounts')
+            .truncate()
+            .then(() => {
+              return insertAccounts(knex, 'accounts');
+            })
+            .then(() => {
+              let response;
+              const stream = knex('accounts').limit(1).stream();
 
-          stream.on('data', (res) => {
-            response = res;
-          });
-          stream.on('finish', () => {
-            expect(response.callCount).to.equal(1);
-            done();
-          });
+              stream.on('data', (res) => {
+                response = res;
+              });
+              stream.on('finish', () => {
+                expect(response.callCount).to.equal(1);
+                done();
+              });
+            });
         });
 
         it('should pass query context for responses through a stream', (done) => {
@@ -234,9 +237,6 @@ describe('Additional', function () {
 
       describe('returning with wrapIdentifier and postProcessResponse` (TODO: fix to work on all possible dialects)', function () {
         const origHooks = {};
-        if (!isPostgreSQL(knex) || !isMssql(knex)) {
-          return;
-        }
 
         before('setup custom hooks', () => {
           origHooks.postProcessResponse =
@@ -273,15 +273,27 @@ describe('Additional', function () {
         });
 
         it('should return the correct column when a single property is given to returning', () => {
+          if (!isPostgreSQL(knex) && !isMssql(knex) && !isBetterSQLite3(knex)) {
+            return;
+          }
+
           return knex('accounts_foo')
             .insert({ balance_foo: 123 })
             .returning('balance_foo')
             .then((res) => {
-              expect(res).to.eql([123]);
+              expect(res).to.eql([
+                {
+                  balance_foo: 123,
+                },
+              ]);
             });
         });
 
         it('should return the correct columns when multiple properties are given to returning', () => {
+          if (!isPostgreSQL(knex) && !isMssql(knex) && !isBetterSQLite3(knex)) {
+            return;
+          }
+
           return knex('accounts_foo')
             .insert({ balance_foo: 123, email_foo: 'foo@bar.com' })
             .returning(['balance_foo', 'email_foo'])
diff --git a/test/integration2/schema/alter.spec.js b/test/integration2/schema/alter.spec.js
index 0df81922..6210f56a 100644
--- a/test/integration2/schema/alter.spec.js
+++ b/test/integration2/schema/alter.spec.js
@@ -179,9 +179,9 @@ describe('Schema', () => {
 
               expect(queries.sql).to.deep.equal([
                 "CREATE TABLE `_knex_temp_alter111` (`column_integer` varchar(255), `column_string` varchar(255), `column_datetime` datetime, `column_defaultTo` integer DEFAULT '0', `column_notNullable` varchar(255) NOT NULL, `column_defaultToAndNotNullable` datetime NOT NULL DEFAULT '0', `column_nullable` boolean NULL)",
-                'INSERT INTO _knex_temp_alter111 SELECT * FROM alter_table;',
-                "DROP TABLE 'alter_table'",
-                "ALTER TABLE '_knex_temp_alter111' RENAME TO 'alter_table'",
+                'INSERT INTO "_knex_temp_alter111" SELECT * FROM "alter_table";',
+                'DROP TABLE "alter_table"',
+                'ALTER TABLE "_knex_temp_alter111" RENAME TO "alter_table"',
               ]);
             });
           });
diff --git a/test/integration2/schema/checks.spec.js b/test/integration2/schema/checks.spec.js
new file mode 100644
index 00000000..9bef0386
--- /dev/null
+++ b/test/integration2/schema/checks.spec.js
@@ -0,0 +1,450 @@
+'use strict';
+
+const { expect } = require('chai');
+
+require('lodash');
+
+const { isSQLite, isMssql } = require('../../util/db-helpers');
+const { getAllDbs, getKnexForDb } = require('../util/knex-instance-provider');
+const logger = require('../../integration/logger');
+
+describe('Checks', () => {
+  getAllDbs().forEach((db) => {
+    describe(db, () => {
+      let knex;
+
+      before(async () => {
+        knex = logger(getKnexForDb(db));
+      });
+
+      after(async () => {
+        return knex.destroy();
+      });
+
+      /**
+       * Perform a check constraint with two tests : test the check constraint don't trigger on valid insert and
+       * test the constraint trigger on invalid insert.
+       *
+       * @param validInsert the valid insert object.
+       * @param invalidInsert the valid insert object.
+       * @returns {Promise<void>}
+       */
+      async function checkTest(validInsert, invalidInsert) {
+        try {
+          await knex('check_test').insert([validInsert]);
+        } catch (err) {
+          expect(
+            err,
+            `valid insert ${JSON.stringify(
+              validInsert
+            )} thrown error (${err.toString()}) instead of pass`
+          ).to.undefined;
+        }
+
+        let res;
+        try {
+          res = await knex('check_test').insert([invalidInsert]);
+        } catch (err) {
+          expect(err).to.not.undefined;
+        }
+        expect(
+          res,
+          `invalid insert ${JSON.stringify(invalidInsert)} pass instead of fail`
+        ).to.undefined;
+      }
+
+      it('create table with raw check on table', async () => {
+        await knex.schema.dropTableIfExists('check_test');
+        await knex.schema
+          .createTable('check_test', function (table) {
+            table.string('col1');
+            table.string('col2');
+            table.check('?? = ??', ['col1', 'col2']);
+          })
+          .testSql((tester) => {
+            tester(
+              ['pg', 'pg-redshift', 'cockroachdb'],
+              [
+                'create table "check_test" ("col1" varchar(255), "col2" varchar(255), check ("col1" = "col2"))',
+              ]
+            );
+            tester(
+              ['oracledb'],
+              [
+                'create table "check_test" ("name" varchar2(255) check ("name" LIKE \'%val%\'))',
+              ]
+            );
+            tester('mysql', [
+              'create table `check_test` (`col1` varchar(255), `col2` varchar(255), check (`col1` = `col2`)) default character set utf8',
+            ]);
+            tester('sqlite3', [
+              'create table `check_test` (`col1` varchar(255), `col2` varchar(255), check (`col1` = `col2`))',
+            ]);
+            tester('mssql', [
+              'CREATE TABLE [check_test] ([col1] nvarchar(255), [col2] nvarchar(255), check ([col1] = [col2]))',
+            ]);
+          });
+
+        await checkTest(
+          { col1: 'test', col2: 'test' },
+          { col1: 'test', col2: 'test2' }
+        );
+      });
+
+      it('create table with numeric positive check', async () => {
+        await knex.schema.dropTableIfExists('check_test');
+        await knex.schema
+          .createTable('check_test', function (table) {
+            table.integer('price').checkPositive();
+          })
+          .testSql((tester) => {
+            tester(
+              ['pg', 'pg-redshift', 'cockroachdb', 'oracledb'],
+              [
+                'create table "check_test" ("price" integer check ("price" > 0))',
+              ]
+            );
+            tester('mysql', [
+              'create table `check_test` (`price` int check (`price` > 0)) default character set utf8',
+            ]);
+            tester('sqlite3', [
+              'create table `check_test` (`price` integer check (`price` > 0))',
+            ]);
+            tester('mssql', [
+              'CREATE TABLE [check_test] ([price] int check ([price] > 0))',
+            ]);
+          });
+
+        await checkTest({ price: 10 }, { price: -5 });
+      });
+
+      it('create table with numeric negative check', async () => {
+        await knex.schema.dropTableIfExists('check_test');
+        await knex.schema
+          .createTable('check_test', function (table) {
+            table.integer('price').checkNegative();
+          })
+          .testSql((tester) => {
+            tester(
+              ['pg', 'pg-redshift', 'cockroachdb', 'oracledb'],
+              [
+                'create table "check_test" ("price" integer check ("price" < 0))',
+              ]
+            );
+            tester('mysql', [
+              'create table `check_test` (`price` int check (`price` < 0)) default character set utf8',
+            ]);
+            tester('sqlite3', [
+              'create table `check_test` (`price` integer check (`price` < 0))',
+            ]);
+            tester('mssql', [
+              'CREATE TABLE [check_test] ([price] int check ([price] < 0))',
+            ]);
+          });
+
+        await checkTest({ price: -5 }, { price: 10 });
+      });
+
+      it('create table with check in', async () => {
+        await knex.schema.dropTableIfExists('check_test');
+        await knex.schema
+          .createTable('check_test', function (table) {
+            table.string('animal').checkIn(['dog', 'cat']);
+          })
+          .testSql((tester) => {
+            tester(
+              ['pg', 'pg-redshift', 'cockroachdb'],
+              [
+                'create table "check_test" ("animal" varchar(255) check ("animal" in (\'dog\',\'cat\')))',
+              ]
+            );
+            tester('oracledb', [
+              'create table "check_test" ("animal" varchar2(255) check ("animal" in (\'dog\', \'cat\')))',
+            ]);
+            tester('mysql', [
+              "create table `check_test` (`animal` varchar(255) check (`animal` in ('dog','cat'))) default character set utf8",
+            ]);
+            tester('sqlite3', [
+              "create table `check_test` (`animal` varchar(255) check (`animal` in ('dog','cat')))",
+            ]);
+            tester('mssql', [
+              "CREATE TABLE [check_test] ([animal] nvarchar(255) check ([animal] in ('dog','cat')))",
+            ]);
+          });
+
+        await checkTest({ animal: 'dog' }, { animal: 'pig' });
+        await checkTest({ animal: 'cat' }, { animal: 'pig' });
+      });
+
+      it('create table with check not in', async () => {
+        await knex.schema.dropTableIfExists('check_test');
+        await knex.schema
+          .createTable('check_test', function (table) {
+            table.string('animal').checkNotIn(['dog', 'cat']);
+          })
+          .testSql((tester) => {
+            tester(
+              ['pg', 'pg-redshift', 'cockroachdb'],
+              [
+                'create table "check_test" ("animal" varchar(255) check ("animal" not in (\'dog\',\'cat\')))',
+              ]
+            );
+            tester('oracledb', [
+              'create table "check_test" ("animal" varchar2(255) check ("animal" not in (\'dog\',\'cat\')))',
+            ]);
+            tester('mysql', [
+              "create table `check_test` (`animal` varchar(255) check (`animal` not in ('dog','cat'))) default character set utf8",
+            ]);
+            tester('sqlite3', [
+              "create table `check_test` (`animal` varchar(255) check (`animal` not in ('dog','cat')))",
+            ]);
+            tester('mssql', [
+              "CREATE TABLE [check_test] ([animal] nvarchar(255) check ([animal] not in ('dog','cat')))",
+            ]);
+          });
+
+        await checkTest({ animal: 'pg' }, { animal: 'cat' });
+        await checkTest({ animal: 'mammoth' }, { animal: 'cat' });
+      });
+
+      it('create table with check between', async () => {
+        await knex.schema.dropTableIfExists('check_test');
+        await knex.schema
+          .createTable('check_test', function (table) {
+            table.integer('price').checkBetween([10, 20]);
+          })
+          .testSql((tester) => {
+            tester(
+              ['pg', 'pg-redshift', 'cockroachdb', 'oracledb'],
+              [
+                'create table "check_test" ("price" integer check ("price" between 10 and 20))',
+              ]
+            );
+            tester('mysql', [
+              'create table `check_test` (`price` int check (`price` between 10 and 20)) default character set utf8',
+            ]);
+            tester('sqlite3', [
+              'create table `check_test` (`price` integer check (`price` between 10 and 20))',
+            ]);
+            tester('mssql', [
+              'CREATE TABLE [check_test] ([price] int check ([price] between 10 and 20))',
+            ]);
+          });
+
+        await checkTest({ price: 10 }, { price: 25 });
+      });
+
+      it('create table with check between with multiple intervals', async () => {
+        await knex.schema.dropTableIfExists('check_test');
+        await knex.schema
+          .createTable('check_test', function (table) {
+            table.integer('price').checkBetween([
+              [10, 20],
+              [30, 40],
+            ]);
+          })
+          .testSql((tester) => {
+            tester(
+              ['pg', 'pg-redshift', 'cockroachdb', 'oracledb'],
+              [
+                'create table "check_test" ("price" integer check ("price" between 10 and 20 or "price" between 30 and 40))',
+              ]
+            );
+            tester('mysql', [
+              'create table `check_test` (`price` int check (`price` between 10 and 20 or `price` between 30 and 40)) default character set utf8',
+            ]);
+            tester('sqlite3', [
+              'create table `check_test` (`price` integer check (`price` between 10 and 20 or `price` between 30 and 40))',
+            ]);
+            tester('mssql', [
+              'CREATE TABLE [check_test] ([price] int check ([price] between 10 and 20 or [price] between 30 and 40))',
+            ]);
+          });
+
+        await checkTest({ price: 15 }, { price: 25 });
+        await checkTest({ price: 35 }, { price: 45 });
+      });
+
+      it('create table with check length', async () => {
+        await knex.schema.dropTableIfExists('check_test');
+        await knex.schema
+          .createTable('check_test', function (table) {
+            table.string('year').checkLength('=', 4);
+          })
+          .testSql((tester) => {
+            tester(
+              ['pg', 'pg-redshift', 'cockroachdb'],
+              [
+                'create table "check_test" ("year" varchar(255) check (length("year") = 4))',
+              ]
+            );
+            tester('oracledb', [
+              'create table "check_test" ("year" varchar2(255) check (length("year") = 4))',
+            ]);
+            tester('mysql', [
+              'create table `check_test` (`year` varchar(255) check (length(`year`) = 4)) default character set utf8',
+            ]);
+            tester('sqlite3', [
+              'create table `check_test` (`year` varchar(255) check (length(`year`) = 4))',
+            ]);
+            tester('mssql', [
+              'CREATE TABLE [check_test] ([year] nvarchar(255) check (LEN([year]) = 4))',
+            ]);
+          });
+
+        await checkTest({ year: '2021' }, { year: '21' });
+      });
+
+      it('create table with check regex', async function () {
+        if (isMssql(knex) || isSQLite(knex)) {
+          this.skip();
+        }
+        await knex.schema.dropTableIfExists('check_test');
+        await knex.schema
+          .createTable('check_test', function (table) {
+            table.string('date').checkRegex('[0-9]{2}-[0-9]{2}-[0-9]{4}');
+          })
+          .testSql((tester) => {
+            tester(
+              ['pg', 'pg-redshift', 'cockroachdb'],
+              [
+                'create table "check_test" ("date" varchar(255) check ("date" ~ \'[0-9]{2}-[0-9]{2}-[0-9]{4}\'))',
+              ]
+            );
+            tester('oracledb', [
+              'create table "check_test" ("date" varchar2(255) check (REGEXP_LIKE("date",\'[0-9]{2}-[0-9]{2}-[0-9]{4}\')))',
+            ]);
+            tester('mysql', [
+              "create table `check_test` (`date` varchar(255) check (`date` REGEXP '[0-9]{2}-[0-9]{2}-[0-9]{4}')) default character set utf8",
+            ]);
+          });
+
+        await checkTest({ date: '01-02-2021' }, { date: '01/02/2021' });
+        await checkTest({ date: '01-02-2021' }, { date: '01-02-221' });
+      });
+
+      it('drop checks', async function () {
+        if (isSQLite(knex)) {
+          this.skip();
+        }
+        await knex.schema.dropTableIfExists('check_test');
+        await knex.schema.createTable('check_test', function (table) {
+          table.integer('price').checkPositive('price_pos_check');
+        });
+        await checkTest({ price: 10 }, { price: -5 });
+        await knex.schema
+          .table('check_test', function (table) {
+            table.dropChecks('price_pos_check');
+          })
+          .testSql((tester) => {
+            tester(
+              ['pg', 'pg-redshift', 'cockroachdb', 'oracledb'],
+              ['alter table "check_test" drop constraint price_pos_check']
+            );
+            tester('mysql', [
+              'alter table `check_test` drop constraint price_pos_check',
+            ]);
+          });
+        // Now, insert negative value work.
+        expect(await knex('check_test').insert([{ price: -5 }])).to.not.throw;
+      });
+
+      it('create table with custom check', async function () {
+        await knex.schema.dropTableIfExists('check_test');
+        await knex.schema
+          .createTable('check_test', (table) => {
+            table.integer('price_min');
+            table.integer('price_max');
+            table
+              .check(
+                '?? < ??',
+                ['price_min', 'price_max'],
+                'price_min_lower_max'
+              )
+              .check('?? > 5', ['price_min']);
+          })
+          .testSql((tester) => {
+            tester(
+              ['pg', 'pg-redshift', 'cockroachdb'],
+              [
+                'create table "check_test" ("price_min" integer, "price_max" integer, constraint price_min_lower_max check ("price_min" < "price_max"), check ("price_min" > 5))',
+              ]
+            );
+            tester('oracledb', [
+              'create table "check_test" ("price_min" integer, "price_max" integer, constraint price_min_lower_max check ("price_min" < "price_max"), check ("price_min" > 5))',
+            ]);
+            tester('mysql', [
+              'create table `check_test` (`price_min` int, `price_max` int, constraint price_min_lower_max check (`price_min` < `price_max`), check (`price_min` > 5)) default character set utf8',
+            ]);
+            tester('mssql', [
+              'CREATE TABLE [check_test] ([price_min] int, [price_max] int, constraint price_min_lower_max check ([price_min] < [price_max]), check ([price_min] > 5))',
+            ]);
+          });
+
+        await checkTest(
+          { price_min: 10, price_max: 20 },
+          { price_min: 10, price_max: 5 }
+        );
+        await checkTest(
+          { price_min: 10, price_max: 20 },
+          { price_min: 0, price_max: 5 }
+        );
+      });
+
+      it('create table with checks then alter', async function () {
+        if (isSQLite(knex)) {
+          this.skip();
+        }
+        await knex.schema.dropTableIfExists('check_test');
+        await knex.schema.createTable('check_test', (table) => {
+          table.integer('price');
+        });
+        expect(await knex('check_test').insert([{ price: -5 }])).to.not.throw;
+        // Alter table with check constraint fail, we have row that violated the constraint
+        let error;
+        try {
+          await knex.schema.table('check_test', (table) => {
+            table.integer('price').checkPositive().alter();
+          });
+        } catch (e) {
+          error = e;
+        }
+        expect(error.message).to.not.undefined;
+
+        // empty the table to add the constraint
+        await knex('check_test').truncate();
+        await knex.schema
+          .table('check_test', (table) => {
+            table.integer('price').checkPositive().alter();
+          })
+          .testSql((tester) => {
+            tester(
+              ['pg', 'pg-redshift'],
+              [
+                'alter table "check_test" alter column "price" drop default',
+                'alter table "check_test" alter column "price" drop not null',
+                'alter table "check_test" alter column "price" type integer using ("price"::integer)',
+                'alter table "check_test" add constraint check_test_price_1 check("price" > 0)',
+              ]
+            );
+            tester('cockroachdb', [
+              'SET enable_experimental_alter_column_type_general = true',
+              'alter table "check_test" alter column "price" drop default',
+              'alter table "check_test" alter column "price" drop not null',
+              'alter table "check_test" alter column "price" type integer using ("price"::integer)',
+              'alter table "check_test" add constraint check_test_price_1 check("price" > 0)',
+            ]);
+            tester('oracledb', [
+              'alter table "check_test" modify "price" integer',
+              'alter table "check_test" add constraint check_test_price_1 check("price" > 0)',
+            ]);
+            tester('mysql', [
+              'alter table `check_test` modify `price` int',
+              'alter table `check_test` add constraint check_test_price_1 check(`price` > 0)',
+            ]);
+          });
+        await checkTest({ price: 10 }, { price: -10 });
+      });
+    });
+  });
+});
diff --git a/test/integration2/schema/foreign-keys.spec.js b/test/integration2/schema/foreign-keys.spec.js
index b77ecaff..ddaf5d94 100644
--- a/test/integration2/schema/foreign-keys.spec.js
+++ b/test/integration2/schema/foreign-keys.spec.js
@@ -76,9 +76,9 @@ describe('Schema', () => {
             if (isSQLite(knex)) {
               expect(queries.sql).to.eql([
                 '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'",
+                '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"',
               ]);
             }
 
@@ -112,9 +112,9 @@ describe('Schema', () => {
 
             expect(queries.sql).to.eql([
               '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'",
+              '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"',
             ]);
           });
 
@@ -138,9 +138,9 @@ describe('Schema', () => {
 
             expect(queries.sql).to.eql([
               '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'",
+              '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/misc.spec.js b/test/integration2/schema/misc.spec.js
index c4e6e9f4..e29791d3 100644
--- a/test/integration2/schema/misc.spec.js
+++ b/test/integration2/schema/misc.spec.js
@@ -381,10 +381,6 @@ describe('Schema (misc)', () => {
         });
 
         describe('increments types - postgres', () => {
-          if (!isPgBased(knex)) {
-            return Promise.resolve();
-          }
-
           before(async () => {
             await knex.schema.createTable(
               'increments_columns_1_test',
@@ -405,7 +401,11 @@ describe('Schema (misc)', () => {
             await knex.schema.dropTable('increments_columns_2_test');
           });
 
-          it('#2210 - creates an incrementing column with a comment', () => {
+          it('#2210 - creates an incrementing column with a comment', function () {
+            if (!isPgBased(knex)) {
+              return this.skip();
+            }
+
             const table_name = 'increments_columns_1_test';
             const expected_column = 'id';
             const expected_comment = 'comment_1';
@@ -441,7 +441,11 @@ describe('Schema (misc)', () => {
               });
           });
 
-          it('#2210 - creates an incrementing column with a specified name and comment', () => {
+          it('#2210 - creates an incrementing column with a specified name and comment', function () {
+            if (!isPgBased(knex)) {
+              return this.skip();
+            }
+
             const table_name = 'increments_columns_2_test';
             const expected_column = 'named_2';
             const expected_comment = 'comment_2';
@@ -479,10 +483,6 @@ describe('Schema (misc)', () => {
         });
 
         describe('increments types - mysql', () => {
-          if (!isMysql(knex)) {
-            return Promise.resolve();
-          }
-
           before(() =>
             Promise.all([
               knex.schema.createTable('increments_columns_1_test', (table) => {
@@ -501,7 +501,11 @@ describe('Schema (misc)', () => {
             ])
           );
 
-          it('#2210 - creates an incrementing column with a comment', () => {
+          it('#2210 - creates an incrementing column with a comment', function () {
+            if (!isMysql(knex)) {
+              return this.skip();
+            }
+
             const table_name = 'increments_columns_1_test';
             const expected_column = 'id';
             const expected_comment = 'comment_1';
@@ -521,7 +525,11 @@ describe('Schema (misc)', () => {
               });
           });
 
-          it('#2210 - creates an incrementing column with a specified name and comment', () => {
+          it('#2210 - creates an incrementing column with a specified name and comment', function () {
+            if (!isMysql(knex)) {
+              return this.skip();
+            }
+
             const table_name = 'increments_columns_2_test';
             const expected_column = 'named_2';
             const expected_comment = 'comment_2';
@@ -543,19 +551,20 @@ describe('Schema (misc)', () => {
         });
 
         describe('enum - postgres', () => {
-          if (!isPgBased(knex)) {
-            return Promise.resolve();
-          }
+          afterEach(async () => {
+            if (isPgBased(knex)) {
+              await knex.schema
+                .dropTableIfExists('native_enum_test')
+                .raw('DROP TYPE IF EXISTS "foo_type"')
+                .raw('DROP SCHEMA IF EXISTS "test" CASCADE')
+          }});
 
-          afterEach(() =>
-            knex.schema
-              .dropTableIfExists('native_enum_test')
-              .raw('DROP TYPE IF EXISTS "foo_type"')
-              .raw('DROP SCHEMA IF EXISTS "test" CASCADE')
-          );
+          it('uses native type with schema', function () {
+            if (!isPgBased(knex)) {
+              return this.skip();
+            }
 
-          it('uses native type with schema', () =>
-            knex.schema.createSchemaIfNotExists('test').then(() => {
+            return knex.schema.createSchemaIfNotExists('test').then(() => {
               return knex.schema
                 .withSchema('test')
                 .createTable('native_enum_test', (table) => {
@@ -577,10 +586,15 @@ describe('Schema (misc)', () => {
                     ]
                   );
                 });
-            }));
+            });
+          });
 
-          it('uses native type when useNative is specified', () =>
-            knex.schema
+          it('uses native type when useNative is specified', function () {
+            if (!isPgBased(knex)) {
+              return this.skip();
+            }
+
+            return knex.schema
               .createTable('native_enum_test', (table) => {
                 table
                   .enum('foo_column', ['a', 'b', 'c'], {
@@ -598,10 +612,14 @@ describe('Schema (misc)', () => {
                     'create table "native_enum_test" ("foo_column" "foo_type" not null, "id" uuid not null)',
                   ]
                 );
-              }));
+              });
+          });
 
-          it('uses an existing native type when useNative and existingType are specified', () =>
-            knex
+          it('uses an existing native type when useNative and existingType are specified', function () {
+            if (!isPgBased(knex)) {
+              return this.skip();
+            }
+            return knex
               .raw("create type \"foo_type\" as enum ('a', 'b', 'c')")
               .then(() => {
                 return knex.schema
@@ -623,7 +641,8 @@ describe('Schema (misc)', () => {
                       ]
                     );
                   });
-              }));
+              });
+          });
         });
 
         it('Callback function must be supplied', () => {
@@ -1576,6 +1595,34 @@ describe('Schema (misc)', () => {
           knex.schema.hasTable('').then((resp) => {
             expect(resp).to.equal(false);
           }));
+
+        describe('sqlite only', () => {
+          it('should not parse table name if wrapIdentifier is not specified', async function () {
+            if (!isSQLite(knex)) {
+              return this.skip();
+            }
+
+            knex.client.config.wrapIdentifier = null;
+
+            const resp = await knex.schema.hasTable('testTableTwo');
+            expect(resp).to.be.false;
+          });
+
+          it('should parse table name if wrapIdentifier is specified', async function () {
+            if (!isSQLite(knex)) {
+              return this.skip();
+            }
+
+            knex.client.config.wrapIdentifier = (
+              value,
+              origImpl,
+              queryContext
+            ) => origImpl(_.snakeCase(value));
+
+            const resp = await knex.schema.hasTable('testTableTwo');
+            expect(resp).to.be.true;
+          });
+        });
       });
 
       describe('renameTable', () => {
@@ -1599,11 +1646,11 @@ describe('Schema (misc)', () => {
             }));
 
           describe('sqlite only', () => {
-            if (!isSQLite(knex)) {
-              return Promise.resolve();
-            }
+            it('checks whether a column exists without being case sensitive, resolving with a boolean', async function () {
+              if (!isSQLite(knex)) {
+                return this.skip();
+              }
 
-            it('checks whether a column exists without being case sensitive, resolving with a boolean', async () => {
               const exists = await knex.schema.hasColumn(
                 'accounts',
                 'FIRST_NAME'
@@ -1616,10 +1663,6 @@ describe('Schema (misc)', () => {
 
         describe('using processorss', () => {
           describe('sqlite and pg only', () => {
-            if (!isSQLite(knex) && !isPgBased(knex)) {
-              return Promise.resolve();
-            }
-
             beforeEach(() => {
               knex.client.config.postProcessResponse = postProcessResponse;
               knex.client.config.wrapIdentifier = wrapIdentifier;
@@ -1630,46 +1673,59 @@ describe('Schema (misc)', () => {
               knex.client.config.wrapIdentifier = null;
             });
 
-            it('checks whether a column exists, resolving with a boolean', () =>
-              knex.schema.hasColumn('accounts', 'firstName').then((exists) => {
-                expect(exists).to.equal(false);
-              }));
+            it('checks whether a column exists, resolving with a boolean', async function () {
+              if (!isSQLite(knex) && !isPgBased(knex)) {
+                return this.skip();
+              }
+
+              const exists = await knex.schema.hasColumn(
+                'accounts',
+                'firstName'
+              );
+              expect(exists).to.equal(false);
+            });
           });
         });
       });
 
       describe('addColumn', () => {
         describe('mysql only', () => {
-          if (!isMysql(knex)) {
-            return Promise.resolve(true);
-          }
-
-          before(() =>
-            knex.schema
-              .createTable('add_column_test_mysql', (tbl) => {
-                tbl.integer('field_foo');
-                tbl.integer('field_bar');
-              })
-              .then(() =>
-                knex.schema.alterTable('add_column_test_mysql', (tbl) => {
-                  tbl.integer('field_foo').comment('foo').alter();
-                  tbl.integer('field_bar').comment('bar').alter();
-                  tbl.integer('field_first').first().comment('First');
-                  tbl
-                    .integer('field_after_foo')
-                    .after('field_foo')
-                    .comment('After');
-                  tbl
-                    .increments('field_nondefault_increments')
-                    .comment('Comment on increment col');
+          before(() => {
+            if (isMysql(knex)) {
+              return knex.schema
+                .createTable('add_column_test_mysql', (tbl) => {
+                  tbl.integer('field_foo');
+                  tbl.integer('field_bar');
                 })
-              )
-          );
+                .then(() =>
+                  knex.schema.alterTable('add_column_test_mysql', (tbl) => {
+                    tbl.integer('field_foo').comment('foo').alter();
+                    tbl.integer('field_bar').comment('bar').alter();
+                    tbl.integer('field_first').first().comment('First');
+                    tbl
+                      .integer('field_after_foo')
+                      .after('field_foo')
+                      .comment('After');
+                    tbl
+                      .increments('field_nondefault_increments')
+                      .comment('Comment on increment col');
+                  })
+                )
+            }
+          });
 
-          after(() => knex.schema.dropTable('add_column_test_mysql'));
+          after(() => {
+            if (isMysql(knex)) {
+              knex.schema.dropTable('add_column_test_mysql')
+            }
+          });
 
-          it('should columns order be correctly with after and first', () =>
-            knex
+          it('should columns order be correctly with after and first', function () {
+            if (!isMysql(knex)) {
+              return this.skip();
+            }
+
+            return knex
               .raw('SHOW CREATE TABLE `add_column_test_mysql`')
               .then((schema) => {
                 // .columnInfo() keys does not guaranteed fields order.
@@ -1699,7 +1755,8 @@ describe('Schema (misc)', () => {
                 expect(comments[2]).to.equal('After');
                 expect(comments[3]).to.equal('bar');
                 expect(comments[4]).to.equal('Comment on increment col');
-              }));
+              });
+          });
         });
       });
 
@@ -2090,10 +2147,10 @@ describe('Schema (misc)', () => {
         });
       });
 
-      it('should warn attempting to create primary from nonexistent columns', () => {
+      it('should warn attempting to create primary from nonexistent columns', function () {
         // Redshift only
         if (!isRedshift(knex)) {
-          return Promise.resolve(true);
+          return this.skip();
         }
         const tableName = 'no_test_column';
         const constraintName = 'testconstraintname';
@@ -2126,9 +2183,9 @@ describe('Schema (misc)', () => {
       });
 
       //Unit tests checks SQL -- This will test running those queries, no hard assertions here.
-      it('#1430 - .primary() & .dropPrimary() same for all dialects', async () => {
+      it('#1430 - .primary() & .dropPrimary() same for all dialects', async function () {
         if (isSQLite(knex)) {
-          return Promise.resolve();
+          return this.skip();
         }
         const constraintName = 'testconstraintname';
         const tableName = 'primarytest';
@@ -2151,9 +2208,6 @@ describe('Schema (misc)', () => {
         describe('sqlite3 only', () => {
           const tableName = 'invalid_field_test_sqlite3';
           const fieldName = 'field_foo';
-          if (!isSQLite(knex)) {
-            return Promise.resolve();
-          }
 
           before(() =>
             knex.schema.createTable(tableName, (tbl) => {
@@ -2163,16 +2217,25 @@ describe('Schema (misc)', () => {
 
           after(() => knex.schema.dropTable(tableName));
 
-          it('should return empty resultset when referencing an existent column', () =>
-            knex(tableName)
+          it('should return empty resultset when referencing an existent column', function () {
+            if (!isSQLite(knex)) {
+              return this.skip();
+            }
+
+            return knex(tableName)
               .select()
               .where(fieldName, 'something')
               .then((rows) => {
                 expect(rows.length).to.equal(0);
-              }));
+              });
+          });
+
+          it('should throw when referencing a non-existent column', function() {
+            if (!isSQLite(knex)) {
+              return this.skip();
+            }
 
-          it('should throw when referencing a non-existent column', () =>
-            knex(tableName)
+            return knex(tableName)
               .select()
               .where(fieldName + 'foo', 'something')
               .then(() => {
@@ -2180,9 +2243,46 @@ describe('Schema (misc)', () => {
               })
               .catch((err) => {
                 expect(err.code).to.equal('SQLITE_ERROR');
-              }));
+              });
+          });
         });
       });
+
+      describe('sqlite ddl', () => {
+        before(async () => {
+          if (!isSQLite(knex)) {
+            return;
+          }
+
+          await knex.schema.createTable('CREATE TABLE', (table) => {
+            table.primary();
+            table.integer('alter_column');
+          });
+
+          await knex('CREATE TABLE').insert({ alter_column: 1 });
+        });
+
+        after(async () => {
+          if (!isSQLite(knex)) {
+            return;
+          }
+
+          await knex.schema.dropTable('CREATE TABLE');
+        });
+
+        it('properly executes any ddl command when the table name is a substring of "CREATE TABLE"', async () => {
+          if (!isSQLite(knex)) {
+            return;
+          }
+
+          await expect(
+            knex.schema.alterTable('CREATE TABLE', (table) => {
+              table.string('alter_column').alter();
+            })
+          ).to.not.be.eventually.rejected;
+        });
+      });
+
       it('supports named primary keys', async () => {
         const constraintName = 'pk-test';
         const tableName = 'namedpk';
diff --git a/test/integration2/schema/primary-keys.spec.js b/test/integration2/schema/primary-keys.spec.js
index fa8d5d45..1de1612b 100644
--- a/test/integration2/schema/primary-keys.spec.js
+++ b/test/integration2/schema/primary-keys.spec.js
@@ -31,7 +31,7 @@ describe('Schema', () => {
         });
 
         afterEach(async () => {
-          await knex.schema.dropTable('primary_table');
+          await knex.schema.dropTableIfExists('primary_table');
         });
 
         describe('createPrimaryKey', () => {
@@ -63,6 +63,103 @@ describe('Schema', () => {
             }
           });
 
+          it('create multiple primary keys with increments on same column', async function () {
+            await knex.schema.dropTableIfExists('table_multiple_keys');
+            await knex.schema.createTable('table_multiple_keys', function (t) {
+              t.primary(['id', 'second_id', 'other_col']);
+              t.string('second_id', 16).notNullable();
+              t.integer('other_col').notNullable();
+              t.increments('id');
+            });
+            await knex('table_multiple_keys').insert([
+              {
+                second_id: 'abc',
+                other_col: 2,
+              },
+              {
+                second_id: 'abc',
+                other_col: 3,
+              },
+            ]);
+            expect(() => {
+              knex('table_multiple_keys').insert([
+                {
+                  id: 1,
+                  second_id: 'abc',
+                  other_col: 2,
+                },
+              ]);
+            }).to.throw;
+            // It's always ok, the primary key is on three columns.
+            await knex('table_multiple_keys').insert([
+              {
+                second_id: 'abc',
+                other_col: 2,
+              },
+              {
+                second_id: 'abc',
+                other_col: 3,
+              },
+            ]);
+            expect(() => {
+              knex('table_multiple_keys').insert([
+                {
+                  id: 4,
+                  second_id: 'abc',
+                  other_col: 3,
+                },
+              ]);
+            }).to.throw;
+          });
+
+          it('create multiple primary keys with increments on other columns', async function () {
+            await knex.schema.dropTableIfExists('table_multiple_keys');
+            await knex.schema.createTable('table_multiple_keys', function (t) {
+              t.primary(['second_id', 'other_col']);
+              t.string('second_id', 16).notNullable();
+              t.integer('other_col').notNullable();
+              t.increments('id');
+            });
+            await knex('table_multiple_keys').insert([
+              {
+                second_id: 'abc',
+                other_col: 2,
+              },
+              {
+                second_id: 'abc',
+                other_col: 3,
+              },
+            ]);
+            expect(() => {
+              knex('table_multiple_keys').insert([
+                {
+                  second_id: 'abc',
+                  other_col: 2,
+                },
+              ]);
+            }).to.throw;
+            // It's always ok, the primary key is on three columns.
+            await knex('table_multiple_keys').insert([
+              {
+                second_id: 'bcd',
+                other_col: 2,
+              },
+              {
+                second_id: 'abc',
+                other_col: 4,
+              },
+            ]);
+            expect(() => {
+              knex('table_multiple_keys').insert([
+                {
+                  id: 4,
+                  second_id: 'abc',
+                  other_col: 3,
+                },
+              ]);
+            }).to.throw;
+          });
+
           it('creates a primary key with a custom constraint name', async function () {
             // CockroachDB 21.1 throws "(72): unimplemented: primary key dropped without subsequent addition of new primary key in same transaction"
             if (isCockroachDB(knex)) {
diff --git a/test/integration2/schema/set-nullable.spec.js b/test/integration2/schema/set-nullable.spec.js
index aa79e617..d73a160b 100644
--- a/test/integration2/schema/set-nullable.spec.js
+++ b/test/integration2/schema/set-nullable.spec.js
@@ -48,9 +48,9 @@ describe('Schema', () => {
             if (isSQLite(knex)) {
               expect(queries.sql).to.eql([
                 'CREATE TABLE `_knex_temp_alter111` (`id_nullable` integer NULL, `id_not_nullable` integer)',
-                'INSERT INTO _knex_temp_alter111 SELECT * FROM primary_table;',
-                "DROP TABLE 'primary_table'",
-                "ALTER TABLE '_knex_temp_alter111' RENAME TO 'primary_table'",
+                'INSERT INTO "_knex_temp_alter111" SELECT * FROM "primary_table";',
+                'DROP TABLE "primary_table"',
+                'ALTER TABLE "_knex_temp_alter111" RENAME TO "primary_table"',
               ]);
             }
 
diff --git a/test/integration2/schema/views.spec.js b/test/integration2/schema/views.spec.js
index ea6305b1..f4e258de 100644
--- a/test/integration2/schema/views.spec.js
+++ b/test/integration2/schema/views.spec.js
@@ -122,6 +122,130 @@ describe('Views', () => {
             });
         });
 
+        it('create or replace view', async () => {
+          // We create the view and test if all is ok
+          await knex.schema.createView('view_test', (view) => {
+            view.as(knex('table_view').select('a', 'b'));
+          });
+          await knex
+            .select(['a', 'b'])
+            .from('view_test')
+            .then(function (results) {
+              expect(results.length).to.equal(3);
+              expect(results[0].a).to.be.equal('test');
+              expect(results[1].a).to.be.equal('test2');
+              expect(results[2].a).to.be.equal('test3');
+              assertNumber(knex, results[0].b, 5);
+              assertNumber(knex, results[1].b, 12);
+              assertNumber(knex, results[2].b, 45);
+            });
+          // Now we test that the new view is replaced
+          await knex.schema
+            .createViewOrReplace('view_test', function (view) {
+              view.columns(['a', 'b']);
+              view.as(
+                knex('table_view').select('a', 'b').where('b', '>', '10')
+              );
+            })
+            .testSql((tester) => {
+              tester(
+                ['pg', 'pg-redshift', 'cockroachdb', 'oracledb'],
+                [
+                  'create or replace view "view_test" ("a", "b") as select "a", "b" from "table_view" where "b" > \'10\'',
+                ]
+              );
+              tester(
+                ['mysql'],
+                [
+                  "create or replace view `view_test` (`a`, `b`) as select `a`, `b` from `table_view` where `b` > '10'",
+                ]
+              );
+              tester(
+                ['sqlite3'],
+                [
+                  'drop view if exists `view_test`',
+                  "create view `view_test` (`a`, `b`) as select `a`, `b` from `table_view` where `b` > '10'",
+                ]
+              );
+              tester('mssql', [
+                "CREATE OR ALTER VIEW [view_test] ([a], [b]) AS select [a], [b] from [table_view] where [b] > '10'",
+              ]);
+            });
+
+          // We test if the select on the view works and if results are good
+          await knex
+            .select(['a', 'b'])
+            .from('view_test')
+            .then(function (results) {
+              expect(results.length).to.equal(2);
+              assertNumber(knex, results[0].b, 12);
+              assertNumber(knex, results[1].b, 45);
+              expect(results[0].a).to.be.equal('test2');
+              expect(results[1].a).to.be.equal('test3');
+            });
+        });
+
+        it('create or replace view without columns', async () => {
+          // We create the view and test if all is ok
+          await knex.schema.createView('view_test', (view) => {
+            view.as(knex('table_view').select('a', 'b'));
+          });
+          await knex
+            .select(['a', 'b'])
+            .from('view_test')
+            .then(function (results) {
+              expect(results.length).to.equal(3);
+              expect(results[0].a).to.be.equal('test');
+              expect(results[1].a).to.be.equal('test2');
+              expect(results[2].a).to.be.equal('test3');
+              assertNumber(knex, results[0].b, 5);
+              assertNumber(knex, results[1].b, 12);
+              assertNumber(knex, results[2].b, 45);
+            });
+          // Now we test that the new view is replaced
+          await knex.schema
+            .createViewOrReplace('view_test', function (view) {
+              view.as(
+                knex('table_view').select('a', 'b').where('b', '>', '10')
+              );
+            })
+            .testSql((tester) => {
+              tester(
+                ['pg', 'pg-redshift', 'cockroachdb', 'oracledb'],
+                [
+                  'create or replace view "view_test" as select "a", "b" from "table_view" where "b" > \'10\'',
+                ]
+              );
+              tester(
+                ['mysql'],
+                [
+                  "create or replace view `view_test` as select `a`, `b` from `table_view` where `b` > '10'",
+                ]
+              );
+              tester(
+                ['sqlite3'],
+                [
+                  'drop view if exists `view_test`',
+                  "create view `view_test` as select `a`, `b` from `table_view` where `b` > '10'",
+                ]
+              );
+              tester('mssql', [
+                "CREATE OR ALTER VIEW [view_test] AS select [a], [b] from [table_view] where [b] > '10'",
+              ]);
+            });
+
+          // We test if the select on the view works and if results are good
+          await knex
+            .select(['a', 'b'])
+            .from('view_test')
+            .then(function (results) {
+              assertNumber(knex, results[0].b, 12);
+              assertNumber(knex, results[1].b, 45);
+              expect(results[0].a).to.be.equal('test2');
+              expect(results[1].a).to.be.equal('test3');
+            });
+        });
+
         it('create materialized view', async function () {
           if (isMssql(knex) || isSQLite(knex) || isMysql(knex)) {
             return this.skip();
diff --git a/test/unit/query/builder.js b/test/unit/query/builder.js
index 17c24c78..511b7841 100644
--- a/test/unit/query/builder.js
+++ b/test/unit/query/builder.js
@@ -208,7 +208,7 @@ describe('Custom identifier wrapping', () => {
           bindings: ['foo', 'taylor', 'bar', 'dayle'],
         },
         sqlite3: {
-          sql: 'insert into `users_wrapper_was_here` (`email_wrapper_was_here`, `name_wrapper_was_here`) select ? as `email_wrapper_was_here`, ? as `name_wrapper_was_here` union all select ? as `email_wrapper_was_here`, ? as `name_wrapper_was_here`',
+          sql: 'insert into `users_wrapper_was_here` (`email_wrapper_was_here`, `name_wrapper_was_here`) select ? as `email_wrapper_was_here`, ? as `name_wrapper_was_here` union all select ? as `email_wrapper_was_here`, ? as `name_wrapper_was_here` returning `id_wrapper_was_here`',
         },
         pg: {
           sql: 'insert into "users_wrapper_was_here" ("email_wrapper_was_here", "name_wrapper_was_here") values (?, ?), (?, ?) returning "id_wrapper_was_here"',
@@ -260,7 +260,7 @@ describe('Custom identifier wrapping', () => {
           bindings: ['foo', 'taylor', 'bar', 'dayle'],
         },
         sqlite3: {
-          sql: 'insert into `users_wrapper_was_here` (`email_wrapper_was_here`, `name_wrapper_was_here`) select ? as `email_wrapper_was_here`, ? as `name_wrapper_was_here` union all select ? as `email_wrapper_was_here`, ? as `name_wrapper_was_here`',
+          sql: 'insert into `users_wrapper_was_here` (`email_wrapper_was_here`, `name_wrapper_was_here`) select ? as `email_wrapper_was_here`, ? as `name_wrapper_was_here` union all select ? as `email_wrapper_was_here`, ? as `name_wrapper_was_here` returning `id_wrapper_was_here`, `name_wrapper_was_here`',
           bindings: ['foo', 'taylor', 'bar', 'dayle'],
         },
         pg: {
@@ -5422,7 +5422,7 @@ describe('QueryBuilder', () => {
           bindings: ['foo', 'taylor', 'bar', 'dayle'],
         },
         sqlite3: {
-          sql: 'insert into `users` (`email`, `name`) select ? as `email`, ? as `name` union all select ? as `email`, ? as `name`',
+          sql: 'insert into `users` (`email`, `name`) select ? as `email`, ? as `name` union all select ? as `email`, ? as `name` returning `id`',
         },
         pg: {
           sql: 'insert into "users" ("email", "name") values (?, ?), (?, ?) returning "id"',
@@ -5473,7 +5473,7 @@ describe('QueryBuilder', () => {
           bindings: ['foo', 'taylor', 'bar', 'dayle'],
         },
         sqlite3: {
-          sql: 'insert into `users` (`email`, `name`) select ? as `email`, ? as `name` union all select ? as `email`, ? as `name`',
+          sql: 'insert into `users` (`email`, `name`) select ? as `email`, ? as `name` union all select ? as `email`, ? as `name` returning `id`, `name`',
           bindings: ['foo', 'taylor', 'bar', 'dayle'],
         },
         pg: {
@@ -9985,40 +9985,6 @@ describe('QueryBuilder', () => {
     }).to.throw(Error);
   });
 
-  it('should warn to user when use `.returning()` function in SQLite3', () => {
-    const loggerConfigForTestingWarnings = {
-      log: {
-        warn: (message) => {
-          if (
-            message ===
-            '.returning() is not supported by sqlite3 and will not have any effect.'
-          ) {
-            throw new Error(message);
-          }
-        },
-      },
-    };
-
-    const sqlite3ClientForWarnings = new SQLite3_Client(
-      Object.assign({ client: 'sqlite3' }, loggerConfigForTestingWarnings)
-    );
-
-    expect(() => {
-      testsql(
-        qb().into('users').insert({ email: 'foo' }).returning('id'),
-        {
-          sqlite3: {
-            sql: 'insert into `users` (`email`) values (?)',
-            bindings: ['foo'],
-          },
-        },
-        {
-          sqlite3: sqlite3ClientForWarnings,
-        }
-      );
-    }).to.throw(Error);
-  });
-
   it('join with subquery using .withSchema', () => {
     testsql(
       qb()
diff --git a/test/unit/schema-builder/mssql.js b/test/unit/schema-builder/mssql.js
index b635bd1c..88c2abbe 100644
--- a/test/unit/schema-builder/mssql.js
+++ b/test/unit/schema-builder/mssql.js
@@ -118,6 +118,19 @@ describe('MSSQL SchemaBuilder', function () {
       );
     });
 
+    it('create view or replace without columns', async function () {
+      const viewSql = client
+        .schemaBuilder()
+        .createViewOrReplace('adults', function (view) {
+          view.as(knexMssql('users').select('name').where('age', '>', '18'));
+        })
+        .toSQL();
+      equal(1, viewSql.length);
+      expect(viewSql[0].sql).to.equal(
+        "CREATE OR ALTER VIEW [adults] AS select [name] from [users] where [age] > '18'"
+      );
+    });
+
     it('create view with check options', async function () {
       expect(() => {
         client
@@ -1357,5 +1370,131 @@ describe('MSSQL SchemaBuilder', function () {
       expect(spy.secondCall.args).to.deep.equal(['email', 'email context']);
       expect(spy.thirdCall.args).to.deep.equal(['users', 'table context']);
     });
+
+    describe('Checks tests', function () {
+      it('allows adding checks positive', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            t.integer('price').checkPositive();
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          'ALTER TABLE [user] ADD [price] int check ([price] > 0)'
+        );
+      });
+
+      it('allows adding checks negative', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            t.integer('price').checkNegative();
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          'ALTER TABLE [user] ADD [price] int check ([price] < 0)'
+        );
+      });
+
+      it('allows adding checks in', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            t.string('animal').checkIn(['cat', 'dog']);
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          "ALTER TABLE [user] ADD [animal] nvarchar(255) check ([animal] in ('cat','dog'))"
+        );
+      });
+
+      it('allows adding checks not in', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            t.string('animal').checkNotIn(['cat', 'dog']);
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          "ALTER TABLE [user] ADD [animal] nvarchar(255) check ([animal] not in ('cat','dog'))"
+        );
+      });
+
+      it('allows adding checks between', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            t.integer('price').checkBetween([10, 15]);
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          'ALTER TABLE [user] ADD [price] int check ([price] between 10 and 15)'
+        );
+      });
+
+      it('allows adding checks between with multiple intervals', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            t.integer('price').checkBetween([
+              [10, 15],
+              [20, 25],
+            ]);
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          'ALTER TABLE [user] ADD [price] int check ([price] between 10 and 15 or [price] between 20 and 25)'
+        );
+      });
+
+      it('allows adding checks between strings', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            t.integer('price').checkBetween(['banana', 'orange']);
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          "ALTER TABLE [user] ADD [price] int check ([price] between 'banana' and 'orange')"
+        );
+      });
+
+      it('allows length equals', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            t.varchar('phone').checkLength('=', 8);
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          'ALTER TABLE [user] ADD [phone] nvarchar(255) check (LEN([phone]) = 8)'
+        );
+      });
+
+      it('check regexp', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            // MSSQL only support simple pattern matching but not regex syntax.
+            t.varchar('phone').checkRegex('[0-9][0-9][0-9]');
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          "ALTER TABLE [user] ADD [phone] nvarchar(255) check ([phone] LIKE '%[0-9][0-9][0-9]%')"
+        );
+      });
+
+      it('drop checks', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            t.dropChecks(['check_constraint1', 'check_constraint2']);
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          'alter table [user] drop constraint check_constraint1, drop constraint check_constraint2'
+        );
+      });
+    });
   });
 });
diff --git a/test/unit/schema-builder/mysql.js b/test/unit/schema-builder/mysql.js
index dbd8c7ac..e16c486a 100644
--- a/test/unit/schema-builder/mysql.js
+++ b/test/unit/schema-builder/mysql.js
@@ -68,13 +68,14 @@ module.exports = function (dialect) {
         .schemaBuilder()
         .createTable('users', function (table) {
           table.increments('id');
+          // In MySQL a autoincrement column is always a primary key
           table.increments('other_id', { primaryKey: false });
         })
         .toSQL();
 
       equal(1, tableSql.length);
       expect(tableSql[0].sql).to.equal(
-        'create table `users` (`id` int unsigned not null auto_increment primary key, `other_id` int unsigned not null auto_increment)'
+        'create table `users` (`id` int unsigned not null auto_increment primary key, `other_id` int unsigned not null)'
       );
     });
 
@@ -155,9 +156,22 @@ module.exports = function (dialect) {
             view.as(knexMysql('users').select('name').where('age', '>', '18'));
           })
           .toSQL();
-        equal(1, viewSql.length);
+        expect(viewSql.length).to.equal(1);
         expect(viewSql[0].sql).to.equal(
-          "create view or replace `adults` (`name`) as select `name` from `users` where `age` > '18'"
+          "create or replace view `adults` (`name`) as select `name` from `users` where `age` > '18'"
+        );
+      });
+
+      it('create view or replace without columns', async function () {
+        const viewSql = client
+          .schemaBuilder()
+          .createViewOrReplace('adults', function (view) {
+            view.as(knexMysql('users').select('name').where('age', '>', '18'));
+          })
+          .toSQL();
+        expect(viewSql.length).to.equal(1);
+        expect(viewSql[0].sql).to.equal(
+          "create or replace view `adults` as select `name` from `users` where `age` > '18'"
         );
       });
 
@@ -665,13 +679,14 @@ module.exports = function (dialect) {
       tableSql = client
         .schemaBuilder()
         .table('users', function () {
+          // In MySQL a autoincrement column is always a primary key
           this.bigIncrements('id', { primaryKey: false });
         })
         .toSQL();
 
       equal(1, tableSql.length);
       expect(tableSql[0].sql).to.equal(
-        'alter table `users` add `id` bigint unsigned not null auto_increment'
+        'alter table `users` add `id` bigint unsigned not null'
       );
     });
 
@@ -1441,5 +1456,130 @@ module.exports = function (dialect) {
         expect(spy.thirdCall.args).to.deep.equal(['users', 'table context']);
       });
     });
+
+    describe('Checks tests', function () {
+      it('allows adding checks positive', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            t.integer('price').checkPositive();
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          'alter table `user` add `price` int check (`price` > 0)'
+        );
+      });
+
+      it('allows adding checks negative', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            t.integer('price').checkNegative();
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          'alter table `user` add `price` int check (`price` < 0)'
+        );
+      });
+
+      it('allows adding checks in', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            t.string('animal').checkIn(['cat', 'dog']);
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          "alter table `user` add `animal` varchar(255) check (`animal` in ('cat','dog'))"
+        );
+      });
+
+      it('allows adding checks not in', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            t.string('animal').checkNotIn(['cat', 'dog']);
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          "alter table `user` add `animal` varchar(255) check (`animal` not in ('cat','dog'))"
+        );
+      });
+
+      it('allows adding checks between', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            t.integer('price').checkBetween([10, 15]);
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          'alter table `user` add `price` int check (`price` between 10 and 15)'
+        );
+      });
+
+      it('allows adding checks between with multiple intervals', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            t.integer('price').checkBetween([
+              [10, 15],
+              [20, 25],
+            ]);
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          'alter table `user` add `price` int check (`price` between 10 and 15 or `price` between 20 and 25)'
+        );
+      });
+
+      it('allows adding checks between strings', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            t.integer('price').checkBetween(['banana', 'orange']);
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          "alter table `user` add `price` int check (`price` between 'banana' and 'orange')"
+        );
+      });
+
+      it('allows length equals', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            t.varchar('phone').checkLength('=', 8);
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          'alter table `user` add `phone` varchar(255) check (length(`phone`) = 8)'
+        );
+      });
+
+      it('check regexp', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            t.varchar('phone').checkRegex('[0-9]{8}');
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          "alter table `user` add `phone` varchar(255) check (`phone` REGEXP '[0-9]{8}')"
+        );
+      });
+
+      it('drop checks', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            t.dropChecks(['check_constraint1', 'check_constraint2']);
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          'alter table `user` drop constraint check_constraint1, drop constraint check_constraint2'
+        );
+      });
+    });
   });
 };
diff --git a/test/unit/schema-builder/oracle.js b/test/unit/schema-builder/oracle.js
index ca8eba8d..ea5df400 100644
--- a/test/unit/schema-builder/oracle.js
+++ b/test/unit/schema-builder/oracle.js
@@ -76,7 +76,7 @@ describe('Oracle SchemaBuilder', function () {
         table.increments('id', { primaryKey: false });
       });
 
-    equal(2, tableSql.toSQL().length);
+    expect(tableSql.toSQL().length).to.equal(2);
     expect(tableSql.toSQL()[0].sql).to.equal(
       'begin execute immediate \'create table "users" ("id" integer not null)\'; exception when others then if sqlcode != -955 then raise; end if; end;'
     );
diff --git a/test/unit/schema-builder/oracledb.js b/test/unit/schema-builder/oracledb.js
index 2471a964..4b43064d 100644
--- a/test/unit/schema-builder/oracledb.js
+++ b/test/unit/schema-builder/oracledb.js
@@ -97,9 +97,22 @@ describe('OracleDb SchemaBuilder', function () {
           view.as(knexOracleDb('users').select('name').where('age', '>', '18'));
         })
         .toSQL();
-      equal(1, viewSql.length);
+      expect(viewSql.length).to.equal(1);
       expect(viewSql[0].sql).to.equal(
-        'create view or replace "adults" ("name") as select "name" from "users" where "age" > \'18\''
+        'create or replace view "adults" ("name") as select "name" from "users" where "age" > \'18\''
+      );
+    });
+
+    it('create view or replace without columns', async function () {
+      const viewSql = client
+        .schemaBuilder()
+        .createViewOrReplace('adults', function (view) {
+          view.as(knexOracleDb('users').select('name').where('age', '>', '18'));
+        })
+        .toSQL();
+      expect(viewSql.length).to.equal(1);
+      expect(viewSql[0].sql).to.equal(
+        'create or replace view "adults" as select "name" from "users" where "age" > \'18\''
       );
     });
 
@@ -112,7 +125,7 @@ describe('OracleDb SchemaBuilder', function () {
           view.checkOption();
         })
         .toSQL();
-      equal(1, tableSql.length);
+      expect(tableSql.length).to.equal(1);
       expect(tableSql[0].sql).to.equal(
         'create view "adults" ("name") as select "name" from "users" where "age" > \'18\' with check option'
       );
@@ -1240,4 +1253,129 @@ describe('OracleDb SchemaBuilder', function () {
       'begin execute immediate \'drop table "book"\'; exception when others then if sqlcode != -942 then raise; end if; end;\nbegin execute immediate \'drop sequence "book_seq"\'; exception when others then if sqlcode != -2289 then raise; end if; end;'
     );
   });
+
+  describe('Checks tests', function () {
+    it('allows adding checks positive', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.integer('price').checkPositive();
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" add "price" integer check ("price" > 0)'
+      );
+    });
+
+    it('allows adding checks negative', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.integer('price').checkNegative();
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" add "price" integer check ("price" < 0)'
+      );
+    });
+
+    it('allows adding checks in', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.string('animal').checkIn(['cat', 'dog']);
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" add "animal" varchar2(255) check ("animal" in (\'cat\', \'dog\'))'
+      );
+    });
+
+    it('allows adding checks not in', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.string('animal').checkNotIn(['cat', 'dog']);
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" add "animal" varchar2(255) check ("animal" not in (\'cat\',\'dog\'))'
+      );
+    });
+
+    it('allows adding checks between', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.integer('price').checkBetween([10, 15]);
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" add "price" integer check ("price" between 10 and 15)'
+      );
+    });
+
+    it('allows adding checks between with multiple intervals', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.integer('price').checkBetween([
+            [10, 15],
+            [20, 25],
+          ]);
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" add "price" integer check ("price" between 10 and 15 or "price" between 20 and 25)'
+      );
+    });
+
+    it('allows adding checks between strings', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.integer('price').checkBetween(['banana', 'orange']);
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" add "price" integer check ("price" between \'banana\' and \'orange\')'
+      );
+    });
+
+    it('allows length equals', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.varchar('phone').checkLength('=', 8);
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" add "phone" varchar2(255) check (length("phone") = 8)'
+      );
+    });
+
+    it('check regexp', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.varchar('phone').checkRegex('[0-9]{8}');
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" add "phone" varchar2(255) check (REGEXP_LIKE("phone",\'[0-9]{8}\'))'
+      );
+    });
+
+    it('drop checks', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.dropChecks(['check_constraint1', 'check_constraint2']);
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" drop constraint check_constraint1, drop constraint check_constraint2'
+      );
+    });
+  });
 });
diff --git a/test/unit/schema-builder/postgres.js b/test/unit/schema-builder/postgres.js
index 23343cfa..951d3be5 100644
--- a/test/unit/schema-builder/postgres.js
+++ b/test/unit/schema-builder/postgres.js
@@ -201,6 +201,19 @@ describe('PostgreSQL SchemaBuilder', function () {
     );
   });
 
+  it('alter table with checks', function () {
+    tableSql = client
+      .schemaBuilder()
+      .table('users', function (table) {
+        table.integer('price').checkPositive();
+      })
+      .toSQL();
+    equal(1, tableSql.length);
+    expect(tableSql[0].sql).to.equal(
+      'alter table "users" add column "price" integer check ("price" > 0)'
+    );
+  });
+
   it('drop table', function () {
     tableSql = client.schemaBuilder().dropTable('users').toSQL();
     equal(1, tableSql.length);
@@ -255,9 +268,22 @@ describe('PostgreSQL SchemaBuilder', function () {
           view.as(knexPg('users').select('name').where('age', '>', '18'));
         })
         .toSQL();
+      expect(viewSql.length).to.equal(1);
+      expect(viewSql[0].sql).to.equal(
+        'create or replace view "adults" ("name") as select "name" from "users" where "age" > \'18\''
+      );
+    });
+
+    it('create view or replace without columns', async function () {
+      const viewSql = client
+        .schemaBuilder()
+        .createViewOrReplace('adults', function (view) {
+          view.as(knexPg('users').select('name').where('age', '>', '18'));
+        })
+        .toSQL();
       equal(1, viewSql.length);
       expect(viewSql[0].sql).to.equal(
-        'create view or replace "adults" ("name") as select "name" from "users" where "age" > \'18\''
+        'create or replace view "adults" as select "name" from "users" where "age" > \'18\''
       );
     });
 
@@ -2005,4 +2031,129 @@ describe('PostgreSQL SchemaBuilder', function () {
       ]);
     });
   });
+
+  describe('Checks tests', function () {
+    it('allows adding checks positive', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.integer('price').checkPositive();
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" add column "price" integer check ("price" > 0)'
+      );
+    });
+
+    it('allows adding checks negative', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.integer('price').checkNegative();
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" add column "price" integer check ("price" < 0)'
+      );
+    });
+
+    it('allows adding checks in', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.string('animal').checkIn(['cat', 'dog']);
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" add column "animal" varchar(255) check ("animal" in (\'cat\',\'dog\'))'
+      );
+    });
+
+    it('allows adding checks not in', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.string('animal').checkNotIn(['cat', 'dog']);
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" add column "animal" varchar(255) check ("animal" not in (\'cat\',\'dog\'))'
+      );
+    });
+
+    it('allows adding checks between', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.integer('price').checkBetween([10, 15]);
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" add column "price" integer check ("price" between 10 and 15)'
+      );
+    });
+
+    it('allows adding checks between with multiple intervals', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.integer('price').checkBetween([
+            [10, 15],
+            [20, 25],
+          ]);
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" add column "price" integer check ("price" between 10 and 15 or "price" between 20 and 25)'
+      );
+    });
+
+    it('allows adding checks between strings', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.integer('price').checkBetween(['banana', 'orange']);
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" add column "price" integer check ("price" between \'banana\' and \'orange\')'
+      );
+    });
+
+    it('allows length equals', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.varchar('phone').checkLength('=', 8);
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" add column "phone" varchar(255) check (length("phone") = 8)'
+      );
+    });
+
+    it('check regexp', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.varchar('phone').checkRegex('[0-9]{8}');
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" add column "phone" varchar(255) check ("phone" ~ \'[0-9]{8}\')'
+      );
+    });
+
+    it('drop checks', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.dropChecks(['check_constraint1', 'check_constraint2']);
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" drop constraint check_constraint1, drop constraint check_constraint2'
+      );
+    });
+  });
 });
diff --git a/test/unit/schema-builder/redshift.js b/test/unit/schema-builder/redshift.js
index 028c7b30..0137fede 100644
--- a/test/unit/schema-builder/redshift.js
+++ b/test/unit/schema-builder/redshift.js
@@ -93,7 +93,7 @@ describe('Redshift SchemaBuilder', function () {
           view.as(knexRedShift('users').select('name').where('age', '>', '18'));
         })
         .toSQL();
-      equal(1, viewSql.length);
+      expect(viewSql.length).to.equal(1);
       expect(viewSql[0].sql).to.equal(
         'create view "adults" ("name") as select "name" from "users" where "age" > \'18\''
       );
@@ -106,7 +106,7 @@ describe('Redshift SchemaBuilder', function () {
           view.as(knexRedShift('users').select('name').where('age', '>', '18'));
         })
         .toSQL();
-      equal(1, viewSql.length);
+      expect(viewSql.length).to.equal(1);
       expect(viewSql[0].sql).to.equal(
         'create view "adults" as select "name" from "users" where "age" > \'18\''
       );
@@ -120,9 +120,22 @@ describe('Redshift SchemaBuilder', function () {
           view.as(knexRedShift('users').select('name').where('age', '>', '18'));
         })
         .toSQL();
-      equal(1, viewSql.length);
+      expect(viewSql.length).to.equal(1);
       expect(viewSql[0].sql).to.equal(
-        'create view or replace "adults" ("name") as select "name" from "users" where "age" > \'18\''
+        'create or replace view "adults" ("name") as select "name" from "users" where "age" > \'18\''
+      );
+    });
+
+    it('create view or replace without columns', async function () {
+      const viewSql = client
+        .schemaBuilder()
+        .createViewOrReplace('adults', function (view) {
+          view.as(knexRedShift('users').select('name').where('age', '>', '18'));
+        })
+        .toSQL();
+      expect(viewSql.length).to.equal(1);
+      expect(viewSql[0].sql).to.equal(
+        'create or replace view "adults" as select "name" from "users" where "age" > \'18\''
       );
     });
 
@@ -135,7 +148,7 @@ describe('Redshift SchemaBuilder', function () {
           view.localCheckOption();
         })
         .toSQL();
-      equal(1, viewSqlLocalCheck.length);
+      expect(viewSqlLocalCheck.length).to.equal(1);
       expect(viewSqlLocalCheck[0].sql).to.equal(
         'create view "adults" ("name") as select "name" from "users" where "age" > \'18\' with local check option'
       );
@@ -148,7 +161,7 @@ describe('Redshift SchemaBuilder', function () {
           view.cascadedCheckOption();
         })
         .toSQL();
-      equal(1, viewSqlCascadedCheck.length);
+      expect(viewSqlCascadedCheck.length).to.equal(1);
       expect(viewSqlCascadedCheck[0].sql).to.equal(
         'create view "adults" ("name") as select "name" from "users" where "age" > \'18\' with cascaded check option'
       );
@@ -1001,4 +1014,129 @@ describe('Redshift SchemaBuilder', function () {
       'alter table "users" add constraint "testconstraintname" primary key ("test")'
     );
   });
+
+  describe('Checks tests', function () {
+    it('allows adding checks positive', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.integer('price').checkPositive();
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" add column "price" integer check ("price" > 0)'
+      );
+    });
+
+    it('allows adding checks negative', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.integer('price').checkNegative();
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" add column "price" integer check ("price" < 0)'
+      );
+    });
+
+    it('allows adding checks in', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.string('animal').checkIn(['cat', 'dog']);
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" add column "animal" varchar(255) check ("animal" in (\'cat\',\'dog\'))'
+      );
+    });
+
+    it('allows adding checks not in', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.string('animal').checkNotIn(['cat', 'dog']);
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" add column "animal" varchar(255) check ("animal" not in (\'cat\',\'dog\'))'
+      );
+    });
+
+    it('allows adding checks between', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.integer('price').checkBetween([10, 15]);
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" add column "price" integer check ("price" between 10 and 15)'
+      );
+    });
+
+    it('allows adding checks between with multiple intervals', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.integer('price').checkBetween([
+            [10, 15],
+            [20, 25],
+          ]);
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" add column "price" integer check ("price" between 10 and 15 or "price" between 20 and 25)'
+      );
+    });
+
+    it('allows adding checks between strings', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.integer('price').checkBetween(['banana', 'orange']);
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" add column "price" integer check ("price" between \'banana\' and \'orange\')'
+      );
+    });
+
+    it('allows length equals', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.varchar('phone').checkLength('=', 8);
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" add column "phone" varchar(255) check (length("phone") = 8)'
+      );
+    });
+
+    it('check regexp', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.varchar('phone').checkRegex('[0-9]{8}');
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" add column "phone" varchar(255) check ("phone" ~ \'[0-9]{8}\')'
+      );
+    });
+
+    it('drop checks', function () {
+      tableSql = client
+        .schemaBuilder()
+        .table('user', function (t) {
+          t.dropChecks(['check_constraint1', 'check_constraint2']);
+        })
+        .toSQL();
+      expect(tableSql[0].sql).to.equal(
+        'alter table "user" drop constraint check_constraint1, drop constraint check_constraint2'
+      );
+    });
+  });
 });
diff --git a/test/unit/schema-builder/sqlite3.js b/test/unit/schema-builder/sqlite3.js
index 1333c390..164b52e4 100644
--- a/test/unit/schema-builder/sqlite3.js
+++ b/test/unit/schema-builder/sqlite3.js
@@ -110,14 +110,32 @@ describe('SQLite SchemaBuilder', function () {
     });
 
     it('create view or replace', async function () {
-      expect(() => {
-        tableSql = client
-          .schemaBuilder()
-          .view('users', function (view) {
-            view.column('oldName').rename('newName').defaultTo('10');
-          })
-          .toSQL();
-      }).to.throw('rename column of views is not supported by this dialect.');
+      const viewSql = client
+        .schemaBuilder()
+        .createViewOrReplace('adults', function (view) {
+          view.columns(['name']);
+          view.as(knexSqlite3('users').select('name').where('age', '>', '18'));
+        })
+        .toSQL();
+      expect(viewSql.length).to.equal(2);
+      expect(viewSql[0].sql).to.equal('drop view if exists `adults`');
+      expect(viewSql[1].sql).to.equal(
+        "create view `adults` (`name`) as select `name` from `users` where `age` > '18'"
+      );
+    });
+
+    it('create view or replace without columns', async function () {
+      const viewSql = client
+        .schemaBuilder()
+        .createViewOrReplace('adults', function (view) {
+          view.as(knexSqlite3('users').select('name').where('age', '>', '18'));
+        })
+        .toSQL();
+      expect(viewSql.length).to.equal(2);
+      expect(viewSql[0].sql).to.equal('drop view if exists `adults`');
+      expect(viewSql[1].sql).to.equal(
+        "create view `adults` as select `name` from `users` where `age` > '18'"
+      );
     });
 
     it('create view with check options', async function () {
@@ -214,15 +232,15 @@ describe('SQLite SchemaBuilder', function () {
     tableSql = client
       .schemaBuilder()
       .createTable('users', function (table) {
-        table.increments('id');
-        table.increments('other_id', { primaryKey: false });
+        // This make nothing in SQLite, autoincrement without primary key is a syntax error.
+        table.increments('id', { primaryKey: false });
       })
       .toSQL();
 
     equal(1, tableSql.length);
     equal(
       tableSql[0].sql,
-      'create table `users` (`id` integer not null primary key autoincrement, `other_id` integer not null autoincrement)'
+      'create table `users` (`id` integer not null primary key autoincrement)'
     );
   });
 
@@ -563,6 +581,7 @@ describe('SQLite SchemaBuilder', function () {
     tableSql = client
       .schemaBuilder()
       .table('users', function (table) {
+        // This make nothing in SQLite, autoincrement without primary key is a syntax error.
         table.bigIncrements('id', { primaryKey: false });
       })
       .toSQL();
@@ -570,7 +589,7 @@ describe('SQLite SchemaBuilder', function () {
     equal(1, tableSql.length);
     equal(
       tableSql[0].sql,
-      'alter table `users` add column `id` integer not null autoincrement'
+      'alter table `users` add column `id` integer not null primary key autoincrement'
     );
   });
 
@@ -4474,5 +4493,130 @@ describe('SQLite parser and compiler', function () {
 
       expect(parsedSql).to.equal(newSql);
     });
+
+    describe('Checks tests', function () {
+      it('allows adding checks positive', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            t.integer('price').checkPositive();
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          'alter table `user` add column `price` integer check (`price` > 0)'
+        );
+      });
+
+      it('allows adding checks negative', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            t.integer('price').checkNegative();
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          'alter table `user` add column `price` integer check (`price` < 0)'
+        );
+      });
+
+      it('allows adding checks in', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            t.string('animal').checkIn(['cat', 'dog']);
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          "alter table `user` add column `animal` varchar(255) check (`animal` in ('cat','dog'))"
+        );
+      });
+
+      it('allows adding checks not in', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            t.string('animal').checkNotIn(['cat', 'dog']);
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          "alter table `user` add column `animal` varchar(255) check (`animal` not in ('cat','dog'))"
+        );
+      });
+
+      it('allows adding checks between', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            t.integer('price').checkBetween([10, 15]);
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          'alter table `user` add column `price` integer check (`price` between 10 and 15)'
+        );
+      });
+
+      it('allows adding checks between with multiple intervals', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            t.integer('price').checkBetween([
+              [10, 15],
+              [20, 25],
+            ]);
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          'alter table `user` add column `price` integer check (`price` between 10 and 15 or `price` between 20 and 25)'
+        );
+      });
+
+      it('allows adding checks between strings', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            t.integer('price').checkBetween(['banana', 'orange']);
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          "alter table `user` add column `price` integer check (`price` between 'banana' and 'orange')"
+        );
+      });
+
+      it('allows length equals', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            t.varchar('phone').checkLength('=', 8);
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          'alter table `user` add column `phone` varchar(255) check (length(`phone`) = 8)'
+        );
+      });
+
+      it('check regexp', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            t.varchar('phone').checkRegex('[0-9]{8}');
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          "alter table `user` add column `phone` varchar(255) check (`phone` REGEXP '[0-9]{8}')"
+        );
+      });
+
+      it('drop checks', function () {
+        tableSql = client
+          .schemaBuilder()
+          .table('user', function (t) {
+            t.dropChecks(['check_constraint1', 'check_constraint2']);
+          })
+          .toSQL();
+        expect(tableSql[0].sql).to.equal(
+          'alter table `user` drop constraint check_constraint1, drop constraint check_constraint2'
+        );
+      });
+    });
   });
 });