Repository: ariga/atlas
Pull request #433 (2022-01-18 09:42:39)

sql/schema: simplify the ExecQuerier interface.
Make it simpler to implement it by tools like Ent


Patch:
diff --git a/sql/internal/sqlx/sqlx.go b/sql/internal/sqlx/sqlx.go
index d773155c..a560408d 100644
--- a/sql/internal/sqlx/sqlx.go
+++ b/sql/internal/sqlx/sqlx.go
@@ -20,6 +20,18 @@ func ValidString(s sql.NullString) bool {
 	return s.Valid && s.String != "" && strings.ToLower(s.String) != "null"
 }
 
+// ScanOne scans one record and closes the rows at the end.
+func ScanOne(rows *sql.Rows, dest ...interface{}) error {
+	defer rows.Close()
+	if !rows.Next() {
+		return sql.ErrNoRows
+	}
+	if err := rows.Scan(dest...); err != nil {
+		return err
+	}
+	return rows.Close()
+}
+
 // ScanFKs scans the rows and adds the foreign-key to the table.
 // Reference elements are added as stubs and should be linked
 // manually by the caller.
diff --git a/sql/mysql/driver.go b/sql/mysql/driver.go
index 07c6e9ff..9627f426 100644
--- a/sql/mysql/driver.go
+++ b/sql/mysql/driver.go
@@ -5,6 +5,7 @@
 package mysql
 
 import (
+	"context"
 	"fmt"
 	"strings"
 
@@ -38,8 +39,12 @@ type (
 // Open opens a new MySQL driver.
 func Open(db schema.ExecQuerier) (*Driver, error) {
 	c := conn{ExecQuerier: db}
-	if err := db.QueryRow(variablesQuery).Scan(&c.version, &c.collate, &c.charset); err != nil {
-		return nil, fmt.Errorf("mysql: scanning system variables: %w", err)
+	rows, err := db.QueryContext(context.Background(), variablesQuery)
+	if err != nil {
+		return nil, fmt.Errorf("mysql: query system variables: %w", err)
+	}
+	if err := sqlx.ScanOne(rows, &c.version, &c.collate, &c.charset); err != nil {
+		return nil, fmt.Errorf("mysql: scan system variables: %w", err)
 	}
 	return &Driver{
 		conn:        c,
diff --git a/sql/mysql/inspect.go b/sql/mysql/inspect.go
index 974467f6..07de9c1a 100644
--- a/sql/mysql/inspect.go
+++ b/sql/mysql/inspect.go
@@ -160,12 +160,15 @@ func (i *inspect) table(ctx context.Context, name string, opts *schema.InspectTa
 		query = tableSchemaQuery
 		args = append(args, opts.Schema)
 	}
-	row := i.QueryRowContext(ctx, query, args...)
+	rows, err := i.QueryContext(ctx, query, args...)
+	if err != nil {
+		return nil, err
+	}
 	var (
 		autoinc                                       sql.NullInt64
 		tSchema, charset, collation, comment, options sql.NullString
 	)
-	if err := row.Scan(&tSchema, &charset, &collation, &autoinc, &comment, &options); err != nil {
+	if err := sqlx.ScanOne(rows, &tSchema, &charset, &collation, &autoinc, &comment, &options); err != nil {
 		if err == sql.ErrNoRows {
 			return nil, &schema.NotExistError{
 				Err: fmt.Errorf("mysql: table %q was not found", name),
@@ -199,6 +202,9 @@ func (i *inspect) table(ctx context.Context, name string, opts *schema.InspectTa
 			V: autoinc.Int64,
 		})
 	}
+	if err := i.createStmt(ctx, t); err != nil {
+		return nil, err
+	}
 	return t, nil
 }
 
@@ -210,7 +216,7 @@ func (i *inspect) columns(ctx context.Context, t *schema.Table) error {
 	}
 	defer rows.Close()
 	for rows.Next() {
-		if err := i.addColumn(ctx, t, rows); err != nil {
+		if err := i.addColumn(t, rows); err != nil {
 			return fmt.Errorf("mysql: %w", err)
 		}
 	}
@@ -218,7 +224,7 @@ func (i *inspect) columns(ctx context.Context, t *schema.Table) error {
 }
 
 // addColumn scans the current row and adds a new column from it to the table.
-func (i *inspect) addColumn(ctx context.Context, t *schema.Table, rows *sql.Rows) error {
+func (i *inspect) addColumn(t *schema.Table, rows *sql.Rows) error {
 	var name, typ, comment, nullable, key, defaults, extra, charset, collation sql.NullString
 	if err := rows.Scan(&name, &typ, &comment, &nullable, &key, &defaults, &extra, &charset, &collation); err != nil {
 		return err
@@ -235,7 +241,7 @@ func (i *inspect) addColumn(ctx context.Context, t *schema.Table, rows *sql.Rows
 		return err
 	}
 	c.Type.Type = ct
-	if err := i.extraAttr(ctx, t, c, extra.String); err != nil {
+	if err := i.extraAttr(t, c, extra.String); err != nil {
 		return err
 	}
 	if sqlx.ValidString(defaults) {
@@ -436,7 +442,7 @@ func (i *inspect) tableNames(ctx context.Context, schema string, opts *schema.In
 
 // extraAttr parses the EXTRA column from the INFORMATION_SCHEMA.COLUMNS table
 // and appends its parsed representation to the column.
-func (i *inspect) extraAttr(ctx context.Context, t *schema.Table, c *schema.Column, extra string) error {
+func (i *inspect) extraAttr(t *schema.Table, c *schema.Column, extra string) error {
 	switch extra := strings.ToLower(extra); extra {
 	case "", "null": // ignore.
 	case defaultGen:
@@ -448,7 +454,7 @@ func (i *inspect) extraAttr(ctx context.Context, t *schema.Table, c *schema.Colu
 		// from INFORMATION_SCHEMA, it is due to information_schema_stats_expiry and we
 		// need to extract it from the 'CREATE TABLE' command.
 		if !sqlx.Has(t.Attrs, a) {
-			inc, err := i.loadAutoinc(ctx, t)
+			inc, err := i.autoinc(t)
 			if err != nil {
 				return err
 			}
@@ -467,11 +473,11 @@ func (i *inspect) extraAttr(ctx context.Context, t *schema.Table, c *schema.Colu
 
 var reAutoinc = regexp.MustCompile(`(?i)\s+AUTO_INCREMENT\s*=\s*(\d+)\s+`)
 
-// loadAutoinc loads the updated AUTO_INCREMENT from CREATE TABLE.
-func (i *inspect) loadAutoinc(ctx context.Context, t *schema.Table) (*AutoIncrement, error) {
-	c, err := i.createStmt(ctx, t)
-	if err != nil {
-		return nil, err
+// autoinc extracts the updated AUTO_INCREMENT from CREATE TABLE.
+func (i *inspect) autoinc(t *schema.Table) (*AutoIncrement, error) {
+	var c CreateStmt
+	if !sqlx.Has(t.Attrs, &c) {
+		return nil, fmt.Errorf("missing CREATE TABLE statment in attribuets for %q", t.Name)
 	}
 	matches := reAutoinc.FindStringSubmatch(c.S)
 	if len(matches) != 2 {
@@ -485,16 +491,17 @@ func (i *inspect) loadAutoinc(ctx context.Context, t *schema.Table) (*AutoIncrem
 }
 
 // createStmt loads the CREATE TABLE statement for the table.
-func (i *inspect) createStmt(ctx context.Context, t *schema.Table) (*CreateStmt, error) {
+func (i *inspect) createStmt(ctx context.Context, t *schema.Table) error {
 	c := &CreateStmt{}
-	if sqlx.Has(t.Attrs, c) {
-		return c, nil
+	rows, err := i.QueryContext(ctx, Build("SHOW CREATE TABLE").Table(t).String())
+	if err != nil {
+		return fmt.Errorf("query CREATE TABLE %q: %w", t.Name, err)
 	}
-	if err := i.QueryRowContext(ctx, Build("SHOW CREATE TABLE").Table(t).String()).Scan(&sql.NullString{}, &c.S); err != nil {
-		return nil, fmt.Errorf("query CREATE TABLE %q: %w", t.Name, err)
+	if err := sqlx.ScanOne(rows, &sql.NullString{}, &c.S); err != nil {
+		return fmt.Errorf("scan CREATE TABLE %q: %w", t.Name, err)
 	}
 	t.Attrs = append(t.Attrs, c)
-	return c, nil
+	return nil
 }
 
 // myDefaultExpr returns the correct schema.Expr based on the column attributes for MySQL.
diff --git a/sql/postgres/diff.go b/sql/postgres/diff.go
index cf64338f..edcad98a 100644
--- a/sql/postgres/diff.go
+++ b/sql/postgres/diff.go
@@ -5,6 +5,7 @@
 package postgres
 
 import (
+	"context"
 	"fmt"
 	"reflect"
 	"strconv"
@@ -267,7 +268,11 @@ func (d *diff) valuesEqual(x, y string) (bool, error) {
 	var b bool
 	// The DEFAULT expressions are safe to be inlined in the SELECT
 	// statement same as we inline them in the CREATE TABLE statement.
-	if err := d.QueryRow(fmt.Sprintf("SELECT %s = %s", x, y)).Scan(&b); err != nil {
+	rows, err := d.QueryContext(context.Background(), fmt.Sprintf("SELECT %s = %s", x, y))
+	if err != nil {
+		return false, err
+	}
+	if err := sqlx.ScanOne(rows, &b); err != nil {
 		return false, err
 	}
 	return b, nil
@@ -279,7 +284,11 @@ func (d *diff) typesEqual(x, y string) (bool, error) {
 	var b bool
 	// The datatype are safe to be inlined in the SELECT statement
 	// same as we inline them in the CREATE TABLE statement.
-	if err := d.QueryRow(fmt.Sprintf("SELECT '%s'::regtype = '%s'::regtype", x, y)).Scan(&b); err != nil {
+	rows, err := d.QueryContext(context.Background(), fmt.Sprintf("SELECT '%s'::regtype = '%s'::regtype", x, y))
+	if err != nil {
+		return false, err
+	}
+	if err := sqlx.ScanOne(rows, &b); err != nil {
 		return false, err
 	}
 	return b, nil
diff --git a/sql/postgres/driver.go b/sql/postgres/driver.go
index 3b24fd1a..d6570ac7 100644
--- a/sql/postgres/driver.go
+++ b/sql/postgres/driver.go
@@ -5,6 +5,7 @@
 package postgres
 
 import (
+	"context"
 	"fmt"
 
 	"ariga.io/atlas/sql/internal/sqlx"
@@ -37,18 +38,13 @@ type (
 // Open opens a new PostgreSQL driver.
 func Open(db schema.ExecQuerier) (*Driver, error) {
 	c := conn{ExecQuerier: db}
-	rows, err := db.Query(paramsQuery)
+	rows, err := db.QueryContext(context.Background(), paramsQuery)
 	if err != nil {
 		return nil, fmt.Errorf("postgres: scanning system variables: %w", err)
 	}
-	defer rows.Close()
-	params := make([]string, 0, 3)
-	for rows.Next() {
-		var v string
-		if err := rows.Scan(&v); err != nil {
-			return nil, fmt.Errorf("postgres: failed scanning row value: %w", err)
-		}
-		params = append(params, v)
+	params, err := sqlx.ScanStrings(rows)
+	if err != nil {
+		return nil, fmt.Errorf("postgres: failed scanning row value: %w", err)
 	}
 	if len(params) != 3 {
 		return nil, fmt.Errorf("postgres: unexpected number of rows: %d", len(params))
diff --git a/sql/postgres/inspect.go b/sql/postgres/inspect.go
index 9b4ef947..d414d757 100644
--- a/sql/postgres/inspect.go
+++ b/sql/postgres/inspect.go
@@ -51,8 +51,12 @@ func (i *inspect) InspectSchema(ctx context.Context, name string, opts *schema.I
 	var schemas []*schema.Schema
 	switch name {
 	case "":
-		if err := i.QueryRowContext(ctx, "SELECT CURRENT_SCHEMA()").Scan(&name); err != nil {
-			return nil, fmt.Errorf("postgres: failed querying attached schema: %w", err)
+		rows, err := i.QueryContext(ctx, "SELECT CURRENT_SCHEMA()")
+		if err != nil {
+			return nil, fmt.Errorf("postgres: query attached schema: %w", err)
+		}
+		if err := sqlx.ScanOne(rows, &name); err != nil {
+			return nil, fmt.Errorf("postgres: scan attached schema: %w", err)
 		}
 		schemas = append(schemas, &schema.Schema{Name: name})
 	default:
@@ -121,9 +125,14 @@ func (i *inspect) table(ctx context.Context, name string, opts *schema.InspectTa
 		query = tableSchemaQuery
 		args = append(args, opts.Schema)
 	}
-	row := i.QueryRowContext(ctx, query, args...)
-	var tSchema, comment sql.NullString
-	if err := row.Scan(&tSchema, &comment); err != nil {
+	var (
+		tSchema, comment sql.NullString
+		rows, err        = i.QueryContext(ctx, query, args...)
+	)
+	if err != nil {
+		return nil, err
+	}
+	if err := sqlx.ScanOne(rows, &tSchema, &comment); err != nil {
 		if err == sql.ErrNoRows {
 			return nil, &schema.NotExistError{
 				Err: fmt.Errorf("postgres: table %q was not found", name),
diff --git a/sql/schema/inspect.go b/sql/schema/inspect.go
index aa13f4d0..610973b0 100644
--- a/sql/schema/inspect.go
+++ b/sql/schema/inspect.go
@@ -27,11 +27,8 @@ func IsNotExistError(err error) bool {
 	return errors.As(err, &e)
 }
 
-// ExecQuerier wraps the standard sql.DB methods.
+// ExecQuerier wraps the two standard sql.DB methods.
 type ExecQuerier interface {
-	QueryRow(query string, args ...interface{}) *sql.Row
-	QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row
-	Query(query string, args ...interface{}) (*sql.Rows, error)
 	QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
 	ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
 }
diff --git a/sql/sqlite/driver.go b/sql/sqlite/driver.go
index 2b43d507..9d86fede 100644
--- a/sql/sqlite/driver.go
+++ b/sql/sqlite/driver.go
@@ -5,6 +5,7 @@
 package sqlite
 
 import (
+	"context"
 	"fmt"
 
 	"ariga.io/atlas/sql/internal/sqlx"
@@ -34,16 +35,19 @@ type (
 
 // Open opens a new SQLite driver.
 func Open(db schema.ExecQuerier) (*Driver, error) {
-	c := conn{ExecQuerier: db}
-	if err := db.QueryRow("SELECT sqlite_version()").Scan(&c.version); err != nil {
-		return nil, fmt.Errorf("sqlite: scanning database version: %w", err)
+	var (
+		c   = conn{ExecQuerier: db}
+		ctx = context.Background()
+	)
+	rows, err := db.QueryContext(ctx, "SELECT sqlite_version(), foreign_keys from pragma_foreign_keys")
+	if err != nil {
+		return nil, fmt.Errorf("sqlite: query version and foreign_keys pragma: %w", err)
 	}
-	if err := db.QueryRow("PRAGMA foreign_keys").Scan(&c.fkEnabled); err != nil {
-		return nil, fmt.Errorf("sqlite: check foreign_keys pragma: %w", err)
+	if err := sqlx.ScanOne(rows, &c.version, &c.fkEnabled); err != nil {
+		return nil, fmt.Errorf("sqlite: scan version and foreign_keys pragma: %w", err)
 	}
-	rows, err := db.Query("SELECT name FROM pragma_collation_list()")
-	if err != nil {
-		return nil, fmt.Errorf("sqlite: check collation_list pragma: %w", err)
+	if rows, err = db.QueryContext(ctx, "SELECT name FROM pragma_collation_list()"); err != nil {
+		return nil, fmt.Errorf("sqlite: query foreign_keys pragma: %w", err)
 	}
 	if c.collations, err = sqlx.ScanStrings(rows); err != nil {
 		return nil, fmt.Errorf("sqlite: scanning database collations: %w", err)
diff --git a/sql/sqlite/migrate.go b/sql/sqlite/migrate.go
index 3d4bde56..f5992323 100644
--- a/sql/sqlite/migrate.go
+++ b/sql/sqlite/migrate.go
@@ -6,8 +6,6 @@ package sqlite
 
 import (
 	"context"
-	"database/sql"
-	"errors"
 	"fmt"
 	"strings"
 
@@ -398,22 +396,22 @@ func (s *state) tableSeq(ctx context.Context, add *schema.AddTable) error {
 		return nil
 	}
 	// SQLite tracks the AUTOINCREMENT in the "sqlite_sequence" table that is created and initialized automatically
-	// whenever such table is created. However, the rows are populated after the first insertion, and therefore, we
-	// check if the sequence row exists, and we either created it for non zero sequence, or update it if it is 0 and
-	// the configured sequence is > 0.
-	var seq int64
-	switch err := s.QueryRowContext(ctx, "SELECT seq FROM sqlite_sequence WHERE name = ?", add.T.Name).Scan(&seq); {
-	case errors.Is(err, sql.ErrNoRows):
+	// whenever the first "PRIMARY KEY AUTOINCREMENT" is created. However, rows in this table are populated after the
+	// first insertion to the associated table (name, seq). Therefore, we check if the sequence table and the row exist,
+	// and in case they are not, we insert a new non zero sequence to it.
+	rows, err := s.QueryContext(ctx, "SELECT seq FROM sqlite_sequence WHERE name = ?", add.T.Name)
+	if err != nil || !rows.Next() {
 		s.append(&migrate.Change{
 			Cmd:     fmt.Sprintf("INSERT INTO sqlite_sequence (name, seq) VALUES (%q, %d)", add.T.Name, inc.Seq),
 			Source:  add,
 			Reverse: fmt.Sprintf("UPDATE sqlite_sequence SET seq = 0 WHERE name = %q", add.T.Name),
 			Comment: fmt.Sprintf("set sequence for %q table", add.T.Name),
 		})
-	case err != nil:
-		return fmt.Errorf("query sequence value for table %q: %w", add.T.Name, err)
 	}
-	return nil
+	if rows != nil {
+		err = rows.Close()
+	}
+	return err
 }
 
 func (s *state) append(c *migrate.Change) {


Test patch:
diff --git a/internal/integration/mysql_test.go b/internal/integration/mysql_test.go
index f640fd31..eedcc580 100644
--- a/internal/integration/mysql_test.go
+++ b/internal/integration/mysql_test.go
@@ -891,6 +891,7 @@ create table atlas_types_sanity
 					},
 				},
 			}
+			rmCreateStmt(ts)
 			require.EqualValues(t, &expected, ts)
 			t.hclDriftTest(n, realm, expected)
 		})
@@ -947,6 +948,7 @@ create table atlas_types_sanity
 					}(),
 				},
 			}
+			rmCreateStmt(ts)
 			require.EqualValues(t, &expected, ts)
 		})
 	})
@@ -1166,5 +1168,15 @@ func (t *myTest) hclDriftTest(n string, realm *schema.Realm, expected schema.Tab
 	require.Len(t, realm.Schemas, 1)
 	ts, ok := realm.Schemas[0].Table(n)
 	require.True(t, ok)
+	rmCreateStmt(ts)
 	require.EqualValues(t, &expected, ts)
 }
+
+func rmCreateStmt(t *schema.Table) {
+	for i := range t.Attrs {
+		if _, ok := t.Attrs[i].(*mysql.CreateStmt); ok {
+			t.Attrs = append(t.Attrs[:i], t.Attrs[i+1:]...)
+			return
+		}
+	}
+}
diff --git a/sql/mysql/inspect_test.go b/sql/mysql/inspect_test.go
index e4b7a727..cb2517f3 100644
--- a/sql/mysql/inspect_test.go
+++ b/sql/mysql/inspect_test.go
@@ -63,6 +63,14 @@ func TestDriver_InspectTable(t *testing.T) {
 +--------------+--------------------+--------------------+----------------+---------------+--------------------+
 | test         | utf8mb4            | utf8mb4_0900_ai_ci | nil            | Comment       | COMPRESSION="ZLIB" |
 +--------------+--------------------+--------------------+----------------+---------------+--------------------+
+`))
+				m.ExpectQuery(sqltest.Escape("SHOW CREATE TABLE `test`.`users`")).
+					WillReturnRows(sqltest.Rows(`
++-------+---------------------------------------------------------------------------------------------------------------------------------------------+
+| Table | Create Table                                                                                                                                |
++-------+---------------------------------------------------------------------------------------------------------------------------------------------+
+| users | CREATE TABLE users (id bigint NOT NULL AUTO_INCREMENT) ENGINE=InnoDB AUTO_INCREMENT=55834574848 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin |
++-------+---------------------------------------------------------------------------------------------------------------------------------------------+
 `))
 				m.ExpectQuery(sqltest.Escape(columnsQuery)).
 					WithArgs("test", "users").
@@ -72,14 +80,6 @@ func TestDriver_InspectTable(t *testing.T) {
 +--------------------+----------------------+----------------------+-------------+------------+----------------+----------------+--------------------+----------------+
 | id                 | bigint(20)           |                      | NO          | PRI        | NULL           | auto_increment | NULL               | NULL           |
 +--------------------+----------------------+----------------------+-------------+------------+----------------+----------------+--------------------+----------------+
-`))
-				m.ExpectQuery(sqltest.Escape("SHOW CREATE TABLE `test`.`users`")).
-					WillReturnRows(sqltest.Rows(`
-+-------+---------------------------------------------------------------------------------------------------------------------------------------------+
-| Table | Create Table                                                                                                                                |
-+-------+---------------------------------------------------------------------------------------------------------------------------------------------+
-| users | CREATE TABLE users (id bigint NOT NULL AUTO_INCREMENT) ENGINE=InnoDB AUTO_INCREMENT=55834574848 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin |
-+-------+---------------------------------------------------------------------------------------------------------------------------------------------+
 `))
 				m.noIndexes()
 				m.noFKs()
@@ -606,7 +606,7 @@ func TestDriver_InspectTable(t *testing.T) {
 					{Name: "c1", Type: &schema.ColumnType{Raw: "int", Type: &schema.IntegerType{T: "int"}}},
 				}
 				require.EqualValues(columns, t.Columns)
-				require.EqualValues([]schema.Attr{&schema.Check{Name: "users_chk_1", Expr: "(`c6` <>_latin1\\'foo\\'s\\')", Attrs: []schema.Attr{&Enforced{}}}}, t.Attrs)
+				require.EqualValues([]schema.Attr{&CreateStmt{S: "CREATE TABLE users()"}, &schema.Check{Name: "users_chk_1", Expr: "(`c6` <>_latin1\\'foo\\'s\\')", Attrs: []schema.Attr{&Enforced{}}}}, t.Attrs)
 			},
 		},
 	}
@@ -911,6 +911,14 @@ func (m mock) tableExists(schema, table string, exists bool) {
 	m.ExpectQuery(sqltest.Escape(tableQuery)).
 		WithArgs(table).
 		WillReturnRows(rows)
+	m.ExpectQuery(sqltest.Escape(fmt.Sprintf("SHOW CREATE TABLE `%s`.`%s`", schema, table))).
+		WillReturnRows(sqltest.Rows(`
++-------------+--------------------------------------+
+|    Table    | Create Table                         |
++-------------+--------------------------------------+
+|` + table + `| CREATE TABLE ` + table + `()         |
++-------------+--------------------------------------+
+`))
 }
 
 func (m mock) tableExistsInSchema(schema, table string, exists bool) {
@@ -921,4 +929,12 @@ func (m mock) tableExistsInSchema(schema, table string, exists bool) {
 	m.ExpectQuery(sqltest.Escape(tableSchemaQuery)).
 		WithArgs(table, schema).
 		WillReturnRows(rows)
+	m.ExpectQuery(sqltest.Escape(fmt.Sprintf("SHOW CREATE TABLE `%s`.`%s`", schema, table))).
+		WillReturnRows(sqltest.Rows(`
++-------------+--------------------------------------+
+|    Table    | Create Table                         |
++-------------+--------------------------------------+
+|` + table + `| CREATE TABLE ` + table + `()         |
++-------------+--------------------------------------+
+`))
 }
diff --git a/sql/sqlite/inspect_test.go b/sql/sqlite/inspect_test.go
index 11fda179..fadd14e4 100644
--- a/sql/sqlite/inspect_test.go
+++ b/sql/sqlite/inspect_test.go
@@ -424,17 +424,11 @@ type mock struct {
 }
 
 func (m mock) systemVars(version string) {
-	m.ExpectQuery(sqltest.Escape("SELECT sqlite_version()")).
+	m.ExpectQuery(sqltest.Escape("SELECT sqlite_version(), foreign_keys from pragma_foreign_keys")).
 		WillReturnRows(sqltest.Rows(`
-  version   
-------------
- ` + version + `
-`))
-	m.ExpectQuery(sqltest.Escape("PRAGMA foreign_keys")).
-		WillReturnRows(sqltest.Rows(`
-  foreign_keys   
-------------
-    1
+     version    |   foreign_keys    
+----------------+-----------------
+ ` + version + `|       1
 `))
 	m.ExpectQuery(sqltest.Escape("SELECT name FROM pragma_collation_list()")).
 		WillReturnRows(sqltest.Rows(`