Repository: ariga/atlas
Pull request #2570 (2024-02-22 15:46:53)

sql/postgres: minor improvements to type references


Patch:
diff --git a/sql/internal/sqlx/plan.go b/sql/internal/sqlx/plan.go
index 619406cd..9bcc15ee 100644
--- a/sql/internal/sqlx/plan.go
+++ b/sql/internal/sqlx/plan.go
@@ -97,7 +97,7 @@ func SetReversible(p *migrate.Plan) error {
 // creation, or deletes fks before deletes their tables.
 func DetachCycles(changes []schema.Change) ([]schema.Change, error) {
 	sorted, err := sortMap(changes)
-	if err == errCycle {
+	if errors.Is(err, errCycle) {
 		return detachReferences(changes), nil
 	}
 	if err != nil {
diff --git a/sql/postgres/convert.go b/sql/postgres/convert.go
index 628511f2..aff0da53 100644
--- a/sql/postgres/convert.go
+++ b/sql/postgres/convert.go
@@ -270,11 +270,6 @@ func columnType(c *columnDesc) (schema.Type, error) {
 			if err != nil {
 				return nil, err
 			}
-			if c.elemtyp == "e" {
-				// Override the element type in
-				// case it is an enum.
-				tt = newEnumType(t, c.typelem)
-			}
 			typ.(*ArrayType).Type = tt
 		}
 	case TypeTSVector, TypeTSQuery:
@@ -294,13 +289,8 @@ func columnType(c *columnDesc) (schema.Type, error) {
 		typ = &schema.UnsupportedType{T: t}
 	}
 	switch c.typtype {
-	case "e":
-		// The `typtype` column is set to 'e' for enum types, and the
-		// values are filled in batch after the rows above is closed.
-		// https://postgresql.org/docs/current/catalog-pg-type.html
-		typ = newEnumType(c.fmtype, c.typid)
-	case "d":
-		// Use user-defined for domain types as not all atlas versions support it.
+	case "d", "e":
+		// User-defined types supported by Atlas.
 		typ = &UserDefinedType{T: c.fmtype}
 	}
 	return typ, nil
@@ -339,7 +329,6 @@ type columnDesc struct {
 	size          int64  // character_maximum_length
 	typtype       string // pg_type.typtype
 	typelem       int64  // pg_type.typelem
-	elemtyp       string // pg_type.typtype of the array element type above.
 	typid         int64  // pg_type.oid
 	precision     int64
 	timePrecision *int64
diff --git a/sql/postgres/crdb.go b/sql/postgres/crdb.go
index c98735bf..9c500348 100644
--- a/sql/postgres/crdb.go
+++ b/sql/postgres/crdb.go
@@ -173,8 +173,6 @@ func (cd *crdbDiff) normalize(table *schema.Table) {
 				// is equivalent to character(1).
 				t.Size = 1
 			}
-		case *enumType:
-			c.Type.Type = &schema.EnumType{T: t.T, Values: t.Values}
 		}
 	}
 }
@@ -324,7 +322,6 @@ SELECT
 	col_description(t3.oid, "ordinal_position") AS comment,
 	t4.typtype,
 	t4.typelem,
-	(CASE WHEN t4.typcategory = 'A' AND t4.typelem <> 0 THEN (SELECT t.typtype FROM pg_catalog.pg_type t WHERE t.oid = t4.typelem) END) AS elemtyp,
 	t4.oid
 FROM
 	"information_schema"."columns" AS t1
diff --git a/sql/postgres/driver_oss.go b/sql/postgres/driver_oss.go
index 69c4b1c9..bb84fec3 100644
--- a/sql/postgres/driver_oss.go
+++ b/sql/postgres/driver_oss.go
@@ -242,3 +242,75 @@ func objectSpec(d *doc, spec *specutil.SchemaSpec, s *schema.Schema) error {
 	}
 	return nil
 }
+
+// convertEnums converts possibly referenced column types (like enums) to
+// an actual schema.Type and sets it on the correct schema.Column.
+func convertTypes(d *doc, r *schema.Realm) error {
+	if len(d.Enums) == 0 {
+		return nil
+	}
+	byName := make(map[string]*schema.EnumType)
+	for _, e := range d.Enums {
+		if byName[e.Name] != nil {
+			return fmt.Errorf("duplicate enum %q", e.Name)
+		}
+		ns, err := specutil.SchemaName(e.Schema)
+		if err != nil {
+			return fmt.Errorf("extract schema name from enum reference: %w", err)
+		}
+		es, ok := r.Schema(ns)
+		if !ok {
+			return fmt.Errorf("schema %q defined on enum %q was not found in realm", ns, e.Name)
+		}
+		e1 := &schema.EnumType{T: e.Name, Schema: es, Values: e.Values}
+		es.AddObjects(e1)
+		byName[e.Name] = e1
+	}
+	for _, t := range d.Tables {
+		for _, c := range t.Columns {
+			var enum *schema.EnumType
+			switch {
+			case c.Type.IsRefTo("enum"):
+				n, err := enumName(c.Type)
+				if err != nil {
+					return err
+				}
+				e, ok := byName[n]
+				if !ok {
+					return fmt.Errorf("enum %q was not found in realm", n)
+				}
+				enum = e
+			default:
+				if n, ok := arrayType(c.Type.T); ok {
+					enum = byName[n]
+				}
+			}
+			if enum == nil {
+				continue
+			}
+			schemaT, err := specutil.SchemaName(t.Schema)
+			if err != nil {
+				return fmt.Errorf("extract schema name from table reference: %w", err)
+			}
+			ts, ok := r.Schema(schemaT)
+			if !ok {
+				return fmt.Errorf("schema %q not found in realm for table %q", schemaT, t.Name)
+			}
+			tt, ok := ts.Table(t.Name)
+			if !ok {
+				return fmt.Errorf("table %q not found in schema %q", t.Name, ts.Name)
+			}
+			cc, ok := tt.Column(c.Name)
+			if !ok {
+				return fmt.Errorf("column %q not found in table %q", c.Name, t.Name)
+			}
+			switch t := cc.Type.Type.(type) {
+			case *ArrayType:
+				t.Type = enum
+			default:
+				cc.Type.Type = enum
+			}
+		}
+	}
+	return nil
+}
diff --git a/sql/postgres/inspect.go b/sql/postgres/inspect.go
index 0f37557f..4cc1f8d6 100644
--- a/sql/postgres/inspect.go
+++ b/sql/postgres/inspect.go
@@ -41,6 +41,14 @@ func (i *inspect) InspectRealm(ctx context.Context, opts *schema.InspectRealmOpt
 		mode = sqlx.ModeInspectRealm(opts)
 	)
 	if len(schemas) > 0 {
+		if err := i.inspectEnums(ctx, r); err != nil {
+			return nil, err
+		}
+		if mode.Is(schema.InspectTypes) {
+			if err := i.inspectTypes(ctx, r, nil); err != nil {
+				return nil, err
+			}
+		}
 		if mode.Is(schema.InspectTables) {
 			if err := i.inspectTables(ctx, r, nil); err != nil {
 				return nil, err
@@ -57,14 +65,6 @@ func (i *inspect) InspectRealm(ctx context.Context, opts *schema.InspectRealmOpt
 				return nil, err
 			}
 		}
-		if err := i.inspectEnums(ctx, r); err != nil {
-			return nil, err
-		}
-		if mode.Is(schema.InspectTypes) {
-			if err := i.inspectTypes(ctx, r, nil); err != nil {
-				return nil, err
-			}
-		}
 		if mode.Is(schema.InspectObjects) {
 			if err := i.inspectSequences(ctx, r, nil); err != nil {
 				return nil, err
@@ -106,6 +106,14 @@ func (i *inspect) InspectSchema(ctx context.Context, name string, opts *schema.I
 		r    = schema.NewRealm(schemas...)
 		mode = sqlx.ModeInspectSchema(opts)
 	)
+	if err := i.inspectEnums(ctx, r); err != nil {
+		return nil, err
+	}
+	if mode.Is(schema.InspectTypes) {
+		if err := i.inspectTypes(ctx, r, opts); err != nil {
+			return nil, err
+		}
+	}
 	if mode.Is(schema.InspectTables) {
 		if err := i.inspectTables(ctx, r, opts); err != nil {
 			return nil, err
@@ -122,14 +130,6 @@ func (i *inspect) InspectSchema(ctx context.Context, name string, opts *schema.I
 			return nil, err
 		}
 	}
-	if err := i.inspectEnums(ctx, r); err != nil {
-		return nil, err
-	}
-	if mode.Is(schema.InspectTypes) {
-		if err := i.inspectTypes(ctx, r, opts); err != nil {
-			return nil, err
-		}
-	}
 	if mode.Is(schema.InspectObjects) {
 		if err := i.inspectSequences(ctx, r, opts); err != nil {
 			return nil, err
@@ -249,12 +249,12 @@ func (i *inspect) columns(ctx context.Context, s *schema.Schema) error {
 // addColumn scans the current row and adds a new column from it to the scope (table or view).
 func (i *inspect) addColumn(s *schema.Schema, rows *sql.Rows) (err error) {
 	var (
-		typid, typelem, maxlen, precision, timeprecision, scale, seqstart, seqinc, seqlast                                                  sql.NullInt64
-		table, name, typ, fmtype, nullable, defaults, identity, genidentity, genexpr, charset, collate, comment, typtype, elemtyp, interval sql.NullString
+		typid, typelem, maxlen, precision, timeprecision, scale, seqstart, seqinc, seqlast                                         sql.NullInt64
+		table, name, typ, fmtype, nullable, defaults, identity, genidentity, genexpr, charset, collate, comment, typtype, interval sql.NullString
 	)
 	if err = rows.Scan(
 		&table, &name, &typ, &fmtype, &nullable, &defaults, &maxlen, &precision, &timeprecision, &scale, &interval, &charset,
-		&collate, &identity, &seqstart, &seqinc, &seqlast, &genidentity, &genexpr, &comment, &typtype, &typelem, &elemtyp, &typid,
+		&collate, &identity, &seqstart, &seqinc, &seqlast, &genidentity, &genexpr, &comment, &typtype, &typelem, &typid,
 	); err != nil {
 		return err
 	}
@@ -282,12 +282,23 @@ func (i *inspect) addColumn(s *schema.Schema, rows *sql.Rows) (err error) {
 		scale:         scale.Int64,
 		typtype:       typtype.String,
 		typelem:       typelem.Int64,
-		elemtyp:       elemtyp.String,
 		typid:         typid.Int64,
 		interval:      interval.String,
 		precision:     precision.Int64,
 		timePrecision: &timeprecision.Int64,
 	})
+	switch tt := c.Type.Type.(type) {
+	case *ArrayType:
+		if u, ok := tt.Underlying().(*UserDefinedType); ok {
+			tt.Type = i.underlyingType(s, u)
+		}
+	case *UserDefinedType:
+		ut := i.underlyingType(s, tt)
+		if ut != tt {
+			c.Type.Raw = tt.T
+			c.Type.Type = ut
+		}
+	}
 	if defaults.Valid {
 		columnDefault(c, defaults.String)
 	}
@@ -319,43 +330,70 @@ func (i *inspect) addColumn(s *schema.Schema, rows *sql.Rows) (err error) {
 	return nil
 }
 
+// parseType is like ParseType, but aware of the Realm state.
+func (i *inspect) parseType(ns *schema.Schema, s string) (schema.Type, error) {
+	t, err := ParseType(s)
+	if err != nil {
+		return nil, err
+	}
+	switch tt := t.(type) {
+	case *ArrayType:
+		if u, ok := tt.Underlying().(*UserDefinedType); ok {
+			tt.Type = i.underlyingType(ns, u)
+		}
+	case *UserDefinedType:
+		t = i.underlyingType(ns, tt)
+	}
+	return t, nil
+}
+
+// underlyingType returns the underlying type of the given user-defined
+// type by searching the realm.
+func (i *inspect) underlyingType(s *schema.Schema, u *UserDefinedType) schema.Type {
+	var (
+		sr       []*schema.Schema
+		ns, name = parseFmtType(u.T)
+	)
+	switch nsScope := i.schema != ""; {
+	// If the scope is one schema, the namespace defined
+	// on the type because it resides on a different schema.
+	case ns == "":
+		if !nsScope && s.Realm != nil {
+			// Search in the "public" schema first, because in the default
+			// configuration unqualified types refer to the public schema.
+			if s1, ok := s.Realm.Schema("public"); ok {
+				sr = append(sr, s1)
+			}
+		}
+		sr = append(sr, s)
+	// Allow searching in other schemas, only if
+	// we are not in a schema scope.
+	case ns != "" && !nsScope && s.Realm != nil:
+		if s1, ok := s.Realm.Schema(ns); ok {
+			sr = []*schema.Schema{s1}
+		}
+	}
+	for _, s := range sr {
+		for _, o := range s.Objects {
+			if e, ok := o.(*schema.EnumType); ok && e.T == name {
+				return e
+			} else if d, ok := o.(*DomainType); ok && d.T == name {
+				return d
+			}
+		}
+	}
+	// No match.
+	return u
+}
+
 // enumValues fills enum columns with their values from the database.
 func (i *inspect) inspectEnums(ctx context.Context, r *schema.Realm) error {
 	var (
 		ids  = make(map[int64]*schema.EnumType)
 		args = make([]any, 0, len(r.Schemas))
-		newE = func(e1 *enumType) *schema.EnumType {
-			e2, ok := ids[e1.ID]
-			if ok {
-				return e2
-			}
-			e2 = &schema.EnumType{T: e1.T}
-			ids[e1.ID] = e2
-			return e2
-		}
-		scanC = func(cs []*schema.Column) {
-			for _, c := range cs {
-				switch t := c.Type.Type.(type) {
-				case *enumType:
-					e := newE(t)
-					c.Type.Type = e
-					c.Type.Raw = e.T
-				case *ArrayType:
-					if e, ok := t.Type.(*enumType); ok {
-						t.Type = newE(e)
-					}
-				}
-			}
-		}
 	)
 	for _, s := range r.Schemas {
 		args = append(args, s.Name)
-		for _, t := range s.Tables {
-			scanC(t.Columns)
-		}
-		for _, v := range s.Views {
-			scanC(v.Columns)
-		}
 	}
 	if len(args) == 0 {
 		return nil
@@ -787,7 +825,7 @@ func canConvert(t schema.Type, x string) (string, bool) {
 	q := x[0:i]
 	x = x[1 : i-1]
 	switch t.(type) {
-	case *enumType:
+	case *schema.EnumType:
 		return q, true
 	case *schema.BoolType:
 		if sqlx.IsLiteralBool(x) {
@@ -823,16 +861,6 @@ type (
 		V int64
 	}
 
-	// enumType represents an enum type. It serves aa intermediate representation of a Postgres enum type,
-	// to temporary save TypeID and TypeName of an enum column until the enum values can be extracted.
-	enumType struct {
-		schema.Type
-		T      string // Type name.
-		Schema string // Optional schema name.
-		ID     int64  // Type id.
-		Values []string
-	}
-
 	// ArrayType defines an array type.
 	// https://postgresql.org/docs/current/arrays.html
 	ArrayType struct {
@@ -1314,11 +1342,6 @@ func parseFmtType(t string) (s, n string) {
 	return s, n
 }
 
-func newEnumType(t string, id int64) *enumType {
-	s, n := parseFmtType(t)
-	return &enumType{T: n, Schema: s, ID: id}
-}
-
 const (
 	// Query to list runtime parameters.
 	paramsQuery = `SELECT setting FROM pg_settings WHERE name IN ('server_version_num', 'crdb_version') ORDER BY name DESC`
@@ -1421,7 +1444,6 @@ SELECT
 	col_description(t3.oid, "ordinal_position") AS comment,
 	t4.typtype,
 	t4.typelem,
-	(CASE WHEN t4.typcategory = 'A' AND t4.typelem <> 0 THEN (SELECT t.typtype FROM pg_catalog.pg_type t WHERE t.oid = t4.typelem) END) AS elemtyp,
 	t4.oid
 FROM
 	"information_schema"."columns" AS t1
diff --git a/sql/postgres/sqlspec.go b/sql/postgres/sqlspec.go
index c3c2ef6e..0d21d6a1 100644
--- a/sql/postgres/sqlspec.go
+++ b/sql/postgres/sqlspec.go
@@ -146,10 +146,7 @@ func evalSpec(p *hclparse.Parser, v any, input map[string]cty.Value) error {
 		if err := specutil.Scan(v, d.ScanDoc(), scanFuncs); err != nil {
 			return fmt.Errorf("specutil: failed converting to *schema.Realm: %w", err)
 		}
-		if err := convertEnums(d.Tables, d.Enums, v); err != nil {
-			return err
-		}
-		if err := convertDomains(d.Tables, d.Domains, v); err != nil {
+		if err := convertTypes(&d, v); err != nil {
 			return err
 		}
 		if err := convertSequences(d.Tables, d.Sequences, v); err != nil {
@@ -170,10 +167,7 @@ func evalSpec(p *hclparse.Parser, v any, input map[string]cty.Value) error {
 		if err := specutil.Scan(r, d.ScanDoc(), scanFuncs); err != nil {
 			return err
 		}
-		if err := convertEnums(d.Tables, d.Enums, r); err != nil {
-			return err
-		}
-		if err := convertDomains(d.Tables, d.Domains, r); err != nil {
+		if err := convertTypes(&d, r); err != nil {
 			return err
 		}
 		if err := convertSequences(d.Tables, d.Sequences, r); err != nil {
@@ -591,78 +585,6 @@ func convertColumnType(spec *sqlspec.Column) (schema.Type, error) {
 	return typ, nil
 }
 
-// convertEnums converts possibly referenced column types (like enums) to
-// an actual schema.Type and sets it on the correct schema.Column.
-func convertEnums(tables []*sqlspec.Table, enums []*enum, r *schema.Realm) error {
-	if len(enums) == 0 {
-		return nil
-	}
-	byName := make(map[string]*schema.EnumType)
-	for _, e := range enums {
-		if byName[e.Name] != nil {
-			return fmt.Errorf("duplicate enum %q", e.Name)
-		}
-		ns, err := specutil.SchemaName(e.Schema)
-		if err != nil {
-			return fmt.Errorf("extract schema name from enum reference: %w", err)
-		}
-		es, ok := r.Schema(ns)
-		if !ok {
-			return fmt.Errorf("schema %q defined on enum %q was not found in realm", ns, e.Name)
-		}
-		e1 := &schema.EnumType{T: e.Name, Schema: es, Values: e.Values}
-		es.AddObjects(e1)
-		byName[e.Name] = e1
-	}
-	for _, t := range tables {
-		for _, c := range t.Columns {
-			var enum *schema.EnumType
-			switch {
-			case c.Type.IsRefTo("enum"):
-				n, err := enumName(c.Type)
-				if err != nil {
-					return err
-				}
-				e, ok := byName[n]
-				if !ok {
-					return fmt.Errorf("enum %q was not found in realm", n)
-				}
-				enum = e
-			default:
-				if n, ok := arrayType(c.Type.T); ok {
-					enum = byName[n]
-				}
-			}
-			if enum == nil {
-				continue
-			}
-			schemaT, err := specutil.SchemaName(t.Schema)
-			if err != nil {
-				return fmt.Errorf("extract schema name from table reference: %w", err)
-			}
-			ts, ok := r.Schema(schemaT)
-			if !ok {
-				return fmt.Errorf("schema %q not found in realm for table %q", schemaT, t.Name)
-			}
-			tt, ok := ts.Table(t.Name)
-			if !ok {
-				return fmt.Errorf("table %q not found in schema %q", t.Name, ts.Name)
-			}
-			cc, ok := tt.Column(c.Name)
-			if !ok {
-				return fmt.Errorf("column %q not found in table %q", c.Name, t.Name)
-			}
-			switch t := cc.Type.Type.(type) {
-			case *ArrayType:
-				t.Type = enum
-			default:
-				cc.Type.Type = enum
-			}
-		}
-	}
-	return nil
-}
-
 // enumName extracts the name of the referenced Enum from the reference string.
 func enumName(ref *schemahcl.Type) (string, error) {
 	s := strings.Split(ref.T, "$enum.")


Test patch:
diff --git a/sql/postgres/inspect_test.go b/sql/postgres/inspect_test.go
index e0ad3672..7c38f9d5 100644
--- a/sql/postgres/inspect_test.go
+++ b/sql/postgres/inspect_test.go
@@ -39,60 +39,6 @@ func TestDriver_InspectTable(t *testing.T) {
 		{
 			name: "column types",
 			before: func(m mock) {
-				m.tableExists("public", "users", true)
-				m.ExpectQuery(queryColumns).
-					WithArgs("public", "users").
-					WillReturnRows(sqltest.Rows(`
- table_name  |  column_name |          data_type          |  formatted          | is_nullable |         column_default                 | character_maximum_length | numeric_precision | datetime_precision | numeric_scale |    interval_type    | character_set_name | collation_name | is_identity | identity_start | identity_increment |   identity_last  | identity_generation | generation_expression | comment | typtype | typelem | elemtyp |  oid
--------------+--------------+-----------------------------+---------------------|-------------+----------------------------------------+--------------------------+-------------------+--------------------+---------------+---------------------+--------------------+----------------+-------------+----------------+--------------------+------------------+---------------------+-----------------------+---------+---------+---------+---------+-------
- users       |  id          | bigint                      | int8                | NO          |                                        |                          |                64 |                    |             0 |                     |                    |                | YES         |      100       |          1         |          1       |    BY DEFAULT       |                       |         | b       |         |         |    20
- users       |  rank        | integer                     | int4                | YES         |                                        |                          |                32 |                    |             0 |                     |                    |                | NO          |                |                    |                  |                     |                       | rank    | b       |         |         |    23
- users       |  c1          | smallint                    | int2                | NO          |           1000                         |                          |                16 |                    |             0 |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |    21
- users       |  c2          | bit                         | bit                 | NO          |                                        |                        1 |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |  1560
- users       |  c3          | bit varying                 | varbit              | NO          |                                        |                       10 |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |  1562
- users       |  c4          | boolean                     | bool                | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |    16
- users       |  c5          | bytea                       | bytea               | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |    17
- users       |  c6          | character                   | bpchar              | NO          |                                        |                      100 |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |  1042
- users       |  c7          | character varying           | varchar             | NO          | 'logged_in'::character varying         |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |  1043
- users       |  c8          | cidr                        | cidr                | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |   650
- users       |  c9          | circle                      | circle              | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |   718
- users       |  c10         | date                        | date                | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |  1082
- users       |  c11         | time with time zone         | timetz              | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |  1266
- users       |  c12         | double precision            | float8              | NO          |                                        |                          |                53 |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |   701
- users       |  c13         | real                        | float4              | NO          |           random()                     |                          |                24 |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |   700
- users       |  c14         | json                        | json                | NO          |           '{}'::json                   |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |   114
- users       |  c15         | jsonb                       | jsonb               | NO          |           '{}'::jsonb                  |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |  3802
- users       |  c16         | money                       | money               | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |   790
- users       |  c17         | numeric                     | numeric             | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |  1700
- users       |  c18         | numeric                     | numeric             | NO          |                                        |                          |                 4 |                    |             4 |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |  1700
- users       |  c19         | integer                     | int4                | NO          | nextval('t1_c19_seq'::regclass)        |                          |                32 |                    |             0 |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |    23
- users       |  c20         | uuid                        | uuid                | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |  2950
- users       |  c21         | xml                         | xml                 | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |   142
- users       |  c22         | ARRAY                       | integer[]           | YES         |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |  1007
- users       |  c23         | USER-DEFINED                | ltree               | YES         |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         | 16535
- users       |  c24         | USER-DEFINED                | state               | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | e       |         |         | 16774
- users       |  c25         | timestamp without time zone | timestamp           | NO          |            now()                       |                          |                   |                  4 |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |  1114
- users       |  c26         | timestamp with time zone    | timestamptz         | NO          |                                        |                          |                   |                  6 |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |  1184
- users       |  c27         | time without time zone      | time                | NO          |                                        |                          |                   |                  6 |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |  1266
- users       |  c28         | int                         | int8                | NO          |                                        |                          |                   |                  6 |               |                     |                    |                | NO          |                |                    |                  |                     |        (c1 + c2)      |         | b       |         |         |  1267
- users       |  c29         | interval                    | interval            | NO          |                                        |                          |                   |                  6 |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |  1268
- users       |  c30         | interval                    | interval            | NO          |                                        |                          |                   |                  6 |               |        MONTH        |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |  1269
- users       |  c31         | interval                    | interval            | NO          |                                        |                          |                   |                  6 |               | MINUTE TO SECOND(6) |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |  1233
- users       |  c32         | bigint                      | int4                | NO          | nextval('public.t1_c32_seq'::regclass) |                          |                32 |                    |             0 |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |    23
- users       |  c33         | USER-DEFINED                | public."status""."  | NO          |  'unknown'::test."status""."           |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | e       |         |         | 16775
- users       |  c34         | ARRAY                       | state[]             | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |  16774  |  e      | 16779
- users       |  c35         | character                   | domain_char         | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | d       |  16774  |  e      | 16779
- users       |  c36         | tsvector                    | tsvector            | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |  16774  |         | 16779
- users       |  c37         | tsquery                     | tsquery             | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |  16774  |         | 16779
- users       |  c38         | datemultirange              | datemultirange      | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | m       |         |         | 4535
- users       |  c39         | numrange                    | numrange            | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | m       |         |         | 4536
- users       |  c40         | smallint                    | int4                | NO          | nextval('"Users_c40_seq"'::regclass)   |                          |                32 |                    |             0 |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |    23
- users       |  c41         | smallint                    | int4                | NO          | nextval('foo."T_C40_seq"'::regclass)   |                          |                32 |                    |             0 |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |    23
- users       |  c42         | smallint                    | int4                | NO          | nextval('"F"."T_C40_seq"'::regclass)   |                          |                32 |                    |             0 |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |    23
-`))
-				m.noIndexes()
-				m.noFKs()
-				m.noChecks()
 				m.ExpectQuery(sqltest.Escape(fmt.Sprintf(enumsQuery, "$1"))).
 					WithArgs("public").
 					WillReturnRows(sqltest.Rows(`
@@ -102,13 +48,67 @@ func TestDriver_InspectTable(t *testing.T) {
  public      |   16774 |  state  | off
  public      |   16775 |  status | unknown
 `))
+				m.tableExists("public", "users", true)
+				m.ExpectQuery(queryColumns).
+					WithArgs("public", "users").
+					WillReturnRows(sqltest.Rows(`
+ table_name  |  column_name |          data_type          |  formatted          | is_nullable |         column_default                 | character_maximum_length | numeric_precision | datetime_precision | numeric_scale |    interval_type    | character_set_name | collation_name | is_identity | identity_start | identity_increment |   identity_last  | identity_generation | generation_expression | comment | typtype | typelem |  oid
+-------------+--------------+-----------------------------+---------------------|-------------+----------------------------------------+--------------------------+-------------------+--------------------+---------------+---------------------+--------------------+----------------+-------------+----------------+--------------------+------------------+---------------------+-----------------------+---------+---------+---------+-------
+ users       |  id          | bigint                      | int8                | NO          |                                        |                          |                64 |                    |             0 |                     |                    |                | YES         |      100       |          1         |          1       |    BY DEFAULT       |                       |         | b       |         |    20
+ users       |  rank        | integer                     | int4                | YES         |                                        |                          |                32 |                    |             0 |                     |                    |                | NO          |                |                    |                  |                     |                       | rank    | b       |         |    23
+ users       |  c1          | smallint                    | int2                | NO          |           1000                         |                          |                16 |                    |             0 |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |    21
+ users       |  c2          | bit                         | bit                 | NO          |                                        |                        1 |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1560
+ users       |  c3          | bit varying                 | varbit              | NO          |                                        |                       10 |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1562
+ users       |  c4          | boolean                     | bool                | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |    16
+ users       |  c5          | bytea                       | bytea               | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |    17
+ users       |  c6          | character                   | bpchar              | NO          |                                        |                      100 |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1042
+ users       |  c7          | character varying           | varchar             | NO          | 'logged_in'::character varying         |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1043
+ users       |  c8          | cidr                        | cidr                | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   650
+ users       |  c9          | circle                      | circle              | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   718
+ users       |  c10         | date                        | date                | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1082
+ users       |  c11         | time with time zone         | timetz              | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1266
+ users       |  c12         | double precision            | float8              | NO          |                                        |                          |                53 |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   701
+ users       |  c13         | real                        | float4              | NO          |           random()                     |                          |                24 |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   700
+ users       |  c14         | json                        | json                | NO          |           '{}'::json                   |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   114
+ users       |  c15         | jsonb                       | jsonb               | NO          |           '{}'::jsonb                  |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  3802
+ users       |  c16         | money                       | money               | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   790
+ users       |  c17         | numeric                     | numeric             | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1700
+ users       |  c18         | numeric                     | numeric             | NO          |                                        |                          |                 4 |                    |             4 |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1700
+ users       |  c19         | integer                     | int4                | NO          | nextval('t1_c19_seq'::regclass)        |                          |                32 |                    |             0 |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |    23
+ users       |  c20         | uuid                        | uuid                | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  2950
+ users       |  c21         | xml                         | xml                 | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   142
+ users       |  c22         | ARRAY                       | integer[]           | YES         |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1007
+ users       |  c23         | USER-DEFINED                | ltree               | YES         |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         | 16535
+ users       |  c24         | USER-DEFINED                | state               | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | e       |         | 16774
+ users       |  c25         | timestamp without time zone | timestamp           | NO          |            now()                       |                          |                   |                  4 |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1114
+ users       |  c26         | timestamp with time zone    | timestamptz         | NO          |                                        |                          |                   |                  6 |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1184
+ users       |  c27         | time without time zone      | time                | NO          |                                        |                          |                   |                  6 |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1266
+ users       |  c28         | int                         | int8                | NO          |                                        |                          |                   |                  6 |               |                     |                    |                | NO          |                |                    |                  |                     |        (c1 + c2)      |         | b       |         |  1267
+ users       |  c29         | interval                    | interval            | NO          |                                        |                          |                   |                  6 |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1268
+ users       |  c30         | interval                    | interval            | NO          |                                        |                          |                   |                  6 |               |        MONTH        |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1269
+ users       |  c31         | interval                    | interval            | NO          |                                        |                          |                   |                  6 |               | MINUTE TO SECOND(6) |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1233
+ users       |  c32         | bigint                      | int4                | NO          | nextval('public.t1_c32_seq'::regclass) |                          |                32 |                    |             0 |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |    23
+ users       |  c33         | USER-DEFINED                | status              | NO          |  'unknown'::test."status""."           |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | e       |         | 16775
+ users       |  c34         | ARRAY                       | state[]             | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |  16774  | 16779
+ users       |  c35         | character                   | domain_char         | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | d       |  16774  | 16779
+ users       |  c36         | tsvector                    | tsvector            | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |  16774  | 16779
+ users       |  c37         | tsquery                     | tsquery             | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |  16774  | 16779
+ users       |  c38         | datemultirange              | datemultirange      | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | m       |         | 4535
+ users       |  c39         | numrange                    | numrange            | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | m       |         | 4536
+ users       |  c40         | smallint                    | int4                | NO          | nextval('"Users_c40_seq"'::regclass)   |                          |                32 |                    |             0 |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |    23
+ users       |  c41         | smallint                    | int4                | NO          | nextval('foo."T_C40_seq"'::regclass)   |                          |                32 |                    |             0 |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |    23
+ users       |  c42         | smallint                    | int4                | NO          | nextval('"F"."T_C40_seq"'::regclass)   |                          |                32 |                    |             0 |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |    23
+`))
+				m.noIndexes()
+				m.noFKs()
+				m.noChecks()
 			},
 			expect: func(require *require.Assertions, t *schema.Table, err error) {
 				require.NoError(err)
 				require.Equal("users", t.Name)
 				stateE := &schema.EnumType{T: "state", Values: []string{"on", "off"}, Schema: t.Schema}
-				statusE := &schema.EnumType{T: `status".` /* intentionally broken */, Values: []string{"unknown"}, Schema: t.Schema}
-				require.EqualValues([]*schema.Column{
+				statusE := &schema.EnumType{T: "status", Values: []string{"unknown"}, Schema: t.Schema}
+				expected := []*schema.Column{
 					{Name: "id", Type: &schema.ColumnType{Raw: "bigint", Type: &schema.IntegerType{T: "bigint"}}, Attrs: []schema.Attr{&Identity{Generation: "BY DEFAULT", Sequence: &Sequence{Start: 100, Increment: 1, Last: 1}}}},
 					{Name: "rank", Type: &schema.ColumnType{Raw: "integer", Null: true, Type: &schema.IntegerType{T: "integer"}}, Attrs: []schema.Attr{&schema.Comment{Text: "rank"}}},
 					{Name: "c1", Type: &schema.ColumnType{Raw: "smallint", Type: &schema.IntegerType{T: "smallint"}}, Default: &schema.Literal{V: "1000"}},
@@ -143,7 +143,7 @@ func TestDriver_InspectTable(t *testing.T) {
 					{Name: "c30", Type: &schema.ColumnType{Raw: "interval", Type: &IntervalType{T: "interval", F: "MONTH", Precision: sqlx.P(6)}}},
 					{Name: "c31", Type: &schema.ColumnType{Raw: "interval", Type: &IntervalType{T: "interval", F: "MINUTE TO SECOND", Precision: sqlx.P(6)}}},
 					{Name: "c32", Type: &schema.ColumnType{Raw: "bigserial", Type: &SerialType{T: "bigserial", SequenceName: "t1_c32_seq"}}},
-					{Name: "c33", Type: &schema.ColumnType{Raw: `status".`, Type: statusE}, Default: &schema.Literal{V: "'unknown'"}},
+					{Name: "c33", Type: &schema.ColumnType{Raw: `status`, Type: statusE}, Default: &schema.Literal{V: "'unknown'"}},
 					{Name: "c34", Type: &schema.ColumnType{Raw: "ARRAY", Type: &ArrayType{T: "state[]", Type: stateE}}},
 					{Name: "c35", Type: &schema.ColumnType{Raw: "domain_char", Type: &UserDefinedType{T: "domain_char"}}},
 					{Name: "c36", Type: &schema.ColumnType{Raw: "tsvector", Type: &TextSearchType{T: "tsvector"}}},
@@ -153,23 +153,27 @@ func TestDriver_InspectTable(t *testing.T) {
 					{Name: "c40", Type: &schema.ColumnType{Raw: "smallserial", Type: &SerialType{T: "smallserial", SequenceName: "Users_c40_seq"}}},
 					{Name: "c41", Type: &schema.ColumnType{Raw: "smallserial", Type: &SerialType{T: "smallserial", SequenceName: "T_C40_seq"}}},
 					{Name: "c42", Type: &schema.ColumnType{Raw: "smallserial", Type: &SerialType{T: "smallserial", SequenceName: "T_C40_seq"}}},
-				}, t.Columns)
+				}
+				for i, c := range expected {
+					require.Equal(c, t.Columns[i])
+				}
 				require.Equal([]schema.Object{stateE, statusE}, t.Schema.Objects)
 			},
 		},
 		{
 			name: "table indexes",
 			before: func(m mock) {
+				m.noEnums()
 				m.tableExists("public", "users", true)
 				m.ExpectQuery(queryColumns).
 					WithArgs("public", "users").
 					WillReturnRows(sqltest.Rows(`
-table_name | column_name |      data_type      | formatted |  is_nullable |         column_default          | character_maximum_length | numeric_precision | datetime_precision | numeric_scale | interval_type | character_set_name | collation_name | is_identity | identity_start | identity_increment |   identity_last  | identity_generation | generation_expression | comment | typtype | typelem | elemtyp |  oid
------------+-------------+---------------------+-----------+--------------+---------------------------------+--------------------------+-------------------+--------------------+---------------+---------------+--------------------+----------------+-------------+----------------+--------------------+------------------+---------------------+-----------------------+---------+---------+---------+---------+-------
-users      | id          | bigint              | int8      |  NO          |                                 |                          |                64 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |    20
-users      | c1          | smallint            | int2      |  NO          |                                 |                          |                16 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |    21
-users      | parent_id   | bigint              | int8      |  YES         |                                 |                          |                64 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |    22
-users      | ts          | tsvector            | tsvector  |  NO          |                                 |                          |                   |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |    23
+table_name | column_name |      data_type      | formatted |  is_nullable |         column_default          | character_maximum_length | numeric_precision | datetime_precision | numeric_scale | interval_type | character_set_name | collation_name | is_identity | identity_start | identity_increment |   identity_last  | identity_generation | generation_expression | comment | typtype | typelem |  oid
+-----------+-------------+---------------------+-----------+--------------+---------------------------------+--------------------------+-------------------+--------------------+---------------+---------------+--------------------+----------------+-------------+----------------+--------------------+------------------+---------------------+-----------------------+---------+---------+---------+-------
+users      | id          | bigint              | int8      |  NO          |                                 |                          |                64 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |    20
+users      | c1          | smallint            | int2      |  NO          |                                 |                          |                16 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |    21
+users      | parent_id   | bigint              | int8      |  YES         |                                 |                          |                64 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |    22
+users      | ts          | tsvector            | tsvector  |  NO          |                                 |                          |                   |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |    23
 `))
 				m.ExpectQuery(queryIndexes).
 					WithArgs("public", "users").
@@ -194,7 +198,6 @@ users           | tsx             | gist        | ts          | f        | f
 `))
 				m.noFKs()
 				m.noChecks()
-				m.noEnums()
 			},
 			expect: func(require *require.Assertions, t *schema.Table, err error) {
 				require.NoError(err)
@@ -233,15 +236,16 @@ users           | tsx             | gist        | ts          | f        | f
 		{
 			name: "fks",
 			before: func(m mock) {
+				m.noEnums()
 				m.tableExists("public", "users", true)
 				m.ExpectQuery(queryColumns).
 					WithArgs("public", "users").
 					WillReturnRows(sqltest.Rows(`
-table_name | column_name |      data_type      | formatted | is_nullable |         column_default          | character_maximum_length | numeric_precision | datetime_precision | numeric_scale | interval_type | character_set_name | collation_name | is_identity | identity_start | identity_increment |   identity_last  | identity_generation | generation_expression | comment | typtype | typelem | elemtyp |  oid
------------+-------------+---------------------+-----------+-------------+---------------------------------+--------------------------+-------------------+--------------------+---------------+---------------+--------------------+----------------+-------------+----------------+--------------------+------------------+---------------------+-----------------------+---------+---------+---------+---------+-------
-users      | id          | integer             | int       | NO          |                                 |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |    20
-users      | oid         | integer             | int       | NO          |                                 |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |    21
-users      | uid         | integer             | int       | NO          |                                 |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |    21
+table_name | column_name |      data_type      | formatted | is_nullable |         column_default          | character_maximum_length | numeric_precision | datetime_precision | numeric_scale | interval_type | character_set_name | collation_name | is_identity | identity_start | identity_increment |   identity_last  | identity_generation | generation_expression | comment | typtype | typelem | oid
+-----------+-------------+---------------------+-----------+-------------+---------------------------------+--------------------------+-------------------+--------------------+---------------+---------------+--------------------+----------------+-------------+----------------+--------------------+------------------+---------------------+-----------------------+---------+---------+---------+------
+users      | id          | integer             | int       | NO          |                                 |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   20
+users      | oid         | integer             | int       | NO          |                                 |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   21
+users      | uid         | integer             | int       | NO          |                                 |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   21
 `))
 				m.noIndexes()
 				m.ExpectQuery(queryFKs).
@@ -256,7 +260,6 @@ multi_column    | users      | oid         | public       | t1
 self_reference  | users      | uid         | public       | users                 | id                     | public                 | a            | c
 `))
 				m.noChecks()
-				m.noEnums()
 			},
 			expect: func(require *require.Assertions, t *schema.Table, err error) {
 				require.NoError(err)
@@ -281,15 +284,16 @@ self_reference  | users      | uid         | public       | users
 		{
 			name: "check",
 			before: func(m mock) {
+				m.noEnums()
 				m.tableExists("public", "users", true)
 				m.ExpectQuery(queryColumns).
 					WithArgs("public", "users").
 					WillReturnRows(sqltest.Rows(`
-table_name |column_name | data_type | formatted | is_nullable | column_default | character_maximum_length | numeric_precision | datetime_precision | numeric_scale | interval_type | character_set_name | collation_name | is_identity | identity_start | identity_increment |   identity_last  | identity_generation | generation_expression | comment | typtype | typelem | elemtyp | oid
------------+------------+-----------+-----------+-------------+----------------+--------------------------+-------------------+--------------------+---------------+---------------+--------------------+----------------+-------------+----------------+--------------------+------------------+---------------------+-----------------------+---------+---------+---------+---------+-----
-users      | c1         | integer   | int4      | NO          |                |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |  23
-users      | c2         | integer   | int4      | NO          |                |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |  23
-users      | c3         | integer   | int4      | NO          |                |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |  23
+table_name |column_name | data_type | formatted | is_nullable | column_default | character_maximum_length | numeric_precision | datetime_precision | numeric_scale | interval_type | character_set_name | collation_name | is_identity | identity_start | identity_increment |   identity_last  | identity_generation | generation_expression | comment | typtype | typelem | oid
+-----------+------------+-----------+-----------+-------------+----------------+--------------------------+-------------------+--------------------+---------------+---------------+--------------------+----------------+-------------+----------------+--------------------+------------------+---------------------+-----------------------+---------+---------+---------+-----
+users      | c1         | integer   | int4      | NO          |                |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  23
+users      | c2         | integer   | int4      | NO          |                |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  23
+users      | c3         | integer   | int4      | NO          |                |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  23
 `))
 				m.noIndexes()
 				m.noFKs()
@@ -307,7 +311,6 @@ users        | users_check1       | (((c2 + c1) + c3) > 10) | c2          | {2,1
 users        | users_check1       | (((c2 + c1) + c3) > 10) | c1          | {2,1,3}        | f
 users        | users_check1       | (((c2 + c1) + c3) > 10) | c3          | {2,1,3}        | f
 `))
-				m.noEnums()
 			},
 			expect: func(require *require.Assertions, t *schema.Table, err error) {
 				require.NoError(err)
@@ -337,6 +340,7 @@ users        | users_check1       | (((c2 + c1) + c3) > 10) | c3          | {2,1
 			var drv migrate.Driver
 			drv, err = Open(db)
 			require.NoError(t, err)
+			drv.(*Driver).schema = "public"
 			mk.ExpectQuery(sqltest.Escape(fmt.Sprintf(schemasQueryArgs, "= $1"))).
 				WithArgs("public").
 				WillReturnRows(sqltest.Rows(`
@@ -367,6 +371,7 @@ func TestDriver_InspectPartitionedTable(t *testing.T) {
 -------------+---------
  public      | nil
 `))
+	mk.noEnums()
 	m.ExpectQuery(sqltest.Escape(fmt.Sprintf(tablesQuery, "$1"))).
 		WithArgs("public").
 		WillReturnRows(sqltest.Rows(`
@@ -380,13 +385,13 @@ func TestDriver_InspectPartitionedTable(t *testing.T) {
 	m.ExpectQuery(sqltest.Escape(fmt.Sprintf(columnsQuery, "$2, $3, $4"))).
 		WithArgs("public", "logs1", "logs2", "logs3").
 		WillReturnRows(sqltest.Rows(`
-table_name |column_name | data_type | formatted | is_nullable | column_default | character_maximum_length | numeric_precision | datetime_precision | numeric_scale | interval_type | character_set_name | collation_name | is_identity | identity_start | identity_increment |   identity_last  | identity_generation | generation_expression | comment | typtype | typelem | elemtyp | oid
------------+------------+-----------+-----------+-------------+----------------+--------------------------+-------------------+--------------------+---------------+---------------+--------------------+----------------+-------------+----------------+--------------------+------------------+---------------------+-----------------------+---------+---------+---------+---------+-----
-logs1      | c1         | integer   | integer   | NO          |                |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |  23
-logs2      | c2         | integer   | integer   | NO          |                |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |  23
-logs2      | c3         | integer   | integer   | NO          |                |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |  23
-logs3      | c4         | integer   | integer   | NO          |                |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |  23
-logs3      | c5         | integer   | integer   | NO          |                |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |         |  23
+table_name |column_name | data_type | formatted | is_nullable | column_default | character_maximum_length | numeric_precision | datetime_precision | numeric_scale | interval_type | character_set_name | collation_name | is_identity | identity_start | identity_increment |   identity_last  | identity_generation | generation_expression | comment | typtype | typelem |  oid
+-----------+------------+-----------+-----------+-------------+----------------+--------------------------+-------------------+--------------------+---------------+---------------+--------------------+----------------+-------------+----------------+--------------------+------------------+---------------------+-----------------------+---------+---------+---------+------
+logs1      | c1         | integer   | integer   | NO          |                |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   23
+logs2      | c2         | integer   | integer   | NO          |                |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   23
+logs2      | c3         | integer   | integer   | NO          |                |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   23
+logs3      | c4         | integer   | integer   | NO          |                |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   23
+logs3      | c5         | integer   | integer   | NO          |                |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   23
 `))
 	m.ExpectQuery(sqltest.Escape(fmt.Sprintf(indexesAbove15, "$2, $3, $4"))).
 		WillReturnRows(sqlmock.NewRows([]string{"table_name", "index_name", "column_name", "primary", "unique", "constraint_type", "predicate", "expression", "options", "indnullsnotdistinct"}))
@@ -394,7 +399,6 @@ logs3      | c5         | integer   | integer   | NO          |                |
 		WillReturnRows(sqlmock.NewRows([]string{"constraint_name", "table_name", "column_name", "referenced_table_name", "referenced_column_name", "referenced_table_schema", "update_rule", "delete_rule"}))
 	m.ExpectQuery(sqltest.Escape(fmt.Sprintf(checksQuery, "$2, $3, $4"))).
 		WillReturnRows(sqlmock.NewRows([]string{"table_name", "constraint_name", "expression", "column_name", "column_indexes"}))
-	mk.noEnums()
 	s, err := drv.InspectSchema(context.Background(), "", &schema.InspectOptions{
 		Mode: schema.InspectSchemas | schema.InspectTables,
 	})
@@ -445,16 +449,17 @@ cockroach
 -------------+---------
  public      | nil
 `))
+	mk.noEnums()
 	mk.tableExists("public", "users", true)
 	mk.ExpectQuery(queryCRDBColumns).
 		WithArgs("public", "users").
 		WillReturnRows(sqltest.Rows(`
-table_name  | column_name | data_type | formatted | is_nullable |              column_default               | character_maximum_length | numeric_precision | datetime_precision | numeric_scale | interval_type | character_set_name | collation_name | is_identity | identity_start | identity_increment |   identity_last  |  identity_generation  | generation_expression | comment | typtype | typelem | elemtyp | oid 
-------------+-------------+-----------+-----------+-------------+-------------------------------------------+--------------------------+-------------------+--------------------+---------------+---------------+--------------------+----------------|-------------+----------------+--------------------+------------------+-----------------------+-----------------------+---------+---------+---------+---------+-----
-users       | a           | bigint    | bigint    | NO          |                                           |                          |                64 |                    |             0 |               |                    |                | NO          |                |                    |                  |                       |                       |         | b       |         |         | 20 
-users       | b           | bigint    | bigint    | NO          |                                           |                          |                64 |                    |             0 |               |                    |                | NO          |                |                    |                  |                       |                       |         | b       |         |         | 20 
-users       | c           | bigint    | bigint    | NO          |                                           |                          |                64 |                    |             0 |               |                    |                | NO          |                |                    |                  |                       |                       |         | b       |         |         | 20 
-users       | d           | bigint    | bigint    | NO          |                                           |                          |                64 |                    |             0 |               |                    |                | NO          |                |                    |                  |                       |                       |         | b       |         |         | 20 
+table_name  | column_name | data_type | formatted | is_nullable |              column_default               | character_maximum_length | numeric_precision | datetime_precision | numeric_scale | interval_type | character_set_name | collation_name | is_identity | identity_start | identity_increment |   identity_last  |  identity_generation  | generation_expression | comment | typtype | typelem | oid 
+------------+-------------+-----------+-----------+-------------+-------------------------------------------+--------------------------+-------------------+--------------------+---------------+---------------+--------------------+----------------|-------------+----------------+--------------------+------------------+-----------------------+-----------------------+---------+---------+---------+-----
+users       | a           | bigint    | bigint    | NO          |                                           |                          |                64 |                    |             0 |               |                    |                | NO          |                |                    |                  |                       |                       |         | b       |         | 20 
+users       | b           | bigint    | bigint    | NO          |                                           |                          |                64 |                    |             0 |               |                    |                | NO          |                |                    |                  |                       |                       |         | b       |         | 20 
+users       | c           | bigint    | bigint    | NO          |                                           |                          |                64 |                    |             0 |               |                    |                | NO          |                |                    |                  |                       |                       |         | b       |         | 20 
+users       | d           | bigint    | bigint    | NO          |                                           |                          |                64 |                    |             0 |               |                    |                | NO          |                |                    |                  |                       |                       |         | b       |         | 20 
 `))
 	mk.ExpectQuery(queryCRDBIndexes).
 		WithArgs("public", "users").
@@ -471,7 +476,6 @@ users       | idx5       | c           | false   | false  |                 | CR
 `))
 	mk.noFKs()
 	mk.noChecks()
-	mk.noEnums()
 	s, err := drv.InspectSchema(context.Background(), "public", &schema.InspectOptions{
 		Mode: schema.InspectSchemas | schema.InspectTables,
 	})
@@ -512,10 +516,10 @@ func TestDriver_InspectSchema(t *testing.T) {
 -------------+---------
  test        | boring
 `))
+	mk.noEnums()
 	m.ExpectQuery(sqltest.Escape(fmt.Sprintf(tablesQuery, "$1"))).
 		WithArgs("test").
 		WillReturnRows(sqlmock.NewRows([]string{"table_schema", "table_name", "comment", "partition_attrs", "partition_strategy", "partition_exprs"}))
-	mk.noEnums()
 	s, err := drv.InspectSchema(context.Background(), "", &schema.InspectOptions{
 		Mode: schema.InspectSchemas | schema.InspectTables,
 	})
@@ -545,11 +549,11 @@ func TestDriver_Realm(t *testing.T) {
  test        | nil
  public      | nil
 `))
+	m.ExpectQuery(sqltest.Escape(fmt.Sprintf(enumsQuery, "$1, $2"))).
+		WillReturnRows(sqlmock.NewRows([]string{"schema_name", "enum_name", "comment", "enum_type", "enum_value"}))
 	m.ExpectQuery(sqltest.Escape(fmt.Sprintf(tablesQuery, "$1, $2"))).
 		WithArgs("test", "public").
 		WillReturnRows(sqlmock.NewRows([]string{"table_schema", "table_name", "comment", "partition_attrs", "partition_strategy", "partition_exprs"}))
-	m.ExpectQuery(sqltest.Escape(fmt.Sprintf(enumsQuery, "$1, $2"))).
-		WillReturnRows(sqlmock.NewRows([]string{"schema_name", "enum_name", "comment", "enum_type", "enum_value"}))
 	realm, err := drv.InspectRealm(context.Background(), &schema.InspectRealmOption{
 		Mode: schema.InspectSchemas | schema.InspectTables,
 	})
@@ -578,11 +582,11 @@ func TestDriver_Realm(t *testing.T) {
  test        | nil
  public      | nil
 `))
+	m.ExpectQuery(sqltest.Escape(fmt.Sprintf(enumsQuery, "$1, $2"))).
+		WillReturnRows(sqlmock.NewRows([]string{"schema_name", "enum_name", "comment", "enum_type", "enum_value"}))
 	m.ExpectQuery(sqltest.Escape(fmt.Sprintf(tablesQuery, "$1, $2"))).
 		WithArgs("test", "public").
 		WillReturnRows(sqlmock.NewRows([]string{"table_schema", "table_name", "comment", "partition_attrs", "partition_strategy", "partition_exprs"}))
-	m.ExpectQuery(sqltest.Escape(fmt.Sprintf(enumsQuery, "$1, $2"))).
-		WillReturnRows(sqlmock.NewRows([]string{"schema_name", "enum_name", "comment", "enum_type", "enum_value"}))
 	realm, err = drv.InspectRealm(context.Background(), &schema.InspectRealmOption{
 		Schemas: []string{"test", "public"},
 		Mode:    schema.InspectSchemas | schema.InspectTables,
@@ -611,10 +615,10 @@ func TestDriver_Realm(t *testing.T) {
 -------------+---------
  test        | nil
 `))
+	mk.noEnums()
 	m.ExpectQuery(sqltest.Escape(fmt.Sprintf(tablesQuery, "$1"))).
 		WithArgs("test").
 		WillReturnRows(sqlmock.NewRows([]string{"table_schema", "table_name", "comment", "partition_attrs", "partition_strategy", "partition_exprs"}))
-	mk.noEnums()
 	realm, err = drv.InspectRealm(context.Background(), &schema.InspectRealmOption{
 		Schemas: []string{"test"},
 		Mode:    schema.InspectSchemas | schema.InspectTables,