diff --git a/docs/howto/analyze.md b/docs/howto/analyze.md index 325acbd6f6..09784d2217 100644 --- a/docs/howto/analyze.md +++ b/docs/howto/analyze.md @@ -71,7 +71,7 @@ reports the result columns and parameters: { "name": "id", "type": { - "name": "bigserial" + "name": "bigint" }, "table": "authors" }, @@ -97,7 +97,7 @@ reports the result columns and parameters: "column": { "name": "id", "type": { - "name": "bigserial" + "name": "bigint" }, "table": "authors" } @@ -109,10 +109,20 @@ reports the result columns and parameters: A column's `type` is written as a call expression: a `name` applied to `args`, each of which carries an optional `label` and exactly one of `type`, -`int`, `bool` or `string`, with `nullable` set at whatever depth it applies. -An array of text is `array` applied to `text`; a `Map(String, Nullable(UInt8))` -in ClickHouse is `map` applied to `string` and a nullable `uint8`. Names are -recorded as the engine reports them. +`int`, `bool`, `string` or `ident`, with `nullable` set at whatever depth it +applies. A `numeric(10,2)` column is `numeric` applied to `10` and `2`; an +array of text is `array` applied to `text`, and an array of arrays nests +one `array` per dimension; a `Map(String, Nullable(UInt8))` in ClickHouse is +`map` applied to `string` and a nullable `uint8`; a `STRUCT` in +GoogleSQL is `struct` applied to an `int64` labelled `a`; the `MAX` of SQL +Server's `nvarchar(max)` is the identifier `max`. + +Types are reported the way the engine itself stores and reports them rather +than the way the schema spelled them: PostgreSQL's `int` and `bigserial` are +`integer` and `bigint`, as `format_type` prints them; MySQL's `BOOLEAN` is +`tinyint(1)`; ClickHouse's `Decimal32(4)` is `decimal(9, 4)`; DuckDB's +`TEXT` is `varchar`; SQL Server's `FLOAT(24)` is `real`. SQLite, which +keeps a declared type as written, is reported as written. Pass `--ast` to also include each statement's parsed AST under an `ast` key. It has the same shape as the output of [`parse`](parse.md), with every node tagged diff --git a/internal/codegen/golang/postgresql_type.go b/internal/codegen/golang/postgresql_type.go index 048c8533d7..3bdfed6a1a 100644 --- a/internal/codegen/golang/postgresql_type.go +++ b/internal/codegen/golang/postgresql_type.go @@ -216,7 +216,7 @@ func postgresType(req *plugin.GenerateRequest, options *opts.Options, col *plugi } return "sql.NullTime" - case "pg_catalog.time": + case "pg_catalog.time", "time", "time without time zone": if driver == opts.SQLDriverPGXV5 { return "pgtype.Time" } @@ -228,7 +228,7 @@ func postgresType(req *plugin.GenerateRequest, options *opts.Options, col *plugi } return "sql.NullTime" - case "pg_catalog.timetz": + case "pg_catalog.timetz", "timetz", "time with time zone": if notNull { return "time.Time" } @@ -237,7 +237,7 @@ func postgresType(req *plugin.GenerateRequest, options *opts.Options, col *plugi } return "sql.NullTime" - case "pg_catalog.timestamp", "timestamp": + case "pg_catalog.timestamp", "timestamp", "timestamp without time zone": if driver == opts.SQLDriverPGXV5 { return "pgtype.Timestamp" } @@ -249,7 +249,7 @@ func postgresType(req *plugin.GenerateRequest, options *opts.Options, col *plugi } return "sql.NullTime" - case "pg_catalog.timestamptz", "timestamptz": + case "pg_catalog.timestamptz", "timestamptz", "timestamp with time zone": if driver == opts.SQLDriverPGXV5 { return "pgtype.Timestamptz" } @@ -261,7 +261,7 @@ func postgresType(req *plugin.GenerateRequest, options *opts.Options, col *plugi } return "sql.NullTime" - case "text", "pg_catalog.varchar", "pg_catalog.bpchar", "string", "citext", "name": + case "text", "pg_catalog.varchar", "varchar", "character varying", "pg_catalog.bpchar", "bpchar", "character", "string", "citext", "name": if notNull { return "string" } @@ -470,7 +470,7 @@ func postgresType(req *plugin.GenerateRequest, options *opts.Options, col *plugi } return "any" - case "bit", "varbit", "pg_catalog.bit", "pg_catalog.varbit": + case "bit", "varbit", "bit varying", "pg_catalog.bit", "pg_catalog.varbit": if driver == opts.SQLDriverPGXV5 { return "pgtype.Bits" } diff --git a/internal/compiler/catalog_core.go b/internal/compiler/catalog_core.go index ce89416926..7f2e2624fe 100644 --- a/internal/compiler/catalog_core.go +++ b/internal/compiler/catalog_core.go @@ -32,19 +32,25 @@ func coreResultCatalog(c *core.Catalog) (*catalog.Catalog, error) { } t := &catalog.Table{Rel: &ast.TableName{Schema: ns.Name, Name: table.Name}} for _, col := range cols { - // The catalog names an array type after its element with the - // suffix appended, which is codegen's data type and array - // flag in one string. The core catalog holds one dimension, - // and codegen renders a "[]" per dimension. - dataType, isArray := strings.CutSuffix(col.TypeName, core.ArraySuffix) + // Codegen reads a data type and an array flag, and renders + // a "[]" per dimension, so an array of arrays of integers + // is the type integer with two dimensions. + expr, err := c.TypeExprOf(col.TypeOID) + if err != nil { + return nil, err + } + inner := expr.Innermost() column := &catalog.Column{ - Name: col.Name, - Type: ast.TypeName{Name: dataType}, - IsNotNull: col.NotNull, - IsArray: isArray, + Name: col.Name, + Type: ast.TypeName{Name: strings.TrimSuffix(inner.Name, " unsigned")}, + IsNotNull: col.NotNull, + IsArray: expr.IsArray(), + ArrayDims: expr.ArrayDims(), + IsUnsigned: strings.HasSuffix(inner.Name, " unsigned"), } - if isArray { - column.ArrayDims = 1 + if len(inner.Args) > 0 && inner.Args[0].Int != nil { + l := int(*inner.Args[0].Int) + column.Length = &l } t.Columns = append(t.Columns, column) } diff --git a/internal/compiler/parse_core.go b/internal/compiler/parse_core.go index 7e5685a962..4c36d7d08c 100644 --- a/internal/compiler/parse_core.go +++ b/internal/compiler/parse_core.go @@ -107,21 +107,33 @@ func coreColumn(c core.Column) *Column { IsArray: c.IsArray, TypeExpr: c.Type, } - // The core reports arrays without dimensions, and codegen renders one - // "[]" per dimension. - if c.IsArray { - col.ArrayDims = 1 - } + describeType(col, c.Type) if c.Source != nil && c.Source.Table != "" { col.Table = &ast.TableName{Schema: c.Source.Schema, Name: c.Source.Table} col.TableAlias = c.Source.TableAlias col.OriginalName = c.Source.Column } - if c.TypeLength > 0 { - l := c.TypeLength + return col +} + +// describeType fills in what codegen reads about a type from its +// expression: one array dimension per nesting, the length that is the +// innermost type's first integer argument (which is how a MySQL tinyint(1) +// is told from a tinyint), and whether the innermost type is unsigned. +func describeType(col *Column, t *core.TypeExpr) { + if t == nil { + if col.IsArray { + col.ArrayDims = 1 + } + return + } + col.ArrayDims = t.ArrayDims() + inner := t.Innermost() + if len(inner.Args) > 0 && inner.Args[0].Int != nil { + l := int(*inner.Args[0].Int) col.Length = &l } - return col + col.Unsigned = strings.HasSuffix(inner.Name, " unsigned") } func coreParamColumn(p core.Parameter, params *named.ParamSet) *Column { @@ -132,9 +144,7 @@ func coreParamColumn(p core.Parameter, params *named.ParamSet) *Column { IsArray: p.IsArray, TypeExpr: p.Type, } - if p.IsArray { - col.ArrayDims = 1 - } + describeType(col, p.Type) if p.Source != nil && p.Source.Table != "" { col.Table = &ast.TableName{Schema: p.Source.Schema, Name: p.Source.Table} col.OriginalName = p.Source.Column diff --git a/internal/core/analysis.go b/internal/core/analysis.go index 7542d12b1e..b0854bf457 100644 --- a/internal/core/analysis.go +++ b/internal/core/analysis.go @@ -65,8 +65,6 @@ type Column struct { SourceAttributeOID int64 `json:"source_attribute_oid,omitempty"` Source *ColumnSource `json:"source,omitempty"` DeclType string `json:"decl_type,omitempty"` - TypeLength int `json:"type_length,omitempty"` - TypeScale int `json:"type_scale,omitempty"` IsPrimaryKey bool `json:"is_primary_key,omitempty"` IsUnique bool `json:"is_unique,omitempty"` IsAutoIncrement bool `json:"is_auto_increment,omitempty"` diff --git a/internal/core/analyzer/analyzer.go b/internal/core/analyzer/analyzer.go index 8bc92bf5b3..98076c429a 100644 --- a/internal/core/analyzer/analyzer.go +++ b/internal/core/analyzer/analyzer.go @@ -112,6 +112,7 @@ func derivedRel(alias string, cols []core.Column) scopeRel { AttOID: col.SourceAttributeOID, Name: col.Name, TypeOID: col.TypeOID, + Type: col.Type.WithNullable(false), NotNull: col.NotNull, }) } @@ -123,12 +124,12 @@ func (a *analyzer) result() core.PrepareResult { // the dialect has such a type. if oid, ok := a.cat.UntypedTypeOID(); ok { for n, p := range a.params { - if p.TypeOID == 0 && p.DataType == "" { + if p.TypeOID == 0 && p.Type == nil { t := exprType{typeOID: oid, nullable: true} p.TypeOID = oid p.DataType, p.IsArray = a.typeNameOf(t) p.NotNull = false - p.Type = a.typeExprOf(t, "") + p.Type = a.typeExprOf(t) a.params[n] = p } } diff --git a/internal/core/analyzer/dml.go b/internal/core/analyzer/dml.go index 28cbc5193c..8f188b82da 100644 --- a/internal/core/analyzer/dml.go +++ b/internal/core/analyzer/dml.go @@ -202,6 +202,7 @@ func findColumn(rel scopeRel, name string) (core.ClassColumn, bool) { func columnType(rel scopeRel, col core.ClassColumn) exprType { return exprType{ typeOID: col.TypeOID, + expr: col.Type, nullable: !col.NotNull, sourceClassOID: rel.classOID, sourceAttributeOID: col.AttOID, diff --git a/internal/core/analyzer/expr.go b/internal/core/analyzer/expr.go index 904993e703..8305222c80 100644 --- a/internal/core/analyzer/expr.go +++ b/internal/core/analyzer/expr.go @@ -2,6 +2,7 @@ package analyzer import ( "fmt" + "slices" "strings" "github.com/sqlc-dev/sqlc/internal/core" @@ -9,12 +10,16 @@ import ( ) type exprType struct { + // typeOID is the type's row: the instance when the catalog holds one, + // else the family, else 0 for a type no dialect seeded and no schema + // declared. typeOID int64 - // typeName names a type the catalog does not hold — a cast to a type no - // dialect seeded and no schema declared, or an array of one. Analysis - // never adds a type: it reports the name the query used and carries on, - // so a query can be analyzed against a catalog it cannot write to. - typeName string + // expr is the whole expression when it says more than the row does — a + // cast to numeric(5, 1) when only numeric is a row — or names a type + // the catalog does not hold. Analysis never adds a type: it reports the + // expression the query used and carries on, so a query can be analyzed + // against a catalog it cannot write to. + expr *core.TypeExpr nullable bool sourceClassOID int64 sourceAttributeOID int64 @@ -156,6 +161,14 @@ func (a *analyzer) typeColumnRef(c *ast.ColumnRef) (exprType, error) { if err != nil { return exprType{}, err } + // A dotted name may be a column's own, as ClickHouse names the columns + // a Nested column stores as n.a. + if !ok && relation != "" { + rel, col, ok, err = a.resolveColumn("", relation+"."+column) + if err != nil { + return exprType{}, err + } + } if !ok { if relation != "" { return exprType{}, fmt.Errorf("unknown column %q.%q", relation, column) @@ -167,13 +180,7 @@ func (a *analyzer) typeColumnRef(c *ast.ColumnRef) (exprType, error) { } return exprType{}, fmt.Errorf("unknown column %q", column) } - return exprType{ - typeOID: col.TypeOID, - nullable: !col.NotNull, - sourceClassOID: rel.classOID, - sourceAttributeOID: col.AttOID, - sourceTableAlias: rel.alias, - }, nil + return columnType(rel, col), nil } func flattenFields(fields *ast.List) []string { @@ -196,10 +203,10 @@ func flattenFields(fields *ast.List) []string { func (a *analyzer) typeParamRef(p *ast.ParamRef) (exprType, error) { cur, ok := a.params[p.Number] if !ok { - cur = core.Parameter{Number: p.Number} + cur = core.Parameter{Number: p.Number, Name: p.Name} a.params[p.Number] = cur } - return exprType{typeOID: cur.TypeOID, nullable: !cur.NotNull}, nil + return exprType{typeOID: cur.TypeOID, expr: cur.Type.WithNullable(false), nullable: !cur.NotNull}, nil } func (a *analyzer) inferParam(number int, t exprType) { @@ -207,12 +214,12 @@ func (a *analyzer) inferParam(number int, t exprType) { if !ok { cur = core.Parameter{Number: number} } - typed := cur.TypeOID == 0 && cur.DataType == "" && (t.typeOID != 0 || t.typeName != "") + typed := cur.TypeOID == 0 && cur.Type == nil && (t.typeOID != 0 || t.expr != nil) if typed { cur.TypeOID = t.typeOID cur.DataType, cur.IsArray = a.typeNameOf(t) cur.NotNull = !t.nullable - cur.Type = a.typeExprOf(t, "") + cur.Type = a.typeExprOf(t) } if cur.Source == nil && t.sourceAttributeOID != 0 { ad, err := a.cat.LookupAttribute(t.sourceAttributeOID) @@ -223,9 +230,6 @@ func (a *analyzer) inferParam(number int, t exprType) { TableAlias: t.sourceTableAlias, Column: ad.Column, } - if typed { - cur.Type = a.typeExprOf(t, ad.DeclType) - } } } a.params[number] = cur @@ -300,14 +304,20 @@ func (a *analyzer) typeAExpr(e *ast.A_Expr) (exprType, error) { a.inferParam(pr.Number, rightT) a.nameParamAfter(pr.Number, e.Rexpr) leftT = rightT + } else if pr := castParamRef(e.Lexpr); pr != nil { + a.inferParam(pr.Number, rightT) + a.nameParamAfter(pr.Number, e.Rexpr) } if pr, ok := e.Rexpr.(*ast.ParamRef); ok && leftT.typeOID != 0 { a.inferParam(pr.Number, leftT) a.nameParamAfter(pr.Number, e.Lexpr) rightT = leftT + } else if pr := castParamRef(e.Rexpr); pr != nil { + a.inferParam(pr.Number, leftT) + a.nameParamAfter(pr.Number, e.Lexpr) } - overload, err := a.resolveOperator(opName, leftT.typeOID, rightT.typeOID) + overload, err := a.resolveOperator(opName, leftT, rightT) if err != nil { return exprType{}, err } @@ -320,6 +330,18 @@ func (a *analyzer) typeAExpr(e *ast.A_Expr) (exprType, error) { }, nil } +// castParamRef is the placeholder a cast wraps, as ClickHouse's {p:UInt64} +// is written, or nil. The cast has typed it already; what it is compared +// with still names it and says which column it stands in for. +func castParamRef(n ast.Node) *ast.ParamRef { + tc, ok := n.(*ast.TypeCast) + if !ok { + return nil + } + pr, _ := tc.Arg.(*ast.ParamRef) + return pr +} + // isNullTest reports whether an operator compares with NULL as a value // rather than propagating it, so that its result is never NULL. func isNullTest(opName string) bool { @@ -383,8 +405,8 @@ func (a *analyzer) typeIn(e *ast.In) (exprType, error) { if err != nil { return exprType{}, err } - if len(cols) > 0 { - if err := a.typeOperands(e.Expr, exprType{typeOID: cols[0].TypeOID, nullable: !cols[0].NotNull}); err != nil { + if pr, ok := e.Expr.(*ast.ParamRef); ok && len(cols) > 0 { + if err := a.typeOperands(pr, columnExprType(cols[0])); err != nil { return exprType{}, err } } @@ -450,9 +472,9 @@ func (a *analyzer) typeCoalesce(e *ast.CoalesceExpr) (exprType, error) { if err != nil { return exprType{}, err } - if !found && t.typeOID != 0 { + if !found && (t.typeOID != 0 || t.expr != nil) { // The result is an expression's, not the column's it came from. - out = exprType{typeOID: t.typeOID, typeName: t.typeName} + out = exprType{typeOID: t.typeOID, expr: t.expr} found = true } nullable = nullable && t.nullable @@ -472,7 +494,7 @@ func (a *analyzer) typeFirstOf(nodes []ast.Node, nullable bool) (exprType, error if err != nil { return exprType{}, err } - if !found && t.typeOID != 0 { + if !found && (t.typeOID != 0 || t.expr != nil) { out = t found = true } @@ -488,36 +510,88 @@ func (a *analyzer) typeArrayExpr(e *ast.A_ArrayExpr) (exprType, error) { if err != nil { return exprType{}, err } - element, _ := a.typeNameOf(elemT) - if element == "" { + element := a.exprOf(elemT) + if element == nil { return exprType{}, nil } - return a.namedType(element + core.ArraySuffix), nil + return a.lookupType(core.Array(element.WithNullable(false))), nil +} + +// lookupType is the type an expression refers to: its row when the catalog +// holds one, its family's row when it holds only that, and the expression +// alone when it holds neither. +func (a *analyzer) lookupType(t *core.TypeExpr) exprType { + if t == nil { + return exprType{} + } + found, ok := a.cat.LookupTypeExpr(t) + if !ok { + return exprType{expr: t.WithNullable(false)} + } + out := exprType{typeOID: found.OID} + if found.OID == found.FamilyOID && len(found.Expr.Args) > 0 { + out.expr = found.Expr + } + return out } // namedType is the type a name refers to, or the name itself when the catalog // has no such type. func (a *analyzer) namedType(name string) exprType { - if oid, err := a.cat.TypeOID(name); err == nil { - return exprType{typeOID: oid} - } - return exprType{typeName: name} + return a.lookupType(core.ParseTypeExpr(name)) } -// typeNameOf reports a type's name and whether it is an array of that name, -// whether the type is one the catalog holds or one only the query named. -func (a *analyzer) typeNameOf(t exprType) (string, bool) { - name := t.typeName - if t.typeOID != 0 { - var err error - if name, err = a.cat.TypeName(t.typeOID); err != nil { - return "", false - } +// exprOf is a type's expression: the one the analysis carries, or the one +// its row stands for. It is a copy, and nil for an untyped expression. +func (a *analyzer) exprOf(t exprType) *core.TypeExpr { + if t.expr != nil { + return t.expr.Clone() } - if element, ok := strings.CutSuffix(name, core.ArraySuffix); ok { - return element, true + if t.typeOID == 0 { + return nil } - return name, false + e, err := a.cat.TypeExprOf(t.typeOID) + if err != nil { + return nil + } + return e +} + +// typeExprOf writes a type as the expression a result reports, with the +// expression's own nullability set from the analysis. +func (a *analyzer) typeExprOf(t exprType) *core.TypeExpr { + e := a.exprOf(t) + if e == nil { + return nil + } + e.Nullable = t.nullable + return e +} + +// typeNameOf reports a type's innermost family name and whether the type is +// an array, which is the flat view the legacy compiler reads. +func (a *analyzer) typeNameOf(t exprType) (string, bool) { + e := a.exprOf(t) + if e == nil { + return "", false + } + // MySQL's unsigned families are their own types, but codegen reads + // the signed family and an unsigned flag, which the bridge derives + // from the expression. + return strings.TrimSuffix(e.Innermost().Name, " unsigned"), e.IsArray() +} + +// columnExprType is the type a result column of a nested query has, as an +// operand of the query around it. +func columnExprType(col core.Column) exprType { + return exprType{typeOID: col.TypeOID, expr: col.Type.WithNullable(false), nullable: !col.NotNull} +} + +// familyOID is the row everything about a type is registered on: the end of +// its resolution chain. +func (a *analyzer) familyOID(oid int64) int64 { + chain := a.cat.ResolutionChain(oid) + return chain[len(chain)-1] } // typeSubLink types a subquery used as an expression: EXISTS and IN yield a @@ -543,7 +617,9 @@ func (a *analyzer) typeSubLink(e *ast.SubLink) (exprType, error) { return exprType{nullable: true}, nil } // A subquery that matches no row yields NULL. - return exprType{typeOID: cols[0].TypeOID, nullable: true}, nil + t := columnExprType(cols[0]) + t.nullable = true + return t, nil default: return a.boolType(false) } @@ -586,7 +662,12 @@ func (a *analyzer) typeNullIf(e *ast.A_Expr) (exprType, error) { // placeholder that type. func (a *analyzer) typeOperands(n ast.Node, other exprType) error { if pr, ok := n.(*ast.ParamRef); ok { - if other.typeOID != 0 || other.typeName != "" { + // Registering the placeholder first keeps the name its syntax gave + // it, as ClickHouse's {name:Type} does. + if _, err := a.typeParamRef(pr); err != nil { + return err + } + if other.typeOID != 0 || other.expr != nil { a.inferParam(pr.Number, other) } return nil @@ -620,19 +701,36 @@ func opNameFromList(l *ast.List) string { return strings.Join(parts, ".") } -func (a *analyzer) resolveOperator(name string, leftOID, rightOID int64) (core.OperatorOverload, error) { - candidates, err := a.cat.FindOperators(name, leftOID, rightOID) +// resolveOperator finds the overload of an operator over two operand types. +// An operator is registered on a family, so an operand that is an instance, +// an alias or a domain is looked up along its resolution chain: numeric(10, +// 2) + numeric(5, 1) resolves on numeric. +func (a *analyzer) resolveOperator(name string, leftT, rightT exprType) (core.OperatorOverload, error) { + leftChain := a.cat.ResolutionChain(leftT.typeOID) + rightChain := a.cat.ResolutionChain(rightT.typeOID) + all, err := a.cat.FindOperators(name, 0, 0) if err != nil { return core.OperatorOverload{}, err } - if len(candidates) > 0 { - return candidates[0], nil + // The operator's overloads are read once; the pairs along the two + // chains are tried against them in order, nearest first. + byOperands := make(map[[2]int64]core.OperatorOverload, len(all)) + for _, ov := range all { + key := [2]int64{ov.LeftTypeOID, ov.RightTypeOID} + if _, seen := byOperands[key]; !seen { + byOperands[key] = ov + } } - - all, err := a.cat.FindOperators(name, 0, 0) - if err != nil { - return core.OperatorOverload{}, err + for _, l := range leftChain { + for _, r := range rightChain { + if ov, ok := byOperands[[2]int64{l, r}]; ok && l != 0 && r != 0 { + return ov, nil + } + } } + leftOID := leftChain[len(leftChain)-1] + rightOID := rightChain[len(rightChain)-1] + for _, ov := range all { if leftOID != 0 && ov.LeftTypeOID != 0 && leftOID != ov.LeftTypeOID { ok, _ := a.cat.CastAllowed(leftOID, ov.LeftTypeOID, "i") @@ -693,7 +791,7 @@ func (a *analyzer) typeFuncCall(f *ast.FuncCall) (exprType, error) { if overloads, err := a.cat.FindProcs("count", nil); err == nil && len(overloads) > 0 { return exprType{typeOID: overloads[0].ReturnTypeOID, nullable: overloads[0].ReturnNullable}, nil } - oid, err := a.cat.TypeOID("int8") + oid, err := a.cat.TypeOID("bigint") if err != nil { return exprType{}, err } @@ -739,6 +837,11 @@ func (a *analyzer) typeFuncCall(f *ast.FuncCall) (exprType, error) { } } ret := a.returnType(p, argTypes) + // A result that depends on an argument's value is spelled by the seed + // as a template over the arguments, filled in from the call. + if computed := a.returnTemplate(p, args, argTypes); computed != nil { + ret = a.lookupType(computed) + } ret.nullable = p.ReturnNullable if !p.NeverNull && anyNullable && a.cat.PropagatesNullable() { ret.nullable = true @@ -746,6 +849,48 @@ func (a *analyzer) typeFuncCall(f *ast.FuncCall) (exprType, error) { return ret, nil } +// returnTemplate fills a seed's return template — Decimal(18, $2) — from +// the call: a $n that stands for an integer literal takes its value, and +// one that stands for a typed argument takes its type. A template that +// cannot be filled leaves the answer to the catalog. +func (a *analyzer) returnTemplate(p core.ProcOverload, args []ast.Node, argTypes []exprType) *core.TypeExpr { + if p.ReturnTemplate == "" { + return nil + } + template := core.ParseTypeExpr(p.ReturnTemplate) + fill := func(arg core.TypeArg) (core.TypeArg, bool) { + n, ok := argIndex(arg.Type.Name) + if !ok || n >= len(args) { + return core.TypeArg{}, false + } + if c, ok := args[n].(*ast.A_Const); ok { + if lit, ok := c.Val.(*ast.Integer); ok { + v := lit.Ival + return core.TypeArg{Label: arg.Label, Int: &v}, true + } + if lit, ok := c.Val.(*ast.String); ok { + v := lit.Str + return core.TypeArg{Label: arg.Label, String: &v}, true + } + } + if t := a.exprOf(argTypes[n]); t != nil { + return core.TypeArg{Label: arg.Label, Type: t.WithNullable(false)}, true + } + return core.TypeArg{}, false + } + for i, arg := range template.Args { + if arg.Type == nil || !strings.HasPrefix(arg.Type.Name, "$") { + continue + } + filled, ok := fill(arg) + if !ok { + return nil + } + template.Args[i] = filled + } + return template +} + // returnType resolves a polymorphic return type — max(anyelement), or a // seed's "$2" for the type of the second argument — to the type the call was // made with. @@ -759,12 +904,12 @@ func (a *analyzer) returnType(p core.ProcOverload, argTypes []exprType) exprType } if n, ok := argIndex(name); ok { if n < len(argTypes) { - return exprType{typeOID: argTypes[n].typeOID, typeName: argTypes[n].typeName} + return exprType{typeOID: argTypes[n].typeOID, expr: argTypes[n].expr} } return exprType{} } - if isPolymorphic(name) && argTypes[0].typeOID != 0 { - return exprType{typeOID: argTypes[0].typeOID} + if isPolymorphic(name) && (argTypes[0].typeOID != 0 || argTypes[0].expr != nil) { + return exprType{typeOID: argTypes[0].typeOID, expr: argTypes[0].expr} } return exprType{typeOID: p.ReturnTypeOID} } @@ -815,12 +960,19 @@ func isPolymorphic(typeName string) bool { } // pickOverload chooses the overload whose parameters the call's arguments -// match best: an exact type match on a parameter beats a polymorphic one, -// which beats a mismatch, and any overload of the right arity beats one of -// the wrong arity. +// match best: an exact type match on a parameter beats a match on the +// argument's family, which beats a polymorphic parameter, which beats a +// mismatch, and any overload of the right arity beats one of the wrong +// arity. func (a *analyzer) pickOverload(overloads []core.ProcOverload, argTypes []int64) core.ProcOverload { best := -1 bestScore := -1 + chains := make([][]int64, len(argTypes)) + for j, oid := range argTypes { + if oid != 0 { + chains[j] = a.cat.ResolutionChain(oid) + } + } for i := range overloads { ov := &overloads[i] if len(ov.ArgTypes) != len(argTypes) { @@ -830,6 +982,8 @@ func (a *analyzer) pickOverload(overloads []core.ProcOverload, argTypes []int64) for j, oid := range argTypes { switch { case oid != 0 && oid == ov.ArgTypes[j]: + score += 3 + case oid != 0 && slices.Contains(chains[j], ov.ArgTypes[j]): score += 2 case a.isPolymorphicOID(ov.ArgTypes[j]): score += 1 @@ -859,14 +1013,26 @@ func (a *analyzer) typeTypeCast(c *ast.TypeCast) (exprType, error) { if c.TypeName == nil { return exprType{}, fmt.Errorf("cast: missing target type") } - name := core.TypeNameString(c.TypeName) - if name == "" { + target := core.TypeExprOfTypeName(c.TypeName) + if target == nil { return exprType{}, fmt.Errorf("cast: missing target type") } - t := a.namedType(name) - // A cast is how a query says what an otherwise untyped placeholder holds. - if err := a.typeOperands(c.Arg, t); err != nil { + t := a.lookupType(target) + // A cast is how a query says what an otherwise untyped placeholder + // holds, and a placeholder so typed is not null unless the type says + // otherwise, as ClickHouse's Nullable(String) does. Anything else + // cast is NULL when it was NULL before, or when the type says so. + t.nullable = target.Nullable + if pr, ok := c.Arg.(*ast.ParamRef); ok { + if err := a.typeOperands(pr, t); err != nil { + return exprType{}, err + } + return t, nil + } + arg, err := a.typeExpr(c.Arg) + if err != nil { return exprType{}, err } + t.nullable = t.nullable || arg.nullable return t, nil } diff --git a/internal/core/analyzer/projection.go b/internal/core/analyzer/projection.go index f3293dcbc6..17fc3cbf47 100644 --- a/internal/core/analyzer/projection.go +++ b/internal/core/analyzer/projection.go @@ -2,6 +2,7 @@ package analyzer import ( "slices" + "strings" "github.com/sqlc-dev/sqlc/internal/core" "github.com/sqlc-dev/sqlc/internal/sql/ast" @@ -32,7 +33,7 @@ func (a *analyzer) projectTarget(rt *ast.ResTarget) error { a.params[pr.Number] = p } } - if t.typeOID == 0 && t.typeName == "" { + if t.typeOID == 0 && t.expr == nil { if oid, ok := a.cat.UntypedTypeOID(); ok { t = exprType{typeOID: oid, nullable: true} } @@ -46,9 +47,14 @@ func (a *analyzer) projectTarget(rt *ast.ResTarget) error { SourceAttributeOID: t.sourceAttributeOID, } col.DataType, col.IsArray = a.typeNameOf(t) + col.Type = a.typeExprOf(t) a.decorateSource(&col, t.sourceAttributeOID, t.sourceTableAlias) - col.Type = a.typeExprOf(t, col.DeclType) if rt.Name == nil || *rt.Name == "" { + // A column whose own name is dotted, as ClickHouse's n.a is, is + // reported under that name rather than its last part. + if col.Source != nil && strings.Contains(col.Source.Column, ".") { + col.Name = col.Source.Column + } a.qualifyDuplicate(&col, t.sourceTableAlias) } a.columns = append(a.columns, col) @@ -77,35 +83,6 @@ func (a *analyzer) qualifyDuplicate(col *core.Column, alias string) { } } -// typeExprOf writes a type as an expression. A source column's declared -// spelling carries what the catalog's flat name cannot, so it is parsed -// when there is one; otherwise the expression is the type's name, wrapped -// in an array when the type is one. Nullability comes from the spelling -// when the spelling says anything about it, and from the analysis -// otherwise. -func (a *analyzer) typeExprOf(t exprType, declType string) *core.TypeExpr { - name, isArray := a.typeNameOf(t) - if name == "" && declType == "" { - return nil - } - var expr *core.TypeExpr - if declType != "" { - expr = core.ParseTypeExpr(declType) - if isArray && expr.Name != "array" { - expr = &core.TypeExpr{Name: "array", Args: []core.TypeArg{{Type: expr}}} - } - } else { - expr = core.ParseTypeExpr(name) - if isArray { - expr = &core.TypeExpr{Name: "array", Args: []core.TypeArg{{Type: expr}}} - } - } - if !expr.HasNullable() { - expr.Nullable = t.nullable - } - return expr -} - func (a *analyzer) decorateSource(col *core.Column, attOID int64, tableAlias string) { if attOID == 0 { return @@ -121,8 +98,6 @@ func (a *analyzer) decorateSource(col *core.Column, attOID int64, tableAlias str Column: ad.Column, } col.DeclType = ad.DeclType - col.TypeLength = ad.TypeLength - col.TypeScale = ad.TypeScale col.IsPrimaryKey = ad.IsPrimaryKey col.IsUnique = ad.IsUnique col.IsAutoIncrement = ad.AutoIncrement @@ -177,9 +152,10 @@ func (a *analyzer) emitStar(rt *ast.ResTarget, fields []string) { SourceClassOID: rel.classOID, SourceAttributeOID: c.AttOID, } - col.DataType, col.IsArray = a.typeNameOf(exprType{typeOID: c.TypeOID}) + t := exprType{typeOID: c.TypeOID, expr: c.Type, nullable: !c.NotNull} + col.DataType, col.IsArray = a.typeNameOf(t) + col.Type = a.typeExprOf(t) a.decorateSource(&col, c.AttOID, rel.alias) - col.Type = a.typeExprOf(exprType{typeOID: c.TypeOID, nullable: !c.NotNull}, col.DeclType) a.qualifyDuplicate(&col, rel.alias) a.columns = append(a.columns, col) star.Columns = append(star.Columns, core.StarColumn{ diff --git a/internal/core/attribute.go b/internal/core/attribute.go index 7a0a58a4ac..9c2a927f5b 100644 --- a/internal/core/attribute.go +++ b/internal/core/attribute.go @@ -15,8 +15,6 @@ type AttributeSpec struct { NotNull bool HasDefault bool DeclType string - TypeLength int - TypeScale int AutoIncrement bool IsPrimaryKey bool IsUnique bool @@ -35,8 +33,6 @@ func (c *Catalog) CreateAttributeSpec(s AttributeSpec) error { HasDefault: boolToInt64(s.HasDefault), Num: int64(s.Num), DeclType: s.DeclType, - TypeLength: int64(s.TypeLength), - TypeScale: int64(s.TypeScale), AutoIncrement: boolToInt64(s.AutoIncrement), IsPrimaryKey: boolToInt64(s.IsPrimaryKey), IsUnique: boolToInt64(s.IsUnique), @@ -154,8 +150,6 @@ type ColumnInfo struct { TypeOID int64 NotNull bool DeclType string - TypeLength int - TypeScale int AutoIncrement bool IsPrimaryKey bool IsUnique bool @@ -179,8 +173,6 @@ func (c *Catalog) ResolveColumn(table, column string) (*ColumnInfo, error) { TypeOID: r.TypeOid, NotNull: r.NotNull != 0, DeclType: r.DeclType, - TypeLength: int(r.TypeLength), - TypeScale: int(r.TypeScale), AutoIncrement: r.AutoIncrement != 0, IsPrimaryKey: r.IsPrimaryKey != 0, IsUnique: r.IsUnique != 0, @@ -203,8 +195,6 @@ func (c *Catalog) TableColumns(table string) ([]ColumnInfo, error) { TypeOID: r.TypeOid, NotNull: r.NotNull != 0, DeclType: r.DeclType, - TypeLength: int(r.TypeLength), - TypeScale: int(r.TypeScale), AutoIncrement: r.AutoIncrement != 0, IsPrimaryKey: r.IsPrimaryKey != 0, IsUnique: r.IsUnique != 0, @@ -217,6 +207,10 @@ type ClassColumn struct { AttOID int64 Name string TypeOID int64 + // Type is the column's type as an expression, set for a column of a + // derived relation whose type the catalog holds no row for, or holds + // only the family of. + Type *TypeExpr NotNull bool Hidden bool } @@ -241,9 +235,9 @@ func (c *Catalog) ClassColumns(classOID int64) ([]ClassColumn, error) { } type CodegenColumn struct { - Name string - TypeName string - NotNull bool + Name string + TypeOID int64 + NotNull bool } func (c *Catalog) ClassCodegenColumns(classOID int64) ([]CodegenColumn, error) { @@ -254,9 +248,9 @@ func (c *Catalog) ClassCodegenColumns(classOID int64) ([]CodegenColumn, error) { out := make([]CodegenColumn, 0, len(rows)) for _, r := range rows { out = append(out, CodegenColumn{ - Name: r.ColumnName, - TypeName: r.TypeName, - NotNull: r.NotNull != 0, + Name: r.ColumnName, + TypeOID: r.TypeOid, + NotNull: r.NotNull != 0, }) } return out, nil @@ -268,8 +262,6 @@ type AttributeDetails struct { Column string Num int DeclType string - TypeLength int - TypeScale int AutoIncrement bool IsPrimaryKey bool IsUnique bool @@ -287,8 +279,6 @@ func (c *Catalog) LookupAttribute(attOID int64) (AttributeDetails, error) { Column: r.ColumnName, Num: int(r.Num), DeclType: r.DeclType, - TypeLength: int(r.TypeLength), - TypeScale: int(r.TypeScale), AutoIncrement: r.AutoIncrement != 0, IsPrimaryKey: r.IsPrimaryKey != 0, IsUnique: r.IsUnique != 0, diff --git a/internal/core/catalog.go b/internal/core/catalog.go index 68d05196e4..334dcdb787 100644 --- a/internal/core/catalog.go +++ b/internal/core/catalog.go @@ -28,6 +28,11 @@ type Catalog struct { // once per extension name: a schema is free to say CREATE EXTENSION twice. loadExtension func(name string) error extensions map[string]bool + + // types remembers the rows and expressions looked up so far, and rules + // what the dialect does to a type before storing it. + types typeCache + rules rules } type Option func(*Catalog) error diff --git a/internal/core/catalogdb/models.go b/internal/core/catalogdb/models.go index 4c79ec8c1b..9c103853ea 100644 --- a/internal/core/catalogdb/models.go +++ b/internal/core/catalogdb/models.go @@ -17,8 +17,6 @@ type SqlAttribute struct { HasDefault int64 Num int64 DeclType string - TypeLength int64 - TypeScale int64 AutoIncrement int64 IsPrimaryKey int64 IsUnique int64 @@ -86,6 +84,7 @@ type SqlProc struct { ReturnTypeOid int64 ReturnSet int64 ReturnNullable int64 + ReturnTemplate string Strict int64 VariadicKind string } @@ -104,9 +103,40 @@ type SqlType struct { NamespaceOid int64 DialectOid sql.NullInt64 Name string - Size int64 + Expr string Typtype string Category sql.NullString Preferred int64 + FamilyOid sql.NullInt64 ElementOid sql.NullInt64 + BaseOid sql.NullInt64 + CanonicalOid sql.NullInt64 + NotNull int64 +} + +type SqlTypeAffinity struct { + DialectOid int64 + Ord int64 + Words string + TypeOid int64 +} + +type SqlTypeArg struct { + TypeOid int64 + Ord int64 + Label string + ArgTypeOid sql.NullInt64 + Nullable int64 + IntValue sql.NullInt64 + BoolValue sql.NullInt64 + StringValue sql.NullString + Ident sql.NullString +} + +type SqlTypeRewrite struct { + DialectOid int64 + Ord int64 + Pattern string + Template string + Cond string } diff --git a/internal/core/catalogdb/query.sql.go b/internal/core/catalogdb/query.sql.go index b14851dce4..ba4ee026d2 100644 --- a/internal/core/catalogdb/query.sql.go +++ b/internal/core/catalogdb/query.sql.go @@ -86,9 +86,8 @@ const createAttribute = `-- name: CreateAttribute :exec INSERT INTO sql_attribute ( class_oid, name, type_oid, not_null, has_default, num, - decl_type, type_length, type_scale, - auto_increment, is_primary_key, is_unique, hidden -) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + decl_type, auto_increment, is_primary_key, is_unique, hidden +) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ` type CreateAttributeParams struct { @@ -99,8 +98,6 @@ type CreateAttributeParams struct { HasDefault int64 Num int64 DeclType string - TypeLength int64 - TypeScale int64 AutoIncrement int64 IsPrimaryKey int64 IsUnique int64 @@ -117,8 +114,6 @@ func (q *Queries) CreateAttribute(ctx context.Context, arg CreateAttributeParams arg.HasDefault, arg.Num, arg.DeclType, - arg.TypeLength, - arg.TypeScale, arg.AutoIncrement, arg.IsPrimaryKey, arg.IsUnique, @@ -266,8 +261,8 @@ const createProc = `-- name: CreateProc :execlastid INSERT INTO sql_proc (namespace_oid, dialect_oid, name, kind, - return_type_oid, return_set, return_nullable, strict, variadic_kind) -VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) + return_type_oid, return_set, return_nullable, return_template, strict, variadic_kind) +VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ` type CreateProcParams struct { @@ -278,6 +273,7 @@ type CreateProcParams struct { ReturnTypeOid int64 ReturnSet int64 ReturnNullable int64 + ReturnTemplate string Strict int64 VariadicKind string } @@ -292,6 +288,7 @@ func (q *Queries) CreateProc(ctx context.Context, arg CreateProcParams) (int64, arg.ReturnTypeOid, arg.ReturnSet, arg.ReturnNullable, + arg.ReturnTemplate, arg.Strict, arg.VariadicKind, ) @@ -330,32 +327,41 @@ func (q *Queries) CreateProcArg(ctx context.Context, arg CreateProcArgParams) er const createType = `-- name: CreateType :execlastid INSERT INTO sql_type - (name, size, typtype, category, preferred, namespace_oid, dialect_oid, element_oid) -VALUES (?, ?, ?, ?, ?, ?, ?, ?) + (name, expr, typtype, category, preferred, namespace_oid, dialect_oid, + family_oid, element_oid, base_oid, canonical_oid, not_null) +VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ` type CreateTypeParams struct { Name string - Size int64 + Expr string Typtype string Category sql.NullString Preferred int64 NamespaceOid int64 DialectOid sql.NullInt64 + FamilyOid sql.NullInt64 ElementOid sql.NullInt64 + BaseOid sql.NullInt64 + CanonicalOid sql.NullInt64 + NotNull int64 } // =============================== sql_type ============================== func (q *Queries) CreateType(ctx context.Context, arg CreateTypeParams) (int64, error) { result, err := q.db.ExecContext(ctx, createType, arg.Name, - arg.Size, + arg.Expr, arg.Typtype, arg.Category, arg.Preferred, arg.NamespaceOid, arg.DialectOid, + arg.FamilyOid, arg.ElementOid, + arg.BaseOid, + arg.CanonicalOid, + arg.NotNull, ) if err != nil { return 0, err @@ -363,6 +369,85 @@ func (q *Queries) CreateType(ctx context.Context, arg CreateTypeParams) (int64, return result.LastInsertId() } +const createTypeAffinity = `-- name: CreateTypeAffinity :exec +INSERT INTO sql_type_affinity (dialect_oid, ord, words, type_oid) +VALUES (?, ?, ?, ?) +` + +type CreateTypeAffinityParams struct { + DialectOid int64 + Ord int64 + Words string + TypeOid int64 +} + +func (q *Queries) CreateTypeAffinity(ctx context.Context, arg CreateTypeAffinityParams) error { + _, err := q.db.ExecContext(ctx, createTypeAffinity, + arg.DialectOid, + arg.Ord, + arg.Words, + arg.TypeOid, + ) + return err +} + +const createTypeArg = `-- name: CreateTypeArg :exec +INSERT INTO sql_type_arg + (type_oid, ord, label, arg_type_oid, nullable, int_value, bool_value, string_value, ident) +VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) +` + +type CreateTypeArgParams struct { + TypeOid int64 + Ord int64 + Label string + ArgTypeOid sql.NullInt64 + Nullable int64 + IntValue sql.NullInt64 + BoolValue sql.NullInt64 + StringValue sql.NullString + Ident sql.NullString +} + +func (q *Queries) CreateTypeArg(ctx context.Context, arg CreateTypeArgParams) error { + _, err := q.db.ExecContext(ctx, createTypeArg, + arg.TypeOid, + arg.Ord, + arg.Label, + arg.ArgTypeOid, + arg.Nullable, + arg.IntValue, + arg.BoolValue, + arg.StringValue, + arg.Ident, + ) + return err +} + +const createTypeRewrite = `-- name: CreateTypeRewrite :exec +INSERT INTO sql_type_rewrite (dialect_oid, ord, pattern, template, cond) +VALUES (?, ?, ?, ?, ?) +` + +type CreateTypeRewriteParams struct { + DialectOid int64 + Ord int64 + Pattern string + Template string + Cond string +} + +func (q *Queries) CreateTypeRewrite(ctx context.Context, arg CreateTypeRewriteParams) error { + _, err := q.db.ExecContext(ctx, createTypeRewrite, + arg.DialectOid, + arg.Ord, + arg.Pattern, + arg.Template, + arg.Cond, + ) + return err +} + const deleteAttribute = `-- name: DeleteAttribute :exec DELETE FROM sql_attribute WHERE class_oid = ? AND name = ? ` @@ -500,7 +585,7 @@ func (q *Queries) FindOperators(ctx context.Context, arg FindOperatorsParams) ([ } const findProcsAnyNamespace = `-- name: FindProcsAnyNamespace :many -SELECT oid, name, kind, return_type_oid, return_nullable +SELECT oid, name, kind, return_type_oid, return_nullable, return_template FROM sql_proc WHERE name = ? ` @@ -511,6 +596,7 @@ type FindProcsAnyNamespaceRow struct { Kind string ReturnTypeOid int64 ReturnNullable int64 + ReturnTemplate string } func (q *Queries) FindProcsAnyNamespace(ctx context.Context, name string) ([]FindProcsAnyNamespaceRow, error) { @@ -528,6 +614,7 @@ func (q *Queries) FindProcsAnyNamespace(ctx context.Context, name string) ([]Fin &i.Kind, &i.ReturnTypeOid, &i.ReturnNullable, + &i.ReturnTemplate, ); err != nil { return nil, err } @@ -543,7 +630,7 @@ func (q *Queries) FindProcsAnyNamespace(ctx context.Context, name string) ([]Fin } const findProcsInNamespaces = `-- name: FindProcsInNamespaces :many -SELECT oid, name, kind, return_type_oid, return_nullable +SELECT oid, name, kind, return_type_oid, return_nullable, return_template FROM sql_proc WHERE name = ?1 AND namespace_oid IN (/*SLICE:namespace_oids*/?) @@ -560,6 +647,7 @@ type FindProcsInNamespacesRow struct { Kind string ReturnTypeOid int64 ReturnNullable int64 + ReturnTemplate string } func (q *Queries) FindProcsInNamespaces(ctx context.Context, arg FindProcsInNamespacesParams) ([]FindProcsInNamespacesRow, error) { @@ -588,6 +676,7 @@ func (q *Queries) FindProcsInNamespaces(ctx context.Context, arg FindProcsInName &i.Kind, &i.ReturnTypeOid, &i.ReturnNullable, + &i.ReturnTemplate, ); err != nil { return nil, err } @@ -603,7 +692,7 @@ func (q *Queries) FindProcsInNamespaces(ctx context.Context, arg FindProcsInName } const listClassColumns = `-- name: ListClassColumns :many -SELECT a.name AS column_name, t.name AS type_name, a.not_null +SELECT a.name AS column_name, a.type_oid, a.not_null FROM sql_attribute a JOIN sql_type t ON t.oid = a.type_oid WHERE a.class_oid = ? AND a.hidden = 0 @@ -612,7 +701,7 @@ ORDER BY a.num type ListClassColumnsRow struct { ColumnName string - TypeName string + TypeOid int64 NotNull int64 } @@ -625,7 +714,7 @@ func (q *Queries) ListClassColumns(ctx context.Context, classOid int64) ([]ListC var items []ListClassColumnsRow for rows.Next() { var i ListClassColumnsRow - if err := rows.Scan(&i.ColumnName, &i.TypeName, &i.NotNull); err != nil { + if err := rows.Scan(&i.ColumnName, &i.TypeOid, &i.NotNull); err != nil { return nil, err } items = append(items, i) @@ -700,10 +789,76 @@ func (q *Queries) ListTablesInNamespace(ctx context.Context, namespaceOid int64) return items, nil } +const listTypeAffinities = `-- name: ListTypeAffinities :many +SELECT words, type_oid FROM sql_type_affinity +WHERE dialect_oid = ? ORDER BY ord +` + +type ListTypeAffinitiesRow struct { + Words string + TypeOid int64 +} + +func (q *Queries) ListTypeAffinities(ctx context.Context, dialectOid int64) ([]ListTypeAffinitiesRow, error) { + rows, err := q.db.QueryContext(ctx, listTypeAffinities, dialectOid) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListTypeAffinitiesRow + for rows.Next() { + var i ListTypeAffinitiesRow + if err := rows.Scan(&i.Words, &i.TypeOid); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listTypeRewrites = `-- name: ListTypeRewrites :many +SELECT pattern, template, cond FROM sql_type_rewrite +WHERE dialect_oid = ? ORDER BY ord +` + +type ListTypeRewritesRow struct { + Pattern string + Template string + Cond string +} + +func (q *Queries) ListTypeRewrites(ctx context.Context, dialectOid int64) ([]ListTypeRewritesRow, error) { + rows, err := q.db.QueryContext(ctx, listTypeRewrites, dialectOid) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListTypeRewritesRow + for rows.Next() { + var i ListTypeRewritesRow + if err := rows.Scan(&i.Pattern, &i.Template, &i.Cond); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const lookupAttribute = `-- name: LookupAttribute :one SELECT ns.name AS schema_name, cls.name AS table_name, a.name AS column_name, a.num, - a.decl_type, a.type_length, a.type_scale, - a.auto_increment, a.is_primary_key, a.is_unique, a.not_null + a.decl_type, a.auto_increment, a.is_primary_key, a.is_unique, a.not_null FROM sql_attribute a JOIN sql_class cls ON cls.oid = a.class_oid JOIN sql_namespace ns ON ns.oid = cls.namespace_oid @@ -716,8 +871,6 @@ type LookupAttributeRow struct { ColumnName string Num int64 DeclType string - TypeLength int64 - TypeScale int64 AutoIncrement int64 IsPrimaryKey int64 IsUnique int64 @@ -733,8 +886,6 @@ func (q *Queries) LookupAttribute(ctx context.Context, oid int64) (LookupAttribu &i.ColumnName, &i.Num, &i.DeclType, - &i.TypeLength, - &i.TypeScale, &i.AutoIncrement, &i.IsPrimaryKey, &i.IsUnique, @@ -744,17 +895,25 @@ func (q *Queries) LookupAttribute(ctx context.Context, oid int64) (LookupAttribu } const lookupType = `-- name: LookupType :one -SELECT oid, name, category, typtype, preferred +SELECT oid, namespace_oid, name, expr, category, typtype, preferred, + family_oid, element_oid, base_oid, canonical_oid, not_null FROM sql_type WHERE oid = ? ` type LookupTypeRow struct { - Oid int64 - Name string - Category sql.NullString - Typtype string - Preferred int64 + Oid int64 + NamespaceOid int64 + Name string + Expr string + Category sql.NullString + Typtype string + Preferred int64 + FamilyOid sql.NullInt64 + ElementOid sql.NullInt64 + BaseOid sql.NullInt64 + CanonicalOid sql.NullInt64 + NotNull int64 } func (q *Queries) LookupType(ctx context.Context, oid int64) (LookupTypeRow, error) { @@ -762,10 +921,17 @@ func (q *Queries) LookupType(ctx context.Context, oid int64) (LookupTypeRow, err var i LookupTypeRow err := row.Scan( &i.Oid, + &i.NamespaceOid, &i.Name, + &i.Expr, &i.Category, &i.Typtype, &i.Preferred, + &i.FamilyOid, + &i.ElementOid, + &i.BaseOid, + &i.CanonicalOid, + &i.NotNull, ) return i, err } @@ -853,8 +1019,7 @@ func (q *Queries) RenameClass(ctx context.Context, arg RenameClassParams) error const resolveColumn = `-- name: ResolveColumn :one SELECT a.oid, a.class_oid, a.name, t.name AS type_name, a.type_oid, a.not_null, - a.decl_type, a.type_length, a.type_scale, - a.auto_increment, a.is_primary_key, a.is_unique + a.decl_type, a.auto_increment, a.is_primary_key, a.is_unique FROM sql_attribute a JOIN sql_class c ON c.oid = a.class_oid JOIN sql_type t ON t.oid = a.type_oid @@ -874,8 +1039,6 @@ type ResolveColumnRow struct { TypeOid int64 NotNull int64 DeclType string - TypeLength int64 - TypeScale int64 AutoIncrement int64 IsPrimaryKey int64 IsUnique int64 @@ -892,8 +1055,6 @@ func (q *Queries) ResolveColumn(ctx context.Context, arg ResolveColumnParams) (R &i.TypeOid, &i.NotNull, &i.DeclType, - &i.TypeLength, - &i.TypeScale, &i.AutoIncrement, &i.IsPrimaryKey, &i.IsUnique, @@ -1001,8 +1162,7 @@ func (q *Queries) SetDialectFlag(ctx context.Context, arg SetDialectFlagParams) const tableColumns = `-- name: TableColumns :many SELECT a.oid, a.class_oid, a.name, t.name AS type_name, a.type_oid, a.not_null, - a.decl_type, a.type_length, a.type_scale, - a.auto_increment, a.is_primary_key, a.is_unique + a.decl_type, a.auto_increment, a.is_primary_key, a.is_unique FROM sql_attribute a JOIN sql_class c ON c.oid = a.class_oid JOIN sql_type t ON t.oid = a.type_oid @@ -1018,8 +1178,6 @@ type TableColumnsRow struct { TypeOid int64 NotNull int64 DeclType string - TypeLength int64 - TypeScale int64 AutoIncrement int64 IsPrimaryKey int64 IsUnique int64 @@ -1042,8 +1200,6 @@ func (q *Queries) TableColumns(ctx context.Context, name string) ([]TableColumns &i.TypeOid, &i.NotNull, &i.DeclType, - &i.TypeLength, - &i.TypeScale, &i.AutoIncrement, &i.IsPrimaryKey, &i.IsUnique, @@ -1061,6 +1217,56 @@ func (q *Queries) TableColumns(ctx context.Context, name string) ([]TableColumns return items, nil } +const typeArgs = `-- name: TypeArgs :many +SELECT ord, label, arg_type_oid, nullable, int_value, bool_value, string_value, ident +FROM sql_type_arg +WHERE type_oid = ? +ORDER BY ord +` + +type TypeArgsRow struct { + Ord int64 + Label string + ArgTypeOid sql.NullInt64 + Nullable int64 + IntValue sql.NullInt64 + BoolValue sql.NullInt64 + StringValue sql.NullString + Ident sql.NullString +} + +func (q *Queries) TypeArgs(ctx context.Context, typeOid int64) ([]TypeArgsRow, error) { + rows, err := q.db.QueryContext(ctx, typeArgs, typeOid) + if err != nil { + return nil, err + } + defer rows.Close() + var items []TypeArgsRow + for rows.Next() { + var i TypeArgsRow + if err := rows.Scan( + &i.Ord, + &i.Label, + &i.ArgTypeOid, + &i.Nullable, + &i.IntValue, + &i.BoolValue, + &i.StringValue, + &i.Ident, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const typeNameByOID = `-- name: TypeNameByOID :one SELECT name FROM sql_type WHERE oid = ? ` @@ -1072,11 +1278,49 @@ func (q *Queries) TypeNameByOID(ctx context.Context, oid int64) (string, error) return name, err } +const typeOIDByExpr = `-- name: TypeOIDByExpr :one +SELECT t.oid +FROM sql_type t +JOIN sql_namespace ns ON ns.oid = t.namespace_oid +WHERE t.expr = ?1 +ORDER BY + CASE ns.name + WHEN 'pg_catalog' THEN 0 + WHEN 'public' THEN 1 + ELSE 2 + END, + ns.name +LIMIT 1 +` + +func (q *Queries) TypeOIDByExpr(ctx context.Context, expr string) (int64, error) { + row := q.db.QueryRowContext(ctx, typeOIDByExpr, expr) + var oid int64 + err := row.Scan(&oid) + return oid, err +} + +const typeOIDByExprInNamespace = `-- name: TypeOIDByExprInNamespace :one +SELECT oid FROM sql_type WHERE namespace_oid = ? AND expr = ? +` + +type TypeOIDByExprInNamespaceParams struct { + NamespaceOid int64 + Expr string +} + +func (q *Queries) TypeOIDByExprInNamespace(ctx context.Context, arg TypeOIDByExprInNamespaceParams) (int64, error) { + row := q.db.QueryRowContext(ctx, typeOIDByExprInNamespace, arg.NamespaceOid, arg.Expr) + var oid int64 + err := row.Scan(&oid) + return oid, err +} + const typeOIDByName = `-- name: TypeOIDByName :one SELECT t.oid FROM sql_type t JOIN sql_namespace ns ON ns.oid = t.namespace_oid -WHERE t.name = ?1 +WHERE t.name = ?1 AND t.family_oid IS NULL ORDER BY CASE ns.name WHEN 'pg_catalog' THEN 0 @@ -1087,6 +1331,8 @@ ORDER BY LIMIT 1 ` +// The family spelled name: an instance carries its family's name too, and +// is found by its expression instead. func (q *Queries) TypeOIDByName(ctx context.Context, name string) (int64, error) { row := q.db.QueryRowContext(ctx, typeOIDByName, name) var oid int64 @@ -1094,9 +1340,77 @@ func (q *Queries) TypeOIDByName(ctx context.Context, name string) (int64, error) return oid, err } +const typeOIDByNameInNamespace = `-- name: TypeOIDByNameInNamespace :one +SELECT oid FROM sql_type +WHERE namespace_oid = ? AND name = ? AND family_oid IS NULL +` + +type TypeOIDByNameInNamespaceParams struct { + NamespaceOid int64 + Name string +} + +func (q *Queries) TypeOIDByNameInNamespace(ctx context.Context, arg TypeOIDByNameInNamespaceParams) (int64, error) { + row := q.db.QueryRowContext(ctx, typeOIDByNameInNamespace, arg.NamespaceOid, arg.Name) + var oid int64 + err := row.Scan(&oid) + return oid, err +} + +const typeOIDsByNameInNamespaces = `-- name: TypeOIDsByNameInNamespaces :many +SELECT oid, namespace_oid FROM sql_type +WHERE name = ?1 AND family_oid IS NULL + AND namespace_oid IN (/*SLICE:namespace_oids*/?) +` + +type TypeOIDsByNameInNamespacesParams struct { + Name string + NamespaceOids []int64 +} + +type TypeOIDsByNameInNamespacesRow struct { + Oid int64 + NamespaceOid int64 +} + +func (q *Queries) TypeOIDsByNameInNamespaces(ctx context.Context, arg TypeOIDsByNameInNamespacesParams) ([]TypeOIDsByNameInNamespacesRow, error) { + query := typeOIDsByNameInNamespaces + var queryParams []any + queryParams = append(queryParams, arg.Name) + if len(arg.NamespaceOids) > 0 { + for _, v := range arg.NamespaceOids { + queryParams = append(queryParams, v) + } + query = strings.Replace(query, "/*SLICE:namespace_oids*/?", strings.Repeat(",?", len(arg.NamespaceOids))[1:], 1) + } else { + query = strings.Replace(query, "/*SLICE:namespace_oids*/?", "NULL", 1) + } + rows, err := q.db.QueryContext(ctx, query, queryParams...) + if err != nil { + return nil, err + } + defer rows.Close() + var items []TypeOIDsByNameInNamespacesRow + for rows.Next() { + var i TypeOIDsByNameInNamespacesRow + if err := rows.Scan(&i.Oid, &i.NamespaceOid); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const typeOIDsInCategory = `-- name: TypeOIDsInCategory :many SELECT oid FROM sql_type WHERE dialect_oid = ? AND category = ? + AND family_oid IS NULL AND canonical_oid IS NULL ORDER BY oid ` @@ -1105,6 +1419,8 @@ type TypeOIDsInCategoryParams struct { Category sql.NullString } +// The families of a category: an instance inherits its family's category +// and an alias stands for the row it points at, so neither is listed. func (q *Queries) TypeOIDsInCategory(ctx context.Context, arg TypeOIDsInCategoryParams) ([]int64, error) { rows, err := q.db.QueryContext(ctx, typeOIDsInCategory, arg.DialectOid, arg.Category) if err != nil { diff --git a/internal/core/catalogdef/query.sql b/internal/core/catalogdef/query.sql index eb9863470c..2c56ac5d15 100644 --- a/internal/core/catalogdef/query.sql +++ b/internal/core/catalogdef/query.sql @@ -37,14 +37,54 @@ SELECT value FROM sql_dialect_flag WHERE dialect_oid = ? AND key = ?; -- name: CreateType :execlastid INSERT INTO sql_type - (name, size, typtype, category, preferred, namespace_oid, dialect_oid, element_oid) -VALUES (?, ?, ?, ?, ?, ?, ?, ?); + (name, expr, typtype, category, preferred, namespace_oid, dialect_oid, + family_oid, element_oid, base_oid, canonical_oid, not_null) +VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + +-- name: CreateTypeArg :exec +INSERT INTO sql_type_arg + (type_oid, ord, label, arg_type_oid, nullable, int_value, bool_value, string_value, ident) +VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?); + +-- name: TypeArgs :many +SELECT ord, label, arg_type_oid, nullable, int_value, bool_value, string_value, ident +FROM sql_type_arg +WHERE type_oid = ? +ORDER BY ord; + +-- name: TypeOIDByExpr :one +SELECT t.oid +FROM sql_type t +JOIN sql_namespace ns ON ns.oid = t.namespace_oid +WHERE t.expr = sqlc.arg(expr) +ORDER BY + CASE ns.name + WHEN 'pg_catalog' THEN 0 + WHEN 'public' THEN 1 + ELSE 2 + END, + ns.name +LIMIT 1; + +-- name: TypeOIDsByNameInNamespaces :many +SELECT oid, namespace_oid FROM sql_type +WHERE name = sqlc.arg(name) AND family_oid IS NULL + AND namespace_oid IN (sqlc.slice(namespace_oids)); + +-- name: TypeOIDByNameInNamespace :one +SELECT oid FROM sql_type +WHERE namespace_oid = ? AND name = ? AND family_oid IS NULL; + +-- name: TypeOIDByExprInNamespace :one +SELECT oid FROM sql_type WHERE namespace_oid = ? AND expr = ?; -- name: TypeOIDByName :one +-- The family spelled name: an instance carries its family's name too, and +-- is found by its expression instead. SELECT t.oid FROM sql_type t JOIN sql_namespace ns ON ns.oid = t.namespace_oid -WHERE t.name = sqlc.arg(name) +WHERE t.name = sqlc.arg(name) AND t.family_oid IS NULL ORDER BY CASE ns.name WHEN 'pg_catalog' THEN 0 @@ -58,15 +98,35 @@ LIMIT 1; SELECT name FROM sql_type WHERE oid = ?; -- name: TypeOIDsInCategory :many +-- The families of a category: an instance inherits its family's category +-- and an alias stands for the row it points at, so neither is listed. SELECT oid FROM sql_type WHERE dialect_oid = ? AND category = ? + AND family_oid IS NULL AND canonical_oid IS NULL ORDER BY oid; -- name: LookupType :one -SELECT oid, name, category, typtype, preferred +SELECT oid, namespace_oid, name, expr, category, typtype, preferred, + family_oid, element_oid, base_oid, canonical_oid, not_null FROM sql_type WHERE oid = ?; +-- name: CreateTypeRewrite :exec +INSERT INTO sql_type_rewrite (dialect_oid, ord, pattern, template, cond) +VALUES (?, ?, ?, ?, ?); + +-- name: ListTypeRewrites :many +SELECT pattern, template, cond FROM sql_type_rewrite +WHERE dialect_oid = ? ORDER BY ord; + +-- name: CreateTypeAffinity :exec +INSERT INTO sql_type_affinity (dialect_oid, ord, words, type_oid) +VALUES (?, ?, ?, ?); + +-- name: ListTypeAffinities :many +SELECT words, type_oid FROM sql_type_affinity +WHERE dialect_oid = ? ORDER BY ord; + -- =============================== sql_class ============================= -- name: CreateClass :execlastid @@ -94,9 +154,8 @@ UPDATE sql_class SET name = sqlc.arg(new_name) WHERE oid = sqlc.arg(oid); -- name: CreateAttribute :exec INSERT INTO sql_attribute ( class_oid, name, type_oid, not_null, has_default, num, - decl_type, type_length, type_scale, - auto_increment, is_primary_key, is_unique, hidden -) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + decl_type, auto_increment, is_primary_key, is_unique, hidden +) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); -- name: SetAttributePrimaryKey :exec UPDATE sql_attribute SET is_primary_key = 1, not_null = 1 @@ -129,8 +188,7 @@ SELECT CAST(COALESCE(MAX(num), 0) AS INTEGER) AS num FROM sql_attribute WHERE cl -- name: ResolveColumn :one SELECT a.oid, a.class_oid, a.name, t.name AS type_name, a.type_oid, a.not_null, - a.decl_type, a.type_length, a.type_scale, - a.auto_increment, a.is_primary_key, a.is_unique + a.decl_type, a.auto_increment, a.is_primary_key, a.is_unique FROM sql_attribute a JOIN sql_class c ON c.oid = a.class_oid JOIN sql_type t ON t.oid = a.type_oid @@ -138,8 +196,7 @@ WHERE c.name = sqlc.arg(table_name) AND a.name = sqlc.arg(column_name); -- name: TableColumns :many SELECT a.oid, a.class_oid, a.name, t.name AS type_name, a.type_oid, a.not_null, - a.decl_type, a.type_length, a.type_scale, - a.auto_increment, a.is_primary_key, a.is_unique + a.decl_type, a.auto_increment, a.is_primary_key, a.is_unique FROM sql_attribute a JOIN sql_class c ON c.oid = a.class_oid JOIN sql_type t ON t.oid = a.type_oid @@ -153,7 +210,7 @@ WHERE class_oid = ? ORDER BY num; -- name: ListClassColumns :many -SELECT a.name AS column_name, t.name AS type_name, a.not_null +SELECT a.name AS column_name, a.type_oid, a.not_null FROM sql_attribute a JOIN sql_type t ON t.oid = a.type_oid WHERE a.class_oid = ? AND a.hidden = 0 @@ -161,8 +218,7 @@ ORDER BY a.num; -- name: LookupAttribute :one SELECT ns.name AS schema_name, cls.name AS table_name, a.name AS column_name, a.num, - a.decl_type, a.type_length, a.type_scale, - a.auto_increment, a.is_primary_key, a.is_unique, a.not_null + a.decl_type, a.auto_increment, a.is_primary_key, a.is_unique, a.not_null FROM sql_attribute a JOIN sql_class cls ON cls.oid = a.class_oid JOIN sql_namespace ns ON ns.oid = cls.namespace_oid @@ -178,8 +234,8 @@ INSERT INTO sql_constraint (class_oid, name, kind, columns) VALUES (?, ?, ?, ?); -- name: CreateProc :execlastid INSERT INTO sql_proc (namespace_oid, dialect_oid, name, kind, - return_type_oid, return_set, return_nullable, strict, variadic_kind) -VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?); + return_type_oid, return_set, return_nullable, return_template, strict, variadic_kind) +VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?); -- name: CreateProcArg :exec INSERT INTO sql_proc_arg (proc_oid, ord, name, type_oid, mode, has_default) @@ -191,12 +247,12 @@ WHERE proc_oid = ? AND mode IN ('i', 'b', 'v') ORDER BY ord; -- name: FindProcsAnyNamespace :many -SELECT oid, name, kind, return_type_oid, return_nullable +SELECT oid, name, kind, return_type_oid, return_nullable, return_template FROM sql_proc WHERE name = ?; -- name: FindProcsInNamespaces :many -SELECT oid, name, kind, return_type_oid, return_nullable +SELECT oid, name, kind, return_type_oid, return_nullable, return_template FROM sql_proc WHERE name = sqlc.arg(name) AND namespace_oid IN (sqlc.slice(namespace_oids)); diff --git a/internal/core/catalogdef/schema.sql b/internal/core/catalogdef/schema.sql index 1e48501d58..26c70436e9 100644 --- a/internal/core/catalogdef/schema.sql +++ b/internal/core/catalogdef/schema.sql @@ -20,27 +20,96 @@ CREATE TABLE sql_dialect_flag ( PRIMARY KEY (dialect_oid, key) ); --- sql_type: data types. Modeled on pg_type. --- typtype: 'b'ase | 'c'omposite | 'd'omain | 'e'num | 'p'seudo | 'r'ange --- category: 'N'umeric | 'S'tring | 'B'oolean | 'D'atetime | 'A'rray | --- 'C'omposite | 'E'num | 'U'serdef | 'X'unknown --- preferred: tie-breaker for implicit cast resolution within a category --- element_oid: for arrays, points at the element type --- dialect_oid: NULL = standard / shared across dialects +-- sql_type: data types, one row per type expression. Modeled on pg_type, +-- with the arguments PostgreSQL keeps as a typmod on the use site held in +-- the row instead. +-- +-- A row is a family — a name the dialect or the schema declares: numeric, +-- array, mood — or an instance, a family applied to arguments: numeric(10, 2), +-- array(integer). expr is the canonical spelling of the whole expression and +-- the row's identity; name is the family's name, on an instance too, so a +-- lookup by name finds the family and an instance points at it. +-- +-- typtype: 'b'ase | 'c'omposite | 'd'omain | 'e'num | 'p'seudo | 'r'ange +-- category: 'N'umeric | 'S'tring | 'B'oolean | 'D'atetime | 'A'rray | +-- 'C'omposite | 'E'num | 'U'serdef | 'X'unknown +-- preferred: tie-breaker for implicit cast resolution within a category +-- family_oid: NULL on a family; the family on an instance +-- element_oid: what the type holds: an array's element, a map's value, +-- a range's subtype +-- base_oid: what the type stands on: a domain's or alias type's base, +-- a wrapper's inner type, a SQLite spelling's affinity +-- canonical_oid: the row the engine reports this one as: an alias spelling +-- points at the type it names +-- not_null: a domain or alias type declared NOT NULL +-- dialect_oid: NULL = standard / shared across dialects CREATE TABLE sql_type ( oid INTEGER PRIMARY KEY AUTOINCREMENT, namespace_oid INTEGER NOT NULL REFERENCES sql_namespace(oid), dialect_oid INTEGER REFERENCES sql_dialect(oid), name TEXT NOT NULL, - size INTEGER NOT NULL DEFAULT 0, + expr TEXT NOT NULL, typtype TEXT NOT NULL DEFAULT 'b', category TEXT, preferred INTEGER NOT NULL DEFAULT 0, + family_oid INTEGER REFERENCES sql_type(oid), element_oid INTEGER REFERENCES sql_type(oid), - UNIQUE (namespace_oid, name) + base_oid INTEGER REFERENCES sql_type(oid), + canonical_oid INTEGER REFERENCES sql_type(oid), + not_null INTEGER NOT NULL DEFAULT 0, + UNIQUE (namespace_oid, expr) ); CREATE INDEX idx_sql_type_name ON sql_type(name); +-- sql_type_arg: the arguments of an instance, or the fields, labels or +-- members of a declared composite, enum or set, in order. Exactly one of +-- arg_type_oid, int_value, bool_value, string_value and ident is set. +-- label: a struct field, tuple element or enum label +-- nullable: the argument type is nullable at this position, as the inner +-- type of Array(Nullable(String)) is +-- ident: a bare word that is not a type: max, sum, day to second +CREATE TABLE sql_type_arg ( + type_oid INTEGER NOT NULL REFERENCES sql_type(oid), + ord INTEGER NOT NULL, + label TEXT NOT NULL DEFAULT '', + arg_type_oid INTEGER REFERENCES sql_type(oid), + nullable INTEGER NOT NULL DEFAULT 0, + int_value INTEGER, + bool_value INTEGER, + string_value TEXT, + ident TEXT, + PRIMARY KEY (type_oid, ord) +); + +-- sql_type_rewrite: the rewrites a dialect applies to a type before it is +-- interned, in order, which are how a dialect stores what only it spells: +-- SQL Server keeps float(24) as real and a bare decimal as decimal(18,0), +-- ClickHouse keeps Decimal32(4) as Decimal(9, 4). pattern is a type +-- expression whose arguments may be $1, $2... binding whatever stands there; +-- template is the expression the match becomes, with the bindings +-- substituted; cond bounds a binding, as "$1 <= 24" does. +CREATE TABLE sql_type_rewrite ( + dialect_oid INTEGER NOT NULL REFERENCES sql_dialect(oid), + ord INTEGER NOT NULL, + pattern TEXT NOT NULL, + template TEXT NOT NULL, + cond TEXT NOT NULL DEFAULT '', + PRIMARY KEY (dialect_oid, ord) +); + +-- sql_type_affinity: the rule a dialect resolves an unseeded type family +-- by, in order: the first row one of whose words the family's name +-- contains names the type it stands on, and a row with no words is the +-- default. SQLite gives every declared spelling one of five affinities +-- this way. +CREATE TABLE sql_type_affinity ( + dialect_oid INTEGER NOT NULL REFERENCES sql_dialect(oid), + ord INTEGER NOT NULL, + words TEXT NOT NULL DEFAULT '', -- comma-separated, upper case + type_oid INTEGER NOT NULL REFERENCES sql_type(oid), + PRIMARY KEY (dialect_oid, ord) +); + -- sql_class: relations (tables, views, indexes). -- kind: 'r' = table, 'v' = view, 'i' = index, 'c' = composite type, 'f' = foreign CREATE TABLE sql_class ( @@ -52,13 +121,9 @@ CREATE TABLE sql_class ( ); -- sql_attribute: columns of a relation. --- decl_type: original declared type string before normalization --- (e.g. VARCHAR(10), BIGINT UNSIGNED, INTEGER PRIMARY KEY). --- Useful for SQLite where multiple syntaxes collapse to --- one of five affinities, and as a debugging aid. --- type_length: length / precision (varchar(N), numeric(p,s).p, --- char(N), bit(N)). 0 = unspecified. --- type_scale: scale for numeric/decimal. 0 = unspecified. +-- decl_type: the type as the schema spelled it, before +-- canonicalization (VARCHAR(10), BIGINT UNSIGNED), which +-- is what a formatter prints back and what SQLite reports. -- auto_increment: rowid alias (sqlite INTEGER PRIMARY KEY), AUTOINCREMENT, -- pg serial/bigserial/identity, mysql AUTO_INCREMENT. -- is_primary_key: this column participates in the relation's primary key. @@ -77,8 +142,6 @@ CREATE TABLE sql_attribute ( has_default INTEGER NOT NULL DEFAULT 0, num INTEGER NOT NULL, -- ordinal position (1-based) decl_type TEXT NOT NULL DEFAULT '', - type_length INTEGER NOT NULL DEFAULT 0, - type_scale INTEGER NOT NULL DEFAULT 0, auto_increment INTEGER NOT NULL DEFAULT 0, is_primary_key INTEGER NOT NULL DEFAULT 0, is_unique INTEGER NOT NULL DEFAULT 0, @@ -102,6 +165,9 @@ CREATE TABLE sql_constraint ( -- kind: 'f' = function, 'a' = aggregate, 'w' = window, 'p' = procedure -- variadic_kind: 'n' = none, 'a' = array (VARIADIC any[]), 'v' = variadic-any -- return_set: 1 if SETOF / table-returning +-- return_template: the result as an expression over the call's arguments, +-- when it depends on their values: Decimal(18, $2) for +-- toDecimal64(x, s). Empty for a result the type says. CREATE TABLE sql_proc ( oid INTEGER PRIMARY KEY AUTOINCREMENT, namespace_oid INTEGER REFERENCES sql_namespace(oid), @@ -111,6 +177,7 @@ CREATE TABLE sql_proc ( return_type_oid INTEGER NOT NULL REFERENCES sql_type(oid), return_set INTEGER NOT NULL DEFAULT 0, return_nullable INTEGER NOT NULL DEFAULT 1, + return_template TEXT NOT NULL DEFAULT '', strict INTEGER NOT NULL DEFAULT 0, variadic_kind TEXT NOT NULL DEFAULT 'n' ); diff --git a/internal/core/dialect.go b/internal/core/dialect.go index bad80dedcb..e192c442c9 100644 --- a/internal/core/dialect.go +++ b/internal/core/dialect.go @@ -77,6 +77,11 @@ const FlagPropagateNullable = "functions.propagate_nullable" // e.id. const FlagQualifyDuplicateColumns = "columns.qualify_duplicates" +// FlagDefaultSchema holds the schema the dialect puts an unqualified object +// in, when that is not the catalog's own default: a type in it is reported +// without its schema. +const FlagDefaultSchema = "schema.default" + // FlagCastCategories holds the categories whose types are all implicitly // castable to one another, as the dialect's seed declared them, so that a type // arriving after the seed — an extension's, say — can join its category. @@ -190,3 +195,16 @@ func (c *Catalog) QualifiesDuplicateColumns() bool { v, _ := c.DialectFlag(c.dialectOID, FlagQualifyDuplicateColumns) return v == "true" } + +// DefaultNamespaces lists the namespaces a type is reported from without +// qualification: the catalog's default, PostgreSQL's system catalog, and +// the dialect's own default schema when it names one. +func (c *Catalog) DefaultNamespaces() []string { + out := []string{"public", "pg_catalog"} + if c.dialectOID != 0 { + if name, _ := c.DialectFlag(c.dialectOID, FlagDefaultSchema); name != "" { + out = append(out, name) + } + } + return out +} diff --git a/internal/core/proc.go b/internal/core/proc.go index 2409a4c4af..28bf32c978 100644 --- a/internal/core/proc.go +++ b/internal/core/proc.go @@ -19,10 +19,14 @@ type ProcSpec struct { ReturnNullable bool // NeverNull marks a function whose result is never NULL even when an // argument is, in a dialect that otherwise propagates nullability. - NeverNull bool - Strict bool - VariadicKind string - Args []ProcArg + NeverNull bool + // ReturnTemplate is the result as an expression over the call's + // arguments, when it depends on their values: Decimal(18, $2) for + // toDecimal64(x, s). + ReturnTemplate string + Strict bool + VariadicKind string + Args []ProcArg } // The proc table stores nullability as one integer: 0 leaves it to the @@ -56,6 +60,7 @@ func (c *Catalog) CreateProc(p ProcSpec) (int64, error) { ReturnTypeOid: p.ReturnTypeOID, ReturnSet: boolToInt64(p.ReturnSet), ReturnNullable: returnNullable(p), + ReturnTemplate: p.ReturnTemplate, Strict: boolToInt64(p.Strict), VariadicKind: p.VariadicKind, }) @@ -99,6 +104,7 @@ type ProcOverload struct { ReturnTypeOID int64 ReturnNullable bool NeverNull bool + ReturnTemplate string ArgTypes []int64 } @@ -123,6 +129,7 @@ func (c *Catalog) FindProcs(name string, namespaceOIDs []int64) ([]ProcOverload, ReturnTypeOID: r.ReturnTypeOid, ReturnNullable: r.ReturnNullable == nullableAlways, NeverNull: r.ReturnNullable == nullableNever, + ReturnTemplate: r.ReturnTemplate, }) } } else { @@ -146,6 +153,7 @@ func (c *Catalog) FindProcs(name string, namespaceOIDs []int64) ([]ProcOverload, ReturnTypeOID: r.ReturnTypeOid, ReturnNullable: r.ReturnNullable == nullableAlways, NeverNull: r.ReturnNullable == nullableNever, + ReturnTemplate: r.ReturnTemplate, }) } } diff --git a/internal/core/rewrite.go b/internal/core/rewrite.go new file mode 100644 index 0000000000..352afe9bb1 --- /dev/null +++ b/internal/core/rewrite.go @@ -0,0 +1,361 @@ +package core + +import ( + "context" + "fmt" + "strconv" + "strings" + "sync" + + "github.com/sqlc-dev/sqlc/internal/core/catalogdb" +) + +// A dialect describes, as data, what it does to a type before storing it. +// The seed loads three kinds of it from dialect.json: rewrites, which turn +// one expression into another (float(24) into real, a bare decimal into +// decimal(18, 0)); identifier words and positions, which say where a bare +// word is a word rather than a type (the max of nvarchar(max), the +// function of SimpleAggregateFunction(sum, UInt64)); and an affinity rule, +// which says what a family the schema declares and the seed does not list +// stands on. None of it is code, so an engine adds a dialect by writing +// files. + +// FlagIdents holds the words that are identifiers wherever they stand as a +// type argument, comma-separated. +const FlagIdents = "types.idents" + +// FlagIdentArgs holds the argument positions that are identifiers in a +// family, as "family:1,2;family:1". +const FlagIdentArgs = "types.ident_args" + +// typeRewrite is one rewrite, parsed: a pattern whose $n arguments bind +// whatever stands there, a template the bindings are substituted into, and +// a condition on a binding. +type typeRewrite struct { + pattern *TypeExpr + template *TypeExpr + cond rewriteCond +} + +// rewriteCond bounds an integer binding: "$1 <= 24". +type rewriteCond struct { + binding string + op string + value int64 +} + +// rules is what the catalog knows of its dialect's rewriting, read from the +// tables once and kept. The seed invalidates it as it adds to them. +type rules struct { + mu sync.Mutex + loaded bool + rewrites []typeRewrite + idents map[string]bool + identArgs map[string][]int +} + +func (c *Catalog) invalidateRules() { + c.rules.mu.Lock() + c.rules.loaded = false + c.rules.mu.Unlock() +} + +// loadRules reads the dialect's rewrites and identifier settings. +func (c *Catalog) loadRules() (*rules, error) { + r := &c.rules + r.mu.Lock() + defer r.mu.Unlock() + if r.loaded { + return r, nil + } + r.rewrites, r.idents, r.identArgs = nil, map[string]bool{}, map[string][]int{} + if c.dialectOID == 0 { + r.loaded = true + return r, nil + } + rows, err := c.q.ListTypeRewrites(context.Background(), c.dialectOID) + if err != nil { + return nil, fmt.Errorf("type rewrites: %w", err) + } + for _, row := range rows { + rw := typeRewrite{pattern: ParseTypeExpr(row.Pattern), template: ParseTypeExpr(row.Template)} + if row.Cond != "" { + cond, err := parseRewriteCond(row.Cond) + if err != nil { + return nil, fmt.Errorf("type rewrite %q: %w", row.Pattern, err) + } + rw.cond = cond + } + r.rewrites = append(r.rewrites, rw) + } + if idents, _ := c.DialectFlag(c.dialectOID, FlagIdents); idents != "" { + for _, w := range strings.Split(idents, ",") { + r.idents[strings.ToLower(strings.TrimSpace(w))] = true + } + } + if identArgs, _ := c.DialectFlag(c.dialectOID, FlagIdentArgs); identArgs != "" { + for _, entry := range strings.Split(identArgs, ";") { + family, positions, ok := strings.Cut(entry, ":") + if !ok { + continue + } + for _, p := range strings.Split(positions, ",") { + if n, err := strconv.Atoi(strings.TrimSpace(p)); err == nil { + family = strings.ToLower(strings.TrimSpace(family)) + r.identArgs[family] = append(r.identArgs[family], n) + } + } + } + } + r.loaded = true + return r, nil +} + +// parseRewriteCond reads "$1 <= 24". +func parseRewriteCond(s string) (rewriteCond, error) { + fields := strings.Fields(s) + if len(fields) != 3 || !strings.HasPrefix(fields[0], "$") { + return rewriteCond{}, fmt.Errorf("condition %q: want \"$n op value\"", s) + } + switch fields[1] { + case "<", "<=", "=", ">=", ">", "!=": + default: + return rewriteCond{}, fmt.Errorf("condition %q: unknown operator", s) + } + v, err := strconv.ParseInt(fields[2], 10, 64) + if err != nil { + return rewriteCond{}, fmt.Errorf("condition %q: %w", s, err) + } + return rewriteCond{binding: fields[0], op: fields[1], value: v}, nil +} + +func (cond rewriteCond) holds(bindings map[string]TypeArg) bool { + if cond.binding == "" { + return true + } + a, ok := bindings[cond.binding] + if !ok || a.Int == nil { + return false + } + switch cond.op { + case "<": + return *a.Int < cond.value + case "<=": + return *a.Int <= cond.value + case "=": + return *a.Int == cond.value + case ">=": + return *a.Int >= cond.value + case ">": + return *a.Int > cond.value + case "!=": + return *a.Int != cond.value + } + return false +} + +// AddTypeRewrite records a rewrite of the catalog's dialect, applied after +// the ones recorded before it. +func (c *Catalog) AddTypeRewrite(ord int, pattern, template, cond string) error { + err := c.q.CreateTypeRewrite(context.Background(), catalogdb.CreateTypeRewriteParams{ + DialectOid: c.dialectOID, + Ord: int64(ord), + Pattern: pattern, + Template: template, + Cond: cond, + }) + if err != nil { + return fmt.Errorf("type rewrite %q: %w", pattern, err) + } + c.invalidateRules() + return nil +} + +// AddTypeAffinity records the next step of the dialect's affinity rule: a +// family whose name contains one of words, upper-cased, stands on typeOID. +// No words is the default that ends the rule. +func (c *Catalog) AddTypeAffinity(ord int, words []string, typeOID int64) error { + err := c.q.CreateTypeAffinity(context.Background(), catalogdb.CreateTypeAffinityParams{ + DialectOid: c.dialectOID, + Ord: int64(ord), + Words: strings.ToUpper(strings.Join(words, ",")), + TypeOid: typeOID, + }) + if err != nil { + return fmt.Errorf("type affinity %d: %w", ord, err) + } + return nil +} + +// userTypeBase is the type an unseeded family stands on by the dialect's +// affinity rule, or 0 when the dialect has none or none of it matches. +func (c *Catalog) userTypeBase(name string) (int64, error) { + if c.dialectOID == 0 { + return 0, nil + } + rows, err := c.q.ListTypeAffinities(context.Background(), c.dialectOID) + if err != nil { + return 0, fmt.Errorf("type affinities: %w", err) + } + upper := strings.ToUpper(name) + for _, row := range rows { + if row.Words == "" { + return row.TypeOid, nil + } + for _, w := range strings.Split(row.Words, ",") { + if w != "" && strings.Contains(upper, w) { + return row.TypeOid, nil + } + } + } + return 0, nil +} + +// canonicalize applies the dialect's identifier settings and rewrites to +// an expression: the first rewrite whose pattern matches is applied, and +// its result is not rewritten again. A rewrite names a family as the +// dialect spells it, so an expression spelled with an alias — dec(10) for +// a rule on decimal — is tried again with the alias resolved. +func (c *Catalog) canonicalize(t *TypeExpr) (*TypeExpr, error) { + r, err := c.loadRules() + if err != nil { + return nil, err + } + t = r.identify(t) + if len(r.rewrites) == 0 { + return t, nil + } + if out, ok := r.rewrite(t); ok { + return out, nil + } + if canonical, ok := c.canonicalFamilyName(t.Name); ok && !strings.EqualFold(canonical, t.Name) { + resolved := t.Clone() + resolved.Name = canonical + if out, ok := r.rewrite(resolved); ok { + return out, nil + } + } + return t, nil +} + +// rewrite applies the first rewrite whose pattern matches the expression. +func (r *rules) rewrite(t *TypeExpr) (*TypeExpr, bool) { + name := strings.ToLower(t.Name) + for _, rw := range r.rewrites { + if strings.ToLower(rw.pattern.Name) != name || len(rw.pattern.Args) != len(t.Args) { + continue + } + bindings, ok := matchArgs(rw.pattern.Args, t.Args) + if !ok || !rw.cond.holds(bindings) { + continue + } + out := substitute(rw.template, bindings) + out.Nullable = t.Nullable + return out, true + } + return nil, false +} + +// canonicalFamilyName is the name the catalog spells a family by, with +// aliases resolved, or false when the name is not a family it holds. +func (c *Catalog) canonicalFamilyName(name string) (string, bool) { + oid, err := c.familyOIDByQualifiedName(strings.ToLower(strings.TrimSpace(name))) + if err != nil { + return "", false + } + if oid, err = c.canonicalOID(oid); err != nil { + return "", false + } + info, err := c.LookupType(oid) + if err != nil { + return "", false + } + return c.qualifiedName(info), true +} + +// identify turns the bare words the dialect calls identifiers into +// identifier arguments. +func (r *rules) identify(t *TypeExpr) *TypeExpr { + if len(t.Args) == 0 || (len(r.idents) == 0 && len(r.identArgs) == 0) { + return t + } + positions := r.identArgs[strings.ToLower(t.Name)] + var out *TypeExpr + for i, a := range t.Args { + if a.Type == nil || len(a.Type.Args) != 0 { + continue + } + word := strings.ToLower(a.Type.Name) + if !r.idents[word] && !containsInt(positions, i+1) { + continue + } + if out == nil { + out = t.Clone() + } + out.Args[i] = TypeArg{Label: a.Label, Ident: &word} + } + if out == nil { + return t + } + return out +} + +func containsInt(list []int, n int) bool { + for _, v := range list { + if v == n { + return true + } + } + return false +} + +// matchArgs matches a pattern's arguments against an expression's, binding +// each $n to what stands in its place and requiring a literal to be equal. +func matchArgs(pattern, args []TypeArg) (map[string]TypeArg, bool) { + bindings := map[string]TypeArg{} + for i, p := range pattern { + a := args[i] + switch { + case p.Type != nil && strings.HasPrefix(p.Type.Name, "$"): + bindings[p.Type.Name] = a + case p.Type != nil: + if a.Type == nil || !strings.EqualFold(a.Type.Name, p.Type.Name) { + return nil, false + } + case p.Int != nil: + if a.Int == nil || *a.Int != *p.Int { + return nil, false + } + case p.String != nil: + if a.String == nil || *a.String != *p.String { + return nil, false + } + case p.Ident != nil: + if a.Ident == nil || *a.Ident != *p.Ident { + return nil, false + } + default: + return nil, false + } + } + return bindings, true +} + +// substitute fills a template's $n arguments from the bindings. +func substitute(template *TypeExpr, bindings map[string]TypeArg) *TypeExpr { + out := template.Clone() + for i, a := range out.Args { + if a.Type != nil && strings.HasPrefix(a.Type.Name, "$") { + if bound, ok := bindings[a.Type.Name]; ok { + label := a.Label + out.Args[i] = bound + if label != "" { + out.Args[i].Label = label + } + } + } else if a.Type != nil { + out.Args[i].Type = substitute(a.Type, bindings) + } + } + return out +} diff --git a/internal/core/schema/schema.go b/internal/core/schema/schema.go index 25d864c13a..e96d8dbe2a 100644 --- a/internal/core/schema/schema.go +++ b/internal/core/schema/schema.go @@ -28,6 +28,12 @@ func Apply(cat *core.Catalog, n ast.Node) error { return applyDropTable(cat, v) case *ast.CreateEnumStmt: return applyCreateEnum(cat, v) + case *ast.CreateDomainStmt: + return applyCreateDomain(cat, v) + case *ast.CompositeTypeStmt: + return applyCompositeType(cat, v) + case *ast.CreateRangeStmt: + return applyCreateRange(cat, v) case *ast.CreateExtensionStmt: if v.Extname == nil { return nil @@ -167,7 +173,7 @@ func applyCreateTable(cat *core.Catalog, stmt *ast.CreateTableStmt) error { Name: col.Colname, TypeOID: typeOID, Num: i + 1, - NotNull: col.IsNotNull || col.PrimaryKey, + NotNull: col.IsNotNull || col.PrimaryKey || typeNotNull(cat, typeOID), IsPrimaryKey: col.PrimaryKey, DeclType: declType(col.TypeName), Hidden: col.IsHidden, @@ -239,7 +245,7 @@ func applyAlterTable(cat *core.Catalog, stmt *ast.AlterTableStmt) error { Name: cmd.Def.Colname, TypeOID: typeOID, Num: num, - NotNull: cmd.Def.IsNotNull || cmd.Def.PrimaryKey, + NotNull: cmd.Def.IsNotNull || cmd.Def.PrimaryKey || typeNotNull(cat, typeOID), IsPrimaryKey: cmd.Def.PrimaryKey, DeclType: declType(cmd.Def.TypeName), }); err != nil { @@ -264,7 +270,7 @@ func applyAlterTable(cat *core.Catalog, stmt *ast.AlterTableStmt) error { if err != nil { return err } - if err := cat.SetAttributeType(classOID, name, typeOID, cmd.Def.TypeName.Name); err != nil { + if err := cat.SetAttributeType(classOID, name, typeOID, declType(cmd.Def.TypeName)); err != nil { return err } // An engine that reports a column's whole new definition also @@ -351,21 +357,134 @@ func listItems(l *ast.List) []ast.Node { return l.Items } +// applyCreateEnum records an enum as a type whose arguments are its labels, +// in order, the way pg_enum keeps them. func applyCreateEnum(cat *core.Catalog, stmt *ast.CreateEnumStmt) error { if stmt.TypeName == nil { return fmt.Errorf("create type with nil name") } - name := core.TypeNameString(stmt.TypeName) + name := declaredTypeName(stmt.TypeName) if name == "" { return fmt.Errorf("create type with empty name") } - if _, err := cat.TypeOID(name); err == nil { + if cat.TypeDeclared(name) { return nil } - _, err := cat.CreateUserType(name, "E") + var labels []core.TypeArg + for _, label := range listStrings(stmt.Vals) { + l := label + labels = append(labels, core.TypeArg{String: &l}) + } + _, err := cat.CreateTypeWithArgs(core.TypeSpec{Name: name, Typtype: "e", Category: "E"}, labels) + return err +} + +// applyCreateDomain records a domain: a type of its own that stands on its +// base, which is what it resolves through, and that may forbid NULL. +func applyCreateDomain(cat *core.Catalog, stmt *ast.CreateDomainStmt) error { + name := strings.ToLower(strings.Join(listStrings(stmt.Domainname), ".")) + if name == "" || stmt.TypeName == nil { + return fmt.Errorf("create domain: missing name or type") + } + if cat.TypeDeclared(name) { + return nil + } + baseOID, err := cat.ResolveType(stmt.TypeName) + if err != nil { + return fmt.Errorf("domain %q: %w", name, err) + } + base, err := cat.LookupType(baseOID) + if err != nil { + return err + } + notNull := false + for _, item := range listItems(stmt.Constraints) { + if con, ok := item.(*ast.Constraint); ok && con.Contype == ast.ConstrTypeNotNull { + notNull = true + } + } + _, err = cat.CreateTypeWithArgs(core.TypeSpec{ + Name: name, + Typtype: "d", + Category: base.Category, + BaseOID: baseOID, + NotNull: notNull, + }, nil) + return err +} + +// applyCompositeType records a composite type as a type whose arguments are +// its fields, labelled by name. +func applyCompositeType(cat *core.Catalog, stmt *ast.CompositeTypeStmt) error { + if stmt.TypeName == nil { + return fmt.Errorf("create type with nil name") + } + name := declaredTypeName(stmt.TypeName) + if name == "" { + return fmt.Errorf("create type with empty name") + } + if cat.TypeDeclared(name) { + return nil + } + var fields []core.TypeArg + for _, item := range listItems(stmt.Coldeflist) { + col, ok := item.(*ast.ColumnDef) + if !ok || col.TypeName == nil { + continue + } + t := core.ColumnTypeExpr(col) + if t == nil { + continue + } + fields = append(fields, core.TypeArg{Label: col.Colname, Type: t}) + } + _, err := cat.CreateTypeWithArgs(core.TypeSpec{Name: name, Typtype: "c", Category: "C"}, fields) return err } +// applyCreateRange records a range type over its subtype, which is what a +// bound of it has. +func applyCreateRange(cat *core.Catalog, stmt *ast.CreateRangeStmt) error { + name := strings.ToLower(strings.Join(listStrings(stmt.TypeName), ".")) + if name == "" { + return fmt.Errorf("create type with empty name") + } + if cat.TypeDeclared(name) { + return nil + } + spec := core.TypeSpec{Name: name, Typtype: "r", Category: "R"} + for _, item := range listItems(stmt.Params) { + def, ok := item.(*ast.DefElem) + if !ok || def.Defname == nil || *def.Defname != "subtype" { + continue + } + tn, ok := def.Arg.(*ast.TypeName) + if !ok { + continue + } + oid, err := cat.ResolveType(tn) + if err != nil { + return fmt.Errorf("range %q: %w", name, err) + } + spec.ElementOID = oid + } + _, err := cat.CreateTypeWithArgs(spec, nil) + return err +} + +// declaredTypeName is the name a CREATE TYPE gives, qualified by its schema +// when it names one. +func declaredTypeName(tn *ast.TypeName) string { + t := core.TypeExprOfTypeName(tn) + if t == nil { + return "" + } + if tn.Schema != "" && !strings.Contains(t.Name, ".") { + return strings.ToLower(tn.Schema) + "." + t.Name + } + return t.Name +} + func applyCreateFunction(cat *core.Catalog, stmt *ast.CreateFunctionStmt) error { // A procedure returns nothing, so there is no result for a query to // select and nothing worth recording. @@ -422,17 +541,20 @@ func resolveOrCreateNamespace(cat *core.Catalog, schema string) (int64, error) { return cat.CreateNamespace(name) } -// columnTypeOID resolves a column's type. Engines report an array column -// either on the type name or on the column itself. +// typeNotNull reports whether a column of the type can never be NULL +// because the type itself says so, as a domain declared NOT NULL does. +func typeNotNull(cat *core.Catalog, typeOID int64) bool { + info, err := cat.LookupType(typeOID) + return err == nil && info.NotNull +} + +// columnTypeOID interns a column's type and returns its row. func columnTypeOID(cat *core.Catalog, col *ast.ColumnDef) (int64, error) { - name := core.TypeNameString(col.TypeName) - if name == "" { + t := core.ColumnTypeExpr(col) + if t == nil { return 0, fmt.Errorf("missing type name") } - if (col.IsArray || col.ArrayDims > 0) && !strings.HasSuffix(name, core.ArraySuffix) { - name += core.ArraySuffix - } - return cat.ResolveTypeName(name) + return cat.ResolveTypeExpr(t) } // declType is the type as the schema spelled it: an engine that folds or diff --git a/internal/core/seed/extension.go b/internal/core/seed/extension.go index ac7eacdde8..c0f3689535 100644 --- a/internal/core/seed/extension.go +++ b/internal/core/seed/extension.go @@ -130,13 +130,5 @@ func (e *extension) funcType(name string) (int64, error) { if name == "" { return 0, nil } - if oid, err := e.cat.TypeOID(name); err == nil { - return oid, nil - } - return e.cat.CreateTypeSpec(core.TypeSpec{ - Name: name, - Typtype: "b", - Category: "U", - DialectOID: e.cat.SeededDialectOID(), - }) + return e.cat.ResolvePseudoTypeExpr(core.ParseTypeExpr(name)) } diff --git a/internal/core/seed/seed.go b/internal/core/seed/seed.go index e5819963ca..e14f17aac8 100644 --- a/internal/core/seed/seed.go +++ b/internal/core/seed/seed.go @@ -31,6 +31,7 @@ import ( "io/fs" "path" "slices" + "strconv" "strings" "github.com/sqlc-dev/sqlc/internal/core" @@ -105,17 +106,66 @@ type Settings struct { // enable_fts5 compile option adds. Modules map[string]string `json:"modules,omitempty"` + // DefaultSchema names the schema a dialect puts an unqualified object + // in when it is not the catalog's own default: SQL Server's dbo, + // DuckDB's main. A type in it is reported unqualified. + DefaultSchema string `json:"default_schema,omitempty"` + + // Rewrites are what the dialect does to a type before storing it, in + // order: the first whose pattern matches applies. A pattern's $1, $2 + // bind whatever stands there, the template is what the match becomes, + // and Where bounds a binding, as "$1 <= 24" does. + Rewrites []Rewrite `json:"rewrites,omitempty"` + + // Idents are the words that are identifiers wherever they stand as a + // type argument, such as the max of nvarchar(max), and IdentArgs the + // argument positions, counted from one, that are identifiers in a + // family, such as the first of SimpleAggregateFunction(sum, UInt64). + Idents []string `json:"idents,omitempty"` + IdentArgs map[string][]int `json:"ident_args,omitempty"` + + // Affinity is the rule a type family the schema declares and the seed + // does not list stands on, in order: the first whose words the name + // contains names the base, and one with no words is the default. + Affinity []Affinity `json:"affinity,omitempty"` + + // Alias says what an alias in types.jsonl is. "canonical", the default, + // makes it another spelling of the type, which a column declared with + // it is reported as, the way PostgreSQL reports int as integer. "base" + // makes it a type of its own that stands on the one it aliases, which + // is how SQLite keeps a column's declared spelling while comparing it + // by its affinity. + Alias string `json:"alias,omitempty"` + // fsys is the dialect directory the settings were read from. fsys fs.FS } -// Type is a type the dialect defines. Aliases are spellings of the same type -// that a schema may use in a column definition; each becomes its own catalog -// type, with implicit casts registered between them. +// Rewrite is one rewrite of a type expression. +type Rewrite struct { + From string `json:"from"` + To string `json:"to"` + Where string `json:"where,omitempty"` +} + +// Affinity is one step of the rule an unseeded family stands on. +type Affinity struct { + Contains []string `json:"contains,omitempty"` + Type string `json:"type"` +} + +// Type is a type family the dialect defines. Aliases are other spellings of +// it that a schema may use in a column definition; each becomes a row that +// points at the type, as an alias of it or as a type standing on it, +// depending on the dialect's Alias setting. type Type struct { Name string `json:"name"` Category string `json:"category"` Aliases []string `json:"aliases,omitempty"` + // Base names the family this one stands on, which must be listed + // before it: MySQL's bigint unsigned is a type of its own that + // resolves as a bigint where nothing takes it as itself. + Base string `json:"base,omitempty"` } // Operator is a single operator overload. @@ -141,7 +191,8 @@ type Function struct { Kind string `json:"kind,omitempty"` Args []Arg `json:"args,omitempty"` // Returns names the result type, or "$1", "$2"... for the type of that - // argument. + // argument, or an expression over the arguments — Decimal(18, $2) — + // for a result that depends on an argument's value. Returns string `json:"returns"` Nullable bool `json:"nullable,omitempty"` // NeverNull marks a result that is never NULL even when an argument @@ -258,9 +309,17 @@ func apply(cat *core.Catalog, fsys fs.FS, settings Settings) error { if err := stream(fsys, TypesFile, b.addType); err != nil { return err } + // Every dialect has arrays, whether or not its list names the family, + // and a lookup of one against the cached catalog cannot add it then. + if _, err := b.createType(core.ArrayTypeName, "A", 0); err != nil { + return err + } if err := b.consts(); err != nil { return err } + if err := b.rules(); err != nil { + return err + } if err := b.categoryOperators(); err != nil { return err } @@ -379,15 +438,25 @@ func Relations(fsys fs.FS, dir, schema string) ([]*catalog.Table, error) { Columns: make([]*catalog.Column, 0, len(rel.Columns)), } for _, col := range rel.Columns { + // A column's type may carry arguments, as MySQL's varchar(64) + // does; the legacy catalog holds the family and the length + // apart. + t := core.ParseTypeExpr(col.Type) column := &catalog.Column{ Name: col.Name, - Type: ast.TypeName{Name: col.Type}, + Type: ast.TypeName{Name: t.Name}, IsNotNull: col.NotNull, IsArray: col.Array, } + if col.Array { + column.ArrayDims = 1 + } if col.Length > 0 { length := col.Length column.Length = &length + } else if len(t.Args) > 0 && t.Args[0].Int != nil { + length := int(*t.Args[0].Int) + column.Length = &length } table.Columns = append(table.Columns, column) } @@ -435,8 +504,9 @@ type builder struct { settings Settings dialectOID int64 - // oids maps a lowercased type name to its OID, and categories records the - // category each was seeded under, in the order they were read. + // oids maps a lowercased type spelling to the row a seed record naming + // it means, and categories records the category each family was seeded + // under, in the order they were read. oids map[string]int64 categories []categorized @@ -455,32 +525,55 @@ type categorized struct { } func (b *builder) addType(t Type) error { - for _, name := range append([]string{t.Name}, t.Aliases...) { - if _, err := b.createType(name, t.Category); err != nil { - return fmt.Errorf("type %q: %w", name, err) + var baseOID int64 + if t.Base != "" { + oid, ok := b.oids[strings.ToLower(t.Base)] + if !ok { + return fmt.Errorf("type %q: base %q is not a type listed before it", t.Name, t.Base) + } + baseOID = oid + } + oid, err := b.createType(t.Name, t.Category, baseOID) + if err != nil { + return fmt.Errorf("type %q: %w", t.Name, err) + } + for _, alias := range t.Aliases { + if err := b.addAlias(alias, oid, t.Category); err != nil { + return fmt.Errorf("type %q: alias %q: %w", t.Name, alias, err) } } - return b.aliasCasts(t) + return nil } -// aliasCasts makes every spelling of a type implicitly castable to every other, -// so that a column declared "integer" and one declared "int4" compare. -func (b *builder) aliasCasts(t Type) error { - names := append([]string{t.Name}, t.Aliases...) - for _, src := range names { - for _, tgt := range names { - if src == tgt { - continue - } - if err := b.addCast(Cast{Source: src, Target: tgt, Context: "i"}); err != nil { - return err - } - } +// addAlias registers another spelling of a type: a row that points at the +// type as its canonical form, or — for a dialect whose aliases are types of +// their own — as its base. +func (b *builder) addAlias(name string, typeOID int64, category string) error { + key := strings.ToLower(name) + if _, ok := b.oids[key]; ok { + return nil + } + spec := core.TypeSpec{Name: key, Typtype: "b", Category: category, DialectOID: b.dialectOID} + if b.settings.Alias == "base" { + spec.BaseOID = typeOID + } else { + spec.CanonicalOID = typeOID + } + oid, err := b.cat.CreateTypeSpec(spec) + if err != nil { + return err + } + // A record naming the alias means the type it stands for, unless the + // alias is a type of its own. + if b.settings.Alias == "base" { + b.oids[key] = oid + } else { + b.oids[key] = typeOID } return nil } -func (b *builder) createType(name, category string) (int64, error) { +func (b *builder) createType(name, category string, baseOID int64) (int64, error) { key := strings.ToLower(name) if oid, ok := b.oids[key]; ok { return oid, nil @@ -489,6 +582,7 @@ func (b *builder) createType(name, category string) (int64, error) { Name: key, Typtype: "b", Category: category, + BaseOID: baseOID, DialectOID: b.dialectOID, }) if err != nil { @@ -524,6 +618,11 @@ func (b *builder) consts() error { return err } } + if b.settings.DefaultSchema != "" { + if err := b.cat.SetDialectFlag(b.dialectOID, core.FlagDefaultSchema, strings.ToLower(b.settings.DefaultSchema)); err != nil { + return err + } + } for key, name := range map[string]string{ core.FlagBoolType: b.settings.Bool, core.FlagLimitType: b.settings.Limit, @@ -566,6 +665,54 @@ func (b *builder) consts() error { return nil } +// rules records what the dialect does to a type before storing it: its +// rewrites, its identifier words and positions, and its affinity rule. +func (b *builder) rules() error { + s := b.settings + for i, rw := range s.Rewrites { + if rw.From == "" || rw.To == "" { + return fmt.Errorf("seed %s: rewrite %d needs from and to", s.Dialect, i+1) + } + if err := b.cat.AddTypeRewrite(i+1, rw.From, rw.To, rw.Where); err != nil { + return err + } + } + if len(s.Idents) > 0 { + if err := b.cat.SetDialectFlag(b.dialectOID, core.FlagIdents, strings.ToLower(strings.Join(s.Idents, ","))); err != nil { + return err + } + } + if len(s.IdentArgs) > 0 { + families := make([]string, 0, len(s.IdentArgs)) + for family := range s.IdentArgs { + families = append(families, family) + } + // In a fixed order, so the catalog comes out the same every time. + slices.Sort(families) + entries := make([]string, 0, len(families)) + for _, family := range families { + positions := make([]string, 0, len(s.IdentArgs[family])) + for _, p := range s.IdentArgs[family] { + positions = append(positions, strconv.Itoa(p)) + } + entries = append(entries, strings.ToLower(family)+":"+strings.Join(positions, ",")) + } + if err := b.cat.SetDialectFlag(b.dialectOID, core.FlagIdentArgs, strings.Join(entries, ";")); err != nil { + return err + } + } + for i, a := range s.Affinity { + oid, ok := b.oids[strings.ToLower(a.Type)] + if !ok { + return fmt.Errorf("seed %s: affinity names unknown type %q", s.Dialect, a.Type) + } + if err := b.cat.AddTypeAffinity(i+1, a.Contains, oid); err != nil { + return err + } + } + return nil +} + func (b *builder) categoryOperators() error { s := b.settings boolOID, ok := b.oids[strings.ToLower(s.Bool)] @@ -673,7 +820,8 @@ func (b *builder) addCast(c Cast) error { } func (b *builder) addFunction(fn Function) error { - returnOID, err := b.funcType(fn.Returns) + returns, template := returnTemplate(fn.Returns) + returnOID, err := b.funcType(returns) if err != nil { return fmt.Errorf("function %q: %w", fn.Name, err) } @@ -702,6 +850,7 @@ func (b *builder) addFunction(fn Function) error { ReturnTypeOID: returnOID, ReturnNullable: fn.Nullable, NeverNull: fn.NeverNull, + ReturnTemplate: template, Args: args, }) if err != nil { @@ -710,6 +859,19 @@ func (b *builder) addFunction(fn Function) error { return nil } +// returnTemplate splits a function's Returns into the type the catalog +// records and the template it keeps: a result spelled over the arguments, +// as Decimal(18, $2) is, records its family and keeps the whole spelling +// to fill in at each call. A bare $n, the type of that argument, is a +// pseudo-type of its own rather than a template. +func returnTemplate(returns string) (string, string) { + if !strings.Contains(returns, "$") || strings.HasPrefix(returns, "$") { + return returns, "" + } + t := core.ParseTypeExpr(returns) + return t.Name, returns +} + func (b *builder) addRelation(rel Relation) error { if rel.Name == "" { return errors.New("relation has no name") @@ -727,22 +889,21 @@ func (b *builder) addRelation(rel Relation) error { return err } for i, col := range rel.Columns { - name := col.Type + t := core.ParseTypeExpr(col.Type) if col.Array { - name += core.ArraySuffix + t = core.Array(t) } - typeOID, err := b.columnType(name) + typeOID, err := b.columnType(t) if err != nil { return fmt.Errorf("relation %q column %q: %w", rel.Name, col.Name, err) } if err := b.cat.CreateAttributeSpec(core.AttributeSpec{ - ClassOID: classOID, - Name: col.Name, - TypeOID: typeOID, - Num: i + 1, - NotNull: col.NotNull, - DeclType: col.Type, - TypeLength: col.Length, + ClassOID: classOID, + Name: col.Name, + TypeOID: typeOID, + Num: i + 1, + NotNull: col.NotNull, + DeclType: col.Type, }); err != nil { return fmt.Errorf("relation %q column %q: %w", rel.Name, col.Name, err) } @@ -769,14 +930,14 @@ func (b *builder) namespace(schema string) (int64, error) { return oid, nil } -// columnType resolves a column's type, which unlike a function signature may -// name an array. -func (b *builder) columnType(name string) (int64, error) { - key := strings.ToLower(name) +// columnType resolves a column's type, which may be an array or carry +// arguments. +func (b *builder) columnType(t *core.TypeExpr) (int64, error) { + key := t.Key() if oid, ok := b.oids[key]; ok { return oid, nil } - oid, err := b.cat.ResolveTypeName(key) + oid, err := b.cat.ResolveTypeExpr(t) if err != nil { return 0, err } @@ -791,5 +952,14 @@ func (b *builder) funcType(name string) (int64, error) { if name == "" { return 0, nil } - return b.createType(name, "U") + key := strings.ToLower(name) + if oid, ok := b.oids[key]; ok { + return oid, nil + } + oid, err := b.cat.ResolvePseudoTypeExpr(core.ParseTypeExpr(name)) + if err != nil { + return 0, err + } + b.oids[key] = oid + return oid, nil } diff --git a/internal/core/typeexpr.go b/internal/core/typeexpr.go index bebb7e83ce..59372bb1f9 100644 --- a/internal/core/typeexpr.go +++ b/internal/core/typeexpr.go @@ -18,14 +18,98 @@ type TypeExpr struct { Args []TypeArg `json:"args,omitempty"` } -// TypeArg is one argument of a TypeExpr: exactly one of Type, Int, Bool or -// String is set. +// TypeArg is one argument of a TypeExpr: exactly one of Type, Int, Bool, +// String or Ident is set. Ident is a bare word that is not a type — the max +// of nvarchar(max), the function of SimpleAggregateFunction(sum, UInt64), +// the fields of interval day to second. type TypeArg struct { Label string `json:"label,omitempty"` Type *TypeExpr `json:"type,omitempty"` Int *int64 `json:"int,omitempty"` Bool *bool `json:"bool,omitempty"` String *string `json:"string,omitempty"` + Ident *string `json:"ident,omitempty"` +} + +// ArrayTypeName is the family every dialect's array is an instance of: an +// array of integers is array(integer), whatever the dialect spells it. +const ArrayTypeName = "array" + +// Array wraps element in one array dimension. +func Array(element *TypeExpr) *TypeExpr { + return &TypeExpr{Name: ArrayTypeName, Args: []TypeArg{{Type: element}}} +} + +// IsArray reports whether the expression is an array. +func (t *TypeExpr) IsArray() bool { + return t != nil && t.Name == ArrayTypeName && len(t.Args) > 0 && t.Args[0].Type != nil +} + +// Element is an array's element type, or nil for anything else. +func (t *TypeExpr) Element() *TypeExpr { + if !t.IsArray() { + return nil + } + return t.Args[0].Type +} + +// ArrayDims counts the array dimensions wrapped around the expression's +// innermost type, and Innermost is that type: the integer of an array of +// arrays of integers. +func (t *TypeExpr) ArrayDims() int { + dims := 0 + for t.IsArray() { + dims++ + t = t.Element() + } + return dims +} + +func (t *TypeExpr) Innermost() *TypeExpr { + for t.IsArray() { + t = t.Element() + } + return t +} + +// Clone copies the expression, arguments and all, so that a caller can set +// nullability on the copy without touching a cached one. +func (t *TypeExpr) Clone() *TypeExpr { + if t == nil { + return nil + } + out := &TypeExpr{Name: t.Name, Nullable: t.Nullable} + if len(t.Args) > 0 { + out.Args = make([]TypeArg, len(t.Args)) + for i, a := range t.Args { + out.Args[i] = a + out.Args[i].Type = a.Type.Clone() + } + } + return out +} + +// WithNullable returns a copy of the expression with its own nullability set +// as given; the nullability of a nested type is left alone. +func (t *TypeExpr) WithNullable(nullable bool) *TypeExpr { + out := t.Clone() + if out != nil { + out.Nullable = nullable + } + return out +} + +// Key is the expression's canonical spelling, which identifies its row in +// the catalog: the expression's own nullability is not part of it, since a +// row is never nullable, while the nullability of a nested type is. +func (t *TypeExpr) Key() string { + if t == nil { + return "" + } + if !t.Nullable { + return t.String() + } + return t.WithNullable(false).String() } // ParseTypeExpr reads a type spelled the way every dialect spells one, as a @@ -36,7 +120,7 @@ type TypeArg struct { func ParseTypeExpr(s string) *TypeExpr { s = strings.TrimSpace(s) if element, ok := strings.CutSuffix(s, ArraySuffix); ok { - return &TypeExpr{Name: "array", Args: []TypeArg{{Type: ParseTypeExpr(element)}}} + return Array(ParseTypeExpr(element)) } name, args := splitTypeArgs(s) name = strings.ToLower(name) @@ -72,16 +156,19 @@ func parseTypeArg(a string) TypeArg { b := strings.EqualFold(a, "true") return TypeArg{Bool: &b} } - // A label is a word before a space that comes before any parenthesis, - // as in `lat Float64` or `tags Array(String)`. + // A label is a word before a colon, as the canonical form writes it: + // `lat: Float64`. A word before a space is a label too, as ClickHouse + // writes `lat Float64`, but only when what follows is a single word, + // since `timestamp with time zone` is a name and not a label. head := a if p := strings.IndexByte(a, '('); p >= 0 { head = a[:p] } - if i := strings.IndexByte(head, ' '); i > 0 { - arg := parseTypeArg(a[i+1:]) - arg.Label = a[:i] - return arg + if i := strings.IndexByte(head, ':'); i > 0 && !strings.ContainsAny(head[:i], " '\"") { + return TypeArg{Label: strings.TrimSpace(a[:i]), Type: ParseTypeExpr(a[i+1:])} + } + if i := strings.IndexByte(head, ' '); i > 0 && !strings.Contains(strings.TrimSpace(head[i+1:]), " ") { + return TypeArg{Label: a[:i], Type: ParseTypeExpr(a[i+1:])} } return TypeArg{Type: ParseTypeExpr(a)} } @@ -103,14 +190,23 @@ func quotedEnd(s string) int { } // splitTypeArgs splits `Base(arg, arg)` into its base name and top-level -// arguments, leaving nested parentheses and quoted strings intact. +// arguments, leaving nested parentheses and quoted strings intact. Words +// after the closing parenthesis belong to the name, since MySQL writes +// decimal(10,2) unsigned and PostgreSQL timestamp(3) with time zone. func splitTypeArgs(t string) (string, []string) { open := strings.IndexByte(t, '(') - if open < 0 || !strings.HasSuffix(t, ")") { + if open < 0 { + return t, nil + } + close := matchingParen(t, open) + if close < 0 { return t, nil } base := strings.TrimSpace(t[:open]) - inner := t[open+1 : len(t)-1] + if rest := strings.TrimSpace(t[close+1:]); rest != "" { + base += " " + rest + } + inner := t[open+1 : close] var ( args []string depth int @@ -143,6 +239,34 @@ func splitTypeArgs(t string) (string, []string) { return base, args } +// matchingParen finds the parenthesis closing the one at open, skipping +// nested parentheses and quoted strings, or -1 when it is not closed. +func matchingParen(t string, open int) int { + depth := 0 + var quote byte + for i := open; i < len(t); i++ { + c := t[i] + switch { + case quote != 0: + if c == '\\' { + i++ + } else if c == quote { + quote = 0 + } + case c == '\'' || c == '"' || c == '`': + quote = c + case c == '(': + depth++ + case c == ')': + depth-- + if depth == 0 { + return i + } + } + } + return -1 +} + // HasNullable reports whether the expression marks nullability anywhere, // which tells whether the spelling it came from said so itself. func (t *TypeExpr) HasNullable() bool { @@ -187,6 +311,8 @@ func (t *TypeExpr) String() string { b.WriteString(strconv.FormatBool(*a.Bool)) case a.String != nil: b.WriteString("'" + strings.ReplaceAll(*a.String, "'", `\'`) + "'") + case a.Ident != nil: + b.WriteString(*a.Ident) } } b.WriteByte(')') diff --git a/internal/core/typename.go b/internal/core/typename.go index c0a9f6d680..4c37a272ac 100644 --- a/internal/core/typename.go +++ b/internal/core/typename.go @@ -7,12 +7,23 @@ import ( "github.com/sqlc-dev/sqlc/internal/sql/ast" ) -// TypeNameString is the catalog's name for the type an AST node names: the type -// as it was written, lowercased, with "[]" appended for an array. Engines -// report a type either as a plain name or as a list of qualifying parts. -func TypeNameString(tn *ast.TypeName) string { +// TypeExprOfTypeName reads the type an AST node names into an expression. +// An engine that renders the whole type as a call expression — DuckDB's +// struct(a: integer, b: varchar) — hands it over in Canonical; one that +// folds it into the spelling the formatter prints back — ClickHouse's +// Array(Nullable(String)), SQLite's VARYING CHARACTER(10) — in Spelling. +// Otherwise the name comes from Name or the qualifying parts of Names, the +// type modifiers become integer or string arguments, and each array bound +// wraps the result in an array. +func TypeExprOfTypeName(tn *ast.TypeName) *TypeExpr { if tn == nil { - return "" + return nil + } + if tn.Canonical != "" { + return ParseTypeExpr(tn.Canonical) + } + if tn.Spelling != "" { + return ParseTypeExpr(tn.Spelling) } name := strings.TrimSpace(tn.Name) if name == "" && tn.Names != nil { @@ -27,33 +38,113 @@ func TypeNameString(tn *ast.TypeName) string { name = strings.Join(parts, ".") } name = strings.ToLower(name) - if name != "" && tn.ArrayBounds != nil && len(tn.ArrayBounds.Items) > 0 { - name += ArraySuffix + if name == "" { + return nil + } + // An engine that reports the schema apart from the name qualifies it + // the way a dotted name does, so the type resolves in its namespace. + if schema := strings.ToLower(tn.Schema); schema != "" && schema != "pg_catalog" && !strings.Contains(name, ".") { + name = schema + "." + name } - return name + // A name an engine spelled with its own arguments or array suffix reads + // the same way a spelling does. + t := ParseTypeExpr(name) + for _, item := range listItems(tn.Typmods) { + if arg, ok := typmodArg(item); ok { + t.Args = append(t.Args, arg) + } + } + for range listItems(tn.ArrayBounds) { + t = Array(t) + } + return t } -// ResolveType returns the type an AST node names, registering it when the -// dialect's seed did not: a schema is free to declare types of its own. -func (c *Catalog) ResolveType(tn *ast.TypeName) (int64, error) { - name := TypeNameString(tn) - if name == "" { - return 0, fmt.Errorf("missing type name") +// ColumnTypeExpr reads a column definition's type. Engines report an array +// column either on the type name or on the column itself. +func ColumnTypeExpr(col *ast.ColumnDef) *TypeExpr { + if col == nil { + return nil + } + t := TypeExprOfTypeName(col.TypeName) + if t == nil { + return nil + } + // MySQL reports an unsigned column on the definition, and the + // members of an enum or set apart from the type's name. + if col.IsUnsigned && !strings.Contains(t.Name, " unsigned") { + t.Name += " unsigned" + } + if vals := listItems(col.Vals); len(vals) > 0 && len(t.Args) == 0 { + for _, item := range vals { + if s, ok := item.(*ast.String); ok { + v := s.Str + t.Args = append(t.Args, TypeArg{String: &v}) + } + } } - return c.ResolveTypeName(name) + if col.TypeName.Canonical != "" || col.TypeName.Spelling != "" || listItems(col.TypeName.ArrayBounds) != nil { + return t + } + dims := col.ArrayDims + if dims == 0 && col.IsArray { + dims = 1 + } + for i := 0; i < dims; i++ { + t = Array(t) + } + return t } -// ResolveTypeName is ResolveType for a type already reduced to its name. -func (c *Catalog) ResolveTypeName(name string) (int64, error) { - if oid, err := c.TypeOID(name); err == nil { - return oid, nil - } - if element, ok := strings.CutSuffix(name, ArraySuffix); ok { - elementOID, err := c.ResolveTypeName(element) - if err != nil { - return 0, err +// typmodArg reads one type modifier as an argument: an integer, a quoted +// string, or a bare word, which is an identifier such as the max of +// nvarchar(max) or the day to second of an interval. A constant node holds +// a literal; a bare String node holds a word. +func typmodArg(n ast.Node) (TypeArg, bool) { + switch v := n.(type) { + case *ast.A_Const: + switch val := v.Val.(type) { + case *ast.String: + s := val.Str + return TypeArg{String: &s}, true + default: + return typmodArg(v.Val) + } + case *ast.Integer: + i := v.Ival + return TypeArg{Int: &i}, true + case *ast.String: + s := strings.ToLower(v.Str) + return TypeArg{Ident: &s}, true + case *ast.ColumnRef: + parts := make([]string, 0, len(listItems(v.Fields))) + for _, item := range listItems(v.Fields) { + if s, ok := item.(*ast.String); ok { + parts = append(parts, s.Str) + } + } + if len(parts) == 0 { + return TypeArg{}, false } - return c.CreateArrayType(name, elementOID) + ident := strings.ToLower(strings.Join(parts, ".")) + return TypeArg{Ident: &ident}, true + } + return TypeArg{}, false +} + +func listItems(l *ast.List) []ast.Node { + if l == nil { + return nil + } + return l.Items +} + +// ResolveType interns the type an AST node names, registering it when the +// dialect's seed did not: a schema is free to declare types of its own. +func (c *Catalog) ResolveType(tn *ast.TypeName) (int64, error) { + t := TypeExprOfTypeName(tn) + if t == nil { + return 0, fmt.Errorf("missing type name") } - return c.CreateUserType(name, "U") + return c.ResolveTypeExpr(t) } diff --git a/internal/core/types.go b/internal/core/types.go index d97abd7f27..7c482a1f2b 100644 --- a/internal/core/types.go +++ b/internal/core/types.go @@ -3,27 +3,124 @@ package core import ( "context" "database/sql" + "errors" "fmt" + "slices" "strings" + "sync" "github.com/sqlc-dev/sqlc/internal/core/catalogdb" ) +// TypeSpec describes a type row. Name is the family's name; Expr is the +// canonical spelling of the whole expression and defaults to the name, which +// is what a family's is. type TypeSpec struct { Name string - Size int + Expr string Typtype string Category string Preferred bool NamespaceOID int64 DialectOID int64 + FamilyOID int64 ElementOID int64 + BaseOID int64 + CanonicalOID int64 + NotNull bool } -func (c *Catalog) CreateType(name string, size int) (int64, error) { - return c.CreateTypeSpec(TypeSpec{Name: name, Size: size, Typtype: "b"}) +// TypeInfo is a type row as the catalog holds it. +type TypeInfo struct { + OID int64 + NamespaceOID int64 + Name string + Expr string + Category string + Typtype string + Preferred bool + FamilyOID int64 + ElementOID int64 + BaseOID int64 + CanonicalOID int64 + NotNull bool +} + +// IsFamily reports whether the row is a family rather than an instance. +func (t TypeInfo) IsFamily() bool { return t.FamilyOID == 0 } + +// typeCache remembers what the catalog holds about a type. A row never +// changes once written, and a restored catalog is read-only, so a cached +// answer is good for the life of the catalog. Analysis runs concurrently on +// a restored catalog, so the cache is locked. +type typeCache struct { + mu sync.RWMutex + infos map[int64]TypeInfo + exprs map[int64]*TypeExpr + namespaces map[int64]string + namespaceOIDs map[string]int64 +} + +func (c *typeCache) namespace(oid int64) (string, bool) { + c.mu.RLock() + defer c.mu.RUnlock() + name, ok := c.namespaces[oid] + return name, ok +} + +func (c *typeCache) namespaceOID(name string) (int64, bool) { + c.mu.RLock() + defer c.mu.RUnlock() + oid, ok := c.namespaceOIDs[name] + return oid, ok +} + +func (c *typeCache) putNamespace(oid int64, name string) { + c.mu.Lock() + defer c.mu.Unlock() + if c.namespaces == nil { + c.namespaces = map[int64]string{} + c.namespaceOIDs = map[string]int64{} + } + c.namespaces[oid] = name + c.namespaceOIDs[name] = oid +} + +func (c *typeCache) info(oid int64) (TypeInfo, bool) { + c.mu.RLock() + defer c.mu.RUnlock() + info, ok := c.infos[oid] + return info, ok +} + +func (c *typeCache) expr(oid int64) (*TypeExpr, bool) { + c.mu.RLock() + defer c.mu.RUnlock() + e, ok := c.exprs[oid] + return e, ok +} + +func (c *typeCache) put(info TypeInfo, expr *TypeExpr) { + c.mu.Lock() + defer c.mu.Unlock() + if c.infos == nil { + c.infos = map[int64]TypeInfo{} + c.exprs = map[int64]*TypeExpr{} + } + c.infos[info.OID] = info + if expr != nil { + c.exprs[info.OID] = expr + } } +func (c *Catalog) CreateType(name string) (int64, error) { + return c.CreateTypeSpec(TypeSpec{Name: name, Typtype: "b"}) +} + +// CreateTypeSpec inserts a type row. It is the raw insert: nothing is +// canonicalized and no arguments are written, so it is what the seed and +// ResolveTypeExpr build on rather than what a caller with an expression +// wants. func (c *Catalog) CreateTypeSpec(t TypeSpec) (int64, error) { if t.Typtype == "" { t.Typtype = "b" @@ -35,58 +132,74 @@ func (c *Catalog) CreateTypeSpec(t TypeSpec) (int64, error) { } t.NamespaceOID = oid } + name := strings.ToLower(t.Name) + expr := t.Expr + if expr == "" { + expr = name + } oid, err := c.q.CreateType(context.Background(), catalogdb.CreateTypeParams{ - Name: strings.ToLower(t.Name), - Size: int64(t.Size), + Name: name, + Expr: expr, Typtype: t.Typtype, Category: nullString(t.Category), Preferred: boolToInt64(t.Preferred), NamespaceOid: t.NamespaceOID, DialectOid: nullInt64(t.DialectOID), + FamilyOid: nullInt64(t.FamilyOID), ElementOid: nullInt64(t.ElementOID), + BaseOid: nullInt64(t.BaseOID), + CanonicalOid: nullInt64(t.CanonicalOID), + NotNull: boolToInt64(t.NotNull), }) if err != nil { - return 0, fmt.Errorf("create type %q: %w", t.Name, err) + return 0, fmt.Errorf("create type %q: %w", expr, err) } return oid, nil } -// ArraySuffix marks the type of an array of the type it is appended to. The -// catalog names an array type after its element, the way a schema spells it. +// ArraySuffix is the suffix a schema appends to an element type's spelling +// to name an array of it, which ParseTypeExpr reads as one array dimension. const ArraySuffix = "[]" -// CreateUserType registers a type a schema declared rather than the dialect, -// such as an enum or a name the dialect's seed does not list. The type gains -// the dialect's comparison operators, so a column of it can be compared. +// CreateUserType registers a type family a schema declared rather than the +// dialect, such as an enum or a name the dialect's seed does not list. The +// type gains the dialect's comparison operators, so a column of it can be +// compared. func (c *Catalog) CreateUserType(name, category string) (int64, error) { typtype := "b" if category == "E" { typtype = "e" } - oid, err := c.CreateTypeSpec(TypeSpec{ - Name: name, - Typtype: typtype, - Category: category, - DialectOID: c.dialectOID, - }) + nsOID, bare, err := c.declaredTypeNamespace(strings.ToLower(name)) if err != nil { - return 0, err + return 0, fmt.Errorf("create type %q: %w", name, err) } - if err := c.createComparisons(oid); err != nil { - return 0, err + spec := TypeSpec{ + Name: bare, + NamespaceOID: nsOID, + Typtype: typtype, + Category: category, + DialectOID: c.dialectOID, } - return oid, nil -} - -// CreateArrayType registers the array type over elementOID. -func (c *Catalog) CreateArrayType(name string, elementOID int64) (int64, error) { - oid, err := c.CreateTypeSpec(TypeSpec{ - Name: name, - Typtype: "b", - Category: "A", - DialectOID: c.dialectOID, - ElementOID: elementOID, - }) + // A dialect may say what an unknown spelling stands on, as SQLite's + // affinity rule does; the type then resolves through that base and + // needs no operators of its own. + if category == "U" { + baseOID, err := c.userTypeBase(bare) + if err != nil { + return 0, err + } + if baseOID != 0 { + base, err := c.LookupType(baseOID) + if err != nil { + return 0, err + } + spec.BaseOID = baseOID + spec.Category = base.Category + return c.CreateTypeSpec(spec) + } + } + oid, err := c.CreateTypeSpec(spec) if err != nil { return 0, err } @@ -128,8 +241,8 @@ func (c *Catalog) createComparisons(typeOID int64) error { return nil } -// TypeOIDsInCategory returns the types the catalog's dialect has in the named -// category, in the order they were created. +// TypeOIDsInCategory returns the type families the catalog's dialect has in +// the named category, in the order they were created. func (c *Catalog) TypeOIDsInCategory(category string) ([]int64, error) { oids, err := c.q.TypeOIDsInCategory(context.Background(), catalogdb.TypeOIDsInCategoryParams{ DialectOid: nullInt64(c.dialectOID), @@ -141,42 +254,531 @@ func (c *Catalog) TypeOIDsInCategory(category string) ([]int64, error) { return oids, nil } +// TypeOID returns the family a name refers to: an alias spelling resolves to +// the type it names. func (c *Catalog) TypeOID(name string) (int64, error) { - oid, err := c.q.TypeOIDByName(context.Background(), strings.ToLower(name)) + oid, err := c.familyOIDByName(strings.ToLower(name)) if err != nil { return 0, fmt.Errorf("type %q: %w", name, err) } + return c.canonicalOID(oid) +} + +// familyOIDByName finds the family row a bare name refers to, alias rows +// included, in the default namespaces: the catalog's own, PostgreSQL's +// system catalog and the dialect's default schema, in that order of +// preference. A type in any other namespace is reached by qualifying it, +// as PostgreSQL reaches one off the search path. +func (c *Catalog) familyOIDByName(name string) (int64, error) { + nsOIDs, err := c.defaultNamespaceOIDs() + if err != nil { + return 0, err + } + rows, err := c.q.TypeOIDsByNameInNamespaces(context.Background(), catalogdb.TypeOIDsByNameInNamespacesParams{ + Name: name, + NamespaceOids: nsOIDs, + }) + if err != nil { + return 0, err + } + for _, ns := range nsOIDs { + for _, row := range rows { + if row.NamespaceOid == ns { + return row.Oid, nil + } + } + } + return 0, sql.ErrNoRows +} + +// defaultNamespaceOIDs lists the namespaces a bare type name is looked up +// in, in order of preference, skipping any the catalog does not have yet. +func (c *Catalog) defaultNamespaceOIDs() ([]int64, error) { + names := []string{"pg_catalog", "public"} + if c.dialectOID != 0 { + if name, _ := c.DialectFlag(c.dialectOID, FlagDefaultSchema); name != "" { + names = append(names, name) + } + } + out := make([]int64, 0, len(names)) + for _, name := range names { + oid, err := c.namespaceOIDByName(name) + if err != nil { + continue + } + out = append(out, oid) + } + return out, nil +} + +// namespaceOIDByName is NamespaceOID with the answer remembered, since a +// type lookup asks for the same few namespaces every time. A namespace +// created after the answer was cached is found on the next miss. +func (c *Catalog) namespaceOIDByName(name string) (int64, error) { + if oid, ok := c.types.namespaceOID(name); ok { + return oid, nil + } + oid, err := c.NamespaceOID(name) + if err != nil { + return 0, err + } + c.types.putNamespace(oid, name) return oid, nil } -func (c *Catalog) TypeName(oid int64) (string, error) { - name, err := c.q.TypeNameByOID(context.Background(), oid) +// familyOIDByQualifiedName is familyOIDByName for a name that may carry its +// namespace, as myschema.mood does: a qualified name is looked up in that +// namespace alone. +func (c *Catalog) familyOIDByQualifiedName(name string) (int64, error) { + ns, bare := splitQualifiedName(name) + if ns == "" { + return c.familyOIDByName(bare) + } + nsOID, err := c.namespaceOIDByName(ns) if err != nil { - return "", fmt.Errorf("type oid %d: %w", oid, err) + return 0, err } - return name, nil + return c.q.TypeOIDByNameInNamespace(context.Background(), catalogdb.TypeOIDByNameInNamespaceParams{ + NamespaceOid: nsOID, + Name: bare, + }) } -type TypeInfo struct { - OID int64 - Name string - Category string - Typtype string - Preferred bool +// TypeDeclared reports whether a schema's CREATE TYPE would redeclare a +// type: one of that name in the namespace the name qualifies, or in the +// default namespaces for a bare name. +func (c *Catalog) TypeDeclared(name string) bool { + _, err := c.familyOIDByQualifiedName(strings.ToLower(name)) + return err == nil +} + +// splitQualifiedName splits "myschema.mood" into its namespace and name. A +// name with no dot has no namespace. +func splitQualifiedName(name string) (ns, bare string) { + if i := strings.LastIndexByte(name, '.'); i > 0 { + return name[:i], name[i+1:] + } + return "", name } +// declaredTypeNamespace is the namespace a declared type's row goes in: the +// one its name qualifies, created if the schema has not, or the dialect's +// default schema — dbo, main — so that a bare CREATE TYPE and a qualified +// reference to it name one row. +func (c *Catalog) declaredTypeNamespace(name string) (int64, string, error) { + ns, bare := splitQualifiedName(name) + if ns == "" { + if c.dialectOID != 0 { + ns, _ = c.DialectFlag(c.dialectOID, FlagDefaultSchema) + } + if ns == "" { + return 0, bare, nil + } + } + oid, err := c.NamespaceOID(ns) + if err != nil { + if oid, err = c.CreateNamespace(ns); err != nil { + return 0, "", err + } + } + return oid, bare, nil +} + +// CreateTypeWithArgs registers a declared type that has arguments of its own +// — a composite's fields, an enum's labels — as a family row carrying them. +// The arguments' types are interned first. +func (c *Catalog) CreateTypeWithArgs(spec TypeSpec, args []TypeArg) (int64, error) { + nsOID, bare, err := c.declaredTypeNamespace(strings.ToLower(spec.Name)) + if err != nil { + return 0, fmt.Errorf("create type %q: %w", spec.Name, err) + } + spec.Name = bare + if nsOID != 0 { + spec.NamespaceOID = nsOID + } + if spec.DialectOID == 0 { + spec.DialectOID = c.dialectOID + } + argOIDs := make([]int64, len(args)) + for i, a := range args { + if a.Type == nil { + continue + } + oid, _, err := c.internType(a.Type, func(name string) (int64, error) { + return c.CreateUserType(name, "U") + }, true) + if err != nil { + return 0, fmt.Errorf("create type %q: %w", spec.Name, err) + } + argOIDs[i] = oid + } + oid, err := c.CreateTypeSpec(spec) + if err != nil { + return 0, err + } + if err := c.createComparisons(oid); err != nil { + return 0, err + } + return oid, c.insertTypeArgs(oid, spec.Expr, args, argOIDs) +} + +// insertTypeArgs writes a type's argument rows. +func (c *Catalog) insertTypeArgs(oid int64, key string, args []TypeArg, argOIDs []int64) error { + ctx := context.Background() + for i, a := range args { + p := catalogdb.CreateTypeArgParams{TypeOid: oid, Ord: int64(i + 1), Label: a.Label} + switch { + case a.Type != nil: + p.ArgTypeOid = nullInt64(argOIDs[i]) + p.Nullable = boolToInt64(a.Type.Nullable) + case a.Int != nil: + p.IntValue = sql.NullInt64{Int64: *a.Int, Valid: true} + case a.Bool != nil: + p.BoolValue = sql.NullInt64{Int64: boolToInt64(*a.Bool), Valid: true} + case a.String != nil: + p.StringValue = sql.NullString{String: *a.String, Valid: true} + case a.Ident != nil: + p.Ident = sql.NullString{String: *a.Ident, Valid: true} + } + if err := c.q.CreateTypeArg(ctx, p); err != nil { + return fmt.Errorf("type %q: argument %d: %w", key, i+1, err) + } + } + return nil +} + +// canonicalOID follows an alias row to the row it stands for. +func (c *Catalog) canonicalOID(oid int64) (int64, error) { + for i := 0; i < 16; i++ { + info, err := c.LookupType(oid) + if err != nil { + return 0, err + } + if info.CanonicalOID == 0 { + return oid, nil + } + oid = info.CanonicalOID + } + return 0, fmt.Errorf("type oid %d: alias chain does not end", oid) +} + +// ResolutionOID is the row an operator, function or cast over the type is +// looked up on when none is registered on the type itself: an instance's +// family, an alias's canonical type, a domain's or wrapper's base. It +// returns 0 when there is nothing further to fall back to. +func (c *Catalog) ResolutionOID(oid int64) int64 { + info, err := c.LookupType(oid) + if err != nil { + return 0 + } + switch { + case info.CanonicalOID != 0: + return info.CanonicalOID + case info.FamilyOID != 0: + return info.FamilyOID + case info.BaseOID != 0: + return info.BaseOID + } + return 0 +} + +// ResolutionChain lists the type and every row resolution falls back to, in +// order, ending with the family everything about the type is registered on. +func (c *Catalog) ResolutionChain(oid int64) []int64 { + chain := []int64{oid} + for i := 0; i < 16 && oid != 0; i++ { + oid = c.ResolutionOID(oid) + if oid != 0 { + chain = append(chain, oid) + } + } + return chain +} + +// TypeName returns the family name of a type row. +func (c *Catalog) TypeName(oid int64) (string, error) { + info, err := c.LookupType(oid) + if err != nil { + return "", err + } + return info.Name, nil +} + +// LookupType returns what the catalog holds about a type row. func (c *Catalog) LookupType(oid int64) (TypeInfo, error) { + if info, ok := c.types.info(oid); ok { + return info, nil + } row, err := c.q.LookupType(context.Background(), oid) if err != nil { return TypeInfo{}, fmt.Errorf("lookup type oid %d: %w", oid, err) } - return TypeInfo{ - OID: row.Oid, - Name: row.Name, - Category: row.Category.String, - Typtype: row.Typtype, - Preferred: row.Preferred != 0, - }, nil + info := TypeInfo{ + OID: row.Oid, + NamespaceOID: row.NamespaceOid, + Name: row.Name, + Expr: row.Expr, + Category: row.Category.String, + Typtype: row.Typtype, + Preferred: row.Preferred != 0, + FamilyOID: orZero(row.FamilyOid), + ElementOID: orZero(row.ElementOid), + BaseOID: orZero(row.BaseOid), + CanonicalOID: orZero(row.CanonicalOid), + NotNull: row.NotNull != 0, + } + c.types.put(info, nil) + return info, nil +} + +// namespaceName is the name of a namespace row, remembered once read. +func (c *Catalog) namespaceName(oid int64) (string, error) { + if name, ok := c.types.namespace(oid); ok { + return name, nil + } + namespaces, err := c.Namespaces() + if err != nil { + return "", err + } + for _, ns := range namespaces { + c.types.putNamespace(ns.OID, ns.Name) + } + name, _ := c.types.namespace(oid) + return name, nil +} + +// TypeExprOf is the expression a type row stands for, read back from its +// arguments: the family's name for a family, the family applied to its +// arguments for an instance. The result is the caller's to change. +func (c *Catalog) TypeExprOf(oid int64) (*TypeExpr, error) { + if e, ok := c.types.expr(oid); ok { + return e.Clone(), nil + } + info, err := c.LookupType(oid) + if err != nil { + return nil, err + } + expr := &TypeExpr{Name: c.qualifiedName(info)} + if !info.IsFamily() { + rows, err := c.q.TypeArgs(context.Background(), oid) + if err != nil { + return nil, fmt.Errorf("type oid %d: arguments: %w", oid, err) + } + for _, r := range rows { + arg := TypeArg{Label: r.Label} + switch { + case r.ArgTypeOid.Valid: + t, err := c.TypeExprOf(r.ArgTypeOid.Int64) + if err != nil { + return nil, err + } + t.Nullable = r.Nullable != 0 + arg.Type = t + case r.IntValue.Valid: + v := r.IntValue.Int64 + arg.Int = &v + case r.BoolValue.Valid: + v := r.BoolValue.Int64 != 0 + arg.Bool = &v + case r.StringValue.Valid: + v := r.StringValue.String + arg.String = &v + case r.Ident.Valid: + v := r.Ident.String + arg.Ident = &v + } + expr.Args = append(expr.Args, arg) + } + } + c.types.put(info, expr) + return expr.Clone(), nil +} + +// qualifiedName is the name a type row is known by in an expression: its +// name, qualified with its namespace when that is not one of the dialect's +// defaults, as format_type prints a type off the search path. An +// instance's key is built from these, so the array of one schema's mood is +// a row apart from the array of another's. +func (c *Catalog) qualifiedName(info TypeInfo) string { + if ns, err := c.namespaceName(info.NamespaceOID); err == nil && ns != "" && !slices.Contains(c.DefaultNamespaces(), ns) { + return ns + "." + info.Name + } + return info.Name +} + +// ResolveTypeExpr interns the type an expression names and returns its row: +// the family for a bare name, the instance for a family applied to +// arguments, each argument type interned first. Names are canonicalized, so +// integer and int4 intern to one row. A family the dialect did not seed is +// one the schema declared, and is registered as a user type. +func (c *Catalog) ResolveTypeExpr(t *TypeExpr) (int64, error) { + oid, _, err := c.internType(t, func(name string) (int64, error) { + return c.CreateUserType(name, "U") + }, true) + return oid, err +} + +// ResolvePseudoTypeExpr is ResolveTypeExpr for the type a function signature +// names. Signatures reference pseudo-types ("any", "record") and types no +// dialect bothers to list, so an unknown family is registered as an opaque +// type rather than rejected, and gets no operators of its own. +func (c *Catalog) ResolvePseudoTypeExpr(t *TypeExpr) (int64, error) { + oid, _, err := c.internType(t, func(name string) (int64, error) { + return c.CreateTypeSpec(TypeSpec{Name: name, Category: "U", DialectOID: c.dialectOID}) + }, true) + return oid, err +} + +// ResolveTypeName is ResolveTypeExpr for a type spelled as a string. +func (c *Catalog) ResolveTypeName(name string) (int64, error) { + return c.ResolveTypeExpr(ParseTypeExpr(name)) +} + +var errUnknownType = errors.New("unknown type") + +// TypeLookup is what LookupTypeExpr found for an expression. +type TypeLookup struct { + // OID is the instance row when the catalog holds one, otherwise the + // family row. + OID int64 + // FamilyOID is the family, which is OID for a family or an instance the + // catalog does not hold. + FamilyOID int64 + // Expr is the expression canonicalized: the family and every argument + // type spelled as the catalog spells them, whether or not the instance + // is a row. + Expr *TypeExpr +} + +// LookupTypeExpr finds the row an expression names without writing, and +// reports false when the family is not one the catalog holds. +func (c *Catalog) LookupTypeExpr(t *TypeExpr) (TypeLookup, bool) { + refuse := func(string) (int64, error) { return 0, errUnknownType } + oid, canonical, err := c.internType(t, refuse, false) + if errors.Is(err, errUnknownType) && canonical != nil { + // The family is known and the instance is not a row. + familyOID, _, err := c.internType(&TypeExpr{Name: canonical.Name}, refuse, false) + if err != nil { + return TypeLookup{}, false + } + return TypeLookup{OID: familyOID, FamilyOID: familyOID, Expr: canonical}, true + } + if err != nil { + return TypeLookup{}, false + } + info, err := c.LookupType(oid) + if err != nil { + return TypeLookup{}, false + } + familyOID := oid + if !info.IsFamily() { + familyOID = info.FamilyOID + } + return TypeLookup{OID: oid, FamilyOID: familyOID, Expr: canonical}, true +} + +// internType resolves an expression to its row, creating the instance row +// when there is none and write allows it, and calling newFamily for a +// family name the catalog does not hold, which may refuse. Alongside the +// row it returns the expression canonicalized; when the instance is not a +// row and writing is not allowed, the canonical expression still comes +// back with errUnknownType. +func (c *Catalog) internType(t *TypeExpr, newFamily func(name string) (int64, error), write bool) (int64, *TypeExpr, error) { + if t == nil || strings.TrimSpace(t.Name) == "" { + return 0, nil, fmt.Errorf("missing type name") + } + t, err := c.canonicalize(t) + if err != nil { + return 0, nil, err + } + name := strings.ToLower(strings.TrimSpace(t.Name)) + familyOID, err := c.familyOIDByQualifiedName(name) + if err != nil { + if name == ArrayTypeName && write { + // Every dialect has arrays, whether or not its seed lists the + // family; one that does not gets it as an array type rather + // than a user type. + familyOID, err = c.CreateTypeSpec(TypeSpec{Name: name, Category: "A", DialectOID: c.dialectOID}) + } else { + familyOID, err = newFamily(name) + } + if err != nil { + return 0, nil, fmt.Errorf("type %q: %w", name, err) + } + } + if familyOID, err = c.canonicalOID(familyOID); err != nil { + return 0, nil, err + } + family, err := c.LookupType(familyOID) + if err != nil { + return 0, nil, err + } + if len(t.Args) == 0 { + return familyOID, &TypeExpr{Name: c.qualifiedName(family)}, nil + } + + // The instance's canonical spelling is the family applied to its + // arguments as the catalog spells them, so each argument type is + // resolved first and read back. An argument whose own instance is not + // a row, in a lookup that may not write, still has a canonical + // spelling, which the whole expression's is built from. + canonical := &TypeExpr{Name: c.qualifiedName(family), Args: make([]TypeArg, len(t.Args))} + argOIDs := make([]int64, len(t.Args)) + unknown := false + for i, a := range t.Args { + canonical.Args[i] = a + if a.Type == nil { + continue + } + oid, argExpr, err := c.internType(a.Type, newFamily, write) + if err != nil { + if !errors.Is(err, errUnknownType) || argExpr == nil { + return 0, nil, err + } + unknown = true + } + argOIDs[i] = oid + argExpr.Nullable = a.Type.Nullable + canonical.Args[i].Type = argExpr + } + if unknown { + return 0, canonical, errUnknownType + } + key := canonical.Key() + ctx := context.Background() + if oid, err := c.q.TypeOIDByExprInNamespace(ctx, catalogdb.TypeOIDByExprInNamespaceParams{ + NamespaceOid: family.NamespaceOID, + Expr: key, + }); err == nil { + return oid, canonical, nil + } else if !errors.Is(err, sql.ErrNoRows) { + return 0, nil, fmt.Errorf("type %q: %w", key, err) + } + // A lookup that may not write stops here, canonical expression in hand. + if !write { + return 0, canonical, errUnknownType + } + + spec := TypeSpec{ + Name: family.Name, + Expr: key, + Typtype: family.Typtype, + Category: family.Category, + NamespaceOID: family.NamespaceOID, + DialectOID: c.dialectOID, + FamilyOID: familyOID, + } + if family.Name == ArrayTypeName && argOIDs[0] != 0 { + spec.ElementOID = argOIDs[0] + } + oid, err := c.CreateTypeSpec(spec) + if err != nil { + return 0, nil, err + } + if err := c.insertTypeArgs(oid, key, canonical.Args, argOIDs); err != nil { + return 0, nil, err + } + return oid, canonical, nil } func nullableOID(oid int64) any { diff --git a/internal/core/types.md b/internal/core/types.md new file mode 100644 index 0000000000..771b09c9d5 --- /dev/null +++ b/internal/core/types.md @@ -0,0 +1,769 @@ +# Types in the analysis core + +How the core catalog, the analyzer and `sqlc analyze` represent a type today, +where that falls short of each engine's type system, how each engine's own +catalog represents one, and the design that closes the gap: every type the +schema or the dialect declares is a row holding its full expression, +canonicalized the way the engine would and denormalized so that a bare name +like `integer` and a structured expression like `numeric(10, 2)` both +resolve to one. + +## What a type is today + +The catalog (`catalogdef/schema.sql`) has one row per *name* in `sql_type`: +a lowercased string, a category letter, a `typtype` that is only ever `b` or +`e`, and an `element_oid` that is written for arrays but never read. A +dialect's `types.jsonl` seeds one row per type and one more per alias, then +joins every spelling of a type to every other with implicit casts. Arrays are +rows named after their element with `[]` appended, created on first use. +Anything else — a type argument, a struct field, an enum label, a domain's +base, a range's subtype — has nowhere to go: `sql_attribute` keeps the +column's verbatim spelling in `decl_type` (only SQLite and ClickHouse set it) +and has `type_length` and `type_scale` columns that no DDL path fills. + +The analyzer (`analyzer/expr.go`) types an expression as `exprType`: a type +OID, or a bare name when the catalog has no row, plus nullability. A type is +therefore a row, and a type that is not a row degrades to whatever row its +spelling's first word finds. + +The output (`TypeExpr` in `typeexpr.go`, printed by `sqlc analyze`) already +has the right shape: a name applied to labelled arguments that are types, +integers, booleans or strings, with `nullable` at any depth. It is complete +only where a source column's `decl_type` spelling exists to be parsed; every +other column and every parameter is rebuilt from the flat row name. + +## What each engine loses + +The table is what `sqlc analyze` reports today for a schema exercising each +engine's type system, against what the engine itself says the type is. + +| Engine | Declared | Reported | The engine says | +|---|---|---|---| +| PostgreSQL | `numeric(10,2)`, `varchar(255)`, `timestamp(3)`, `bit(8)` | `numeric`, `varchar`, `timestamp`, `bit` | typmods are part of the type | +| PostgreSQL | `int[][]` | `array(int4)` | two dimensions | +| PostgreSQL | `CREATE DOMAIN posint AS integer` | `posint`, category U | an integer with a constraint | +| PostgreSQL | `CREATE TYPE point2 AS (x float8, y float8)` | `point2`, category U | two named fields | +| PostgreSQL | `CREATE TYPE mood AS ENUM (...)` | `mood` | the labels | +| PostgreSQL | `CREATE TYPE floatrange AS RANGE (subtype = float8)` | `floatrange`, category U | a range over float8 | +| PostgreSQL | `myschema.mood` | `mood` for a column, `myschema.mood` for a cast: two rows, both in `public` | one type in a namespace | +| PostgreSQL | `interval day to second` | `interval` | fields are a typmod | +| MySQL | `BIGINT UNSIGNED`, `INT UNSIGNED` | `bigint`, `int` | a different value range; codegen picks `int64` over `uint64` | +| MySQL | `TINYINT(1)` | `tinyint` | the display width is how drivers and codegen spot a boolean | +| MySQL | `DECIMAL(10,2) UNSIGNED`, `DATETIME(6)`, `VARCHAR(255)` | `decimal`, `datetime`, `varchar` | precision, fractional seconds, length | +| MySQL | `ENUM('a','b')`, `SET('x','y')` | `enum`, `set` | the members | +| MySQL | `CAST(? AS CHAR(10))` | `var_string` | `char`; the parser's internal name leaks | +| SQLite | `FOO BAR(3)`, `VARCHAR(255)` | `foo bar(3)`, `varchar(255)` | correct spelling, but each is a row of category U that compares with nothing, and the affinity SQLite gives it (NUMERIC, TEXT) is not modelled | +| ClickHouse | every column type | complete | complete, from the spelling | +| ClickHouse | `CAST(x AS Nullable(String))` | `nullable` | `Nullable(String)` | +| ClickHouse | `CAST(x AS Array(UInt8))` | `array` | `Array(UInt8)` | +| ClickHouse | `toDecimal64(x, 4)`, `toDateTime64(x, 3)` | `decimal64`, `datetime64` | `Decimal(18, 4)`, `DateTime64(3)`: the result depends on an argument's value | +| ClickHouse | `SimpleAggregateFunction(sum, UInt64)` | `simpleaggregatefunction(sum, uint64)` | `sum` is a function name, which the expression reads as a type | +| ClickHouse | `n Nested(a UInt8, b String)` | one column `n` | two columns `n.a Array(UInt8)`, `n.b Array(String)` | +| DuckDB | `STRUCT(a INTEGER, b VARCHAR)`, `MAP(VARCHAR, INTEGER)`, `UNION(num INTEGER, str VARCHAR)` | `struct`, `map`, `union` | the fields | +| DuckDB | `INTEGER[]`, `INTEGER[3]`, `INTEGER[][]` | `array(integer)` for all three | LIST, fixed-size ARRAY, nested LIST | +| DuckDB | `DECIMAL(18,3)`, `VARCHAR(10)`, `ENUM('a','b')` | `decimal`, `varchar`, `enum` | arguments and members | +| GoogleSQL | `ARRAY` | a row *named* `array` | an array of int64 | +| GoogleSQL | `STRUCT`, `ARRAY>` | `struct`, `array` | the fields | +| GoogleSQL | `STRING(10)`, `NUMERIC(10,2)`, `[1, 2]`, `STRUCT(1 AS x)` | `string`, `numeric`, untyped, untyped | parameters; a constructed array and struct | +| SQL Server | `NVARCHAR(MAX)`, `VARBINARY(MAX)` | `nvarchar`, `varbinary` | MAX decides the Go type | +| SQL Server | `DECIMAL(10,2)`, `DATETIME2(3)`, `FLOAT(24)`, `VECTOR(3)` | `decimal`, `datetime2`, `float`, `vector` | arguments; `FLOAT(24)` is `real` | +| SQL Server | `CREATE TYPE dbo.PhoneNumber FROM varchar(20) NOT NULL` | `phonenumber`, category U | a `varchar(20)` that is never null, in schema `dbo` | + +Three of these are regressions against the legacy compiler rather than gaps +shared with it: the plugin protocol's `Column` carries `unsigned`, `length` +and `array_dims`, codegen reads all three (`golang/mysql_type.go` turns +`tinyint` with length 1 into `bool` and `unsigned` into `uint64`; +`golang/go_type.go` nests one slice per dimension), and the core bridge in +`compiler/parse_core.go` sets none of them from what the core reports. + +Two are broken outside column declarations only: ClickHouse's columns are +whole because the engine hands the core a spelling and the core keeps it on +the attribute. The same spelling in a cast, a function result or a typed +placeholder has no attribute to live on, so it degrades to its first word. +That is the tell: the expression belongs to the type, not to the column. + +## What each engine's own catalog says + +Each engine was asked, on a live system where one could be had, what it +records about a type, how it spells a column's type back, what it says a +query result's type is, and how it describes a function. PostgreSQL 16, +MySQL 8, SQLite 3.53, ClickHouse 25.8 and DuckDB 1.5 answered directly; SQL +Server and GoogleSQL are from their documented catalogs and the parsers +sqlc uses for them. + +**PostgreSQL** has one `pg_type` row per family, and a second row per array +type (`_int4`, with `typelem` pointing at the element). Arguments are not +part of the type: they are an opaque `int32` typmod on the use site — +`pg_attribute.atttypmod`, a domain's `typtypmod`, a function argument's +type has none — whose encoding is the type's own business and which +`format_type(oid, typmod)` decodes back into a spelling. Dimensions are +likewise on the attribute (`attndims`) and informational: `int[3]` and +`int[][]` are both the type `integer[]`. Declared types are rows with a +`typtype`: `e` with labels and their order in `pg_enum`, `c` with fields as +the attributes of a hidden relation (`typrelid`), `d` with `typbasetype`, +`typtypmod` and `typnotnull`, `r` and `m` with the subtype in `pg_range`; +pseudo-types (`anyarray`, `record`) are rows of `typtype` `p` and category +`P`. What it reports is canonical and not what was written: `int` comes back +as `integer`, `varchar(255)` as `character varying(255)`, `timestamp(3)` as +`timestamp(3) without time zone`, `int[3]` as `integer[]`, and a domain +column as the domain's name. A view keeps its columns' typmods; a prepared +statement's result types (`pg_prepared_statements.result_types`, the +protocol's RowDescription) carry the typmod only for a column read straight +from a table and `-1` for an expression, so `numeric(10,2) + 1` is +`numeric`. `pg_proc` has full signatures over families and pseudo-types, +`pg_operator` likewise, and `pg_cast` the contexts. + +**MySQL** has no catalog of types, functions or operators. What it has is +`information_schema.COLUMNS`, which describes a column twice: `DATA_TYPE` is +the family (`bigint`, `decimal`, `enum`) and `COLUMN_TYPE` is the whole +canonical spelling — `bigint unsigned`, `tinyint(1)`, `decimal(10,2) +unsigned`, `enum('a','b')`, `bigint(20) unsigned zerofill` — beside the +arguments decoded into `NUMERIC_PRECISION`, `NUMERIC_SCALE`, +`CHARACTER_MAXIMUM_LENGTH`, `DATETIME_PRECISION`, `CHARACTER_SET_NAME` and +`COLLATION_NAME`. The spelling is canonical: `BOOLEAN` becomes `tinyint(1)`, +`INTEGER` becomes `int`, `VARCHAR(10) CHARACTER SET binary` becomes +`varbinary(10)`. A view's columns show that the binder computes a full type +for every expression: `decimal(10,2) + 1` is `decimal(11,2)`, `decimal(10,2) +* decimal(10,2)` is `decimal(20,4)`, `int unsigned + 1` is `bigint +unsigned`, `CONCAT(varchar(255), 'x')` is `varchar(256)`, `SUM(int unsigned)` +is `decimal(32,0)`, `AVG(int)` is `decimal(14,4)`, `->>` is `longtext`. User +routines are described the same way in `ROUTINES` and `PARAMETERS` +(`DTD_IDENTIFIER` is `decimal(5,2)`, `bigint unsigned`); built-in functions +are not described at all. A result set on the wire is coarser than the +catalog: a storage type code (`TINY`, `LONG`, `NEWDECIMAL`, `VAR_STRING`), +a length in bytes, a decimals count and flags (`UNSIGNED`, `NOT_NULL`, +`ENUM`, `SET`, `BINARY`), so a `varchar(255)` column and `CAST(x AS +CHAR(10))` are both `VAR_STRING`, an enum is `STRING` with the `ENUM` flag, +and a `tinyint(1)` is `TINY` with length 1. That code is where the parser's +`var_string` comes from. + +**SQLite** has no catalog of types either. `pragma_table_xinfo` returns a +column's declared type verbatim — `VARCHAR(255)`, `FOO BAR(3)`, `my type`, +or nothing — and the type system is affinity: a rule over the spelling's +substrings (INT anywhere is INTEGER; CHAR, CLOB or TEXT is TEXT; BLOB or no +type is BLOB; REAL, FLOA or DOUB is REAL; anything else is NUMERIC) that +decides how a stored value is coerced, so `FOO BAR(3)` holding `'12'` +stores the integer 12. Arguments are decoration: `CAST(x AS DECIMAL(5,2))` +applies NUMERIC affinity and nothing else. A `STRICT` table admits only +`INT`, `INTEGER`, `REAL`, `TEXT`, `BLOB` and `ANY`, and rejects +`VARCHAR(10)`. An expression has no type; a value has a storage class +(`typeof()` is `integer`, `real`, `text`, `blob` or `null`), and a result +column's `sqlite3_column_decltype` is the declared spelling for a column +read from a table and nothing for anything else. `pragma_function_list` +names functions and their arity and nothing more. + +**ClickHouse** models a type as a call expression, which is why the output +shape was chosen. `system.data_type_families` lists 66 families and 73 +aliases (`INT` is an alias of `Int32`); a column's type in `system.columns` +is the whole expression, canonicalized: `Decimal32(4)` is stored as +`Decimal(9, 4)`, `Enum('a', 'b')` as `Enum8('a' = 1, 'b' = 2)`, +`Variant(String, Int64)` with its members sorted, and `Nested(a UInt8, b +String)` as two columns `n.a Array(UInt8)` and `n.b Array(String)`. +`Nullable` and `LowCardinality` are spelled as wrappers and reported as part +of the type, at any depth. Every expression has a full type computed by the +binder, from argument types with promotion — `Int8 + UInt8` is `Int16`, +`Int32 + UInt64` is `Int64`, `Int32 / Int32` is `Float64`, `Decimal(9, 4) * +Decimal(38, 10)` is `Decimal(38, 14)` — from argument values — +`toDecimal64(x, 4)` is `Decimal(18, 4)`, `toDateTime64(x, 3)` is +`DateTime64(3)` — and from literals by value: `1` is `UInt8`, `-1` is +`Int8`, `[1, NULL]` is `Array(Nullable(UInt8))`. Wrappers propagate: +`concat(lc, 'x')` is `LowCardinality(String)`, `ns = 'x'` is +`Nullable(UInt8)`, `NULL` is `Nullable(Nothing)`. A typed placeholder +`{p:Decimal(10, 2)}` is exactly its declared type. `system.functions` has a +name, an aggregate flag, an alias and a description, and no signature. + +**DuckDB** has `duckdb_types()`, one row per spelling with a `logical_type` +naming the family (`int`, `int4` and `integer` are three rows over +`INTEGER`), a category (`NUMERIC`, `STRING`, `DATETIME`, `BOOLEAN`, +`COMPOSITE`, or none for `bit` and `enum`), and `labels` for an enum, which +a `CREATE TYPE ... AS ENUM` adds to as a non-internal row in the user's +schema. `duckdb_columns().data_type` is the whole canonical expression: +`INTEGER[]`, `INTEGER[3]`, `STRUCT(a INTEGER, b VARCHAR)`, `MAP(VARCHAR, +INTEGER)`, `UNION(num INTEGER, str VARCHAR)`, `DECIMAL(18,3)`, with the +precision and scale also decoded into their own columns. Canonicalization +goes further than anywhere else: `TEXT` is `VARCHAR`, `VARCHAR(10)` is +`VARCHAR` (the length is dropped), `NUMERIC` is `DECIMAL(18,3)`, `VARINT` is +`BIGNUM`, `FLOAT4` is `FLOAT`, `JSON` keeps its name over `VARCHAR`'s id, +and a column of the named enum `mood` is reported as `ENUM('sad', 'ok')` +with the name gone. Expressions have full binder-computed types: +`DECIMAL(18,3) * DECIMAL(18,3)` is `DECIMAL(18,6)`, `1.5` is +`DECIMAL(2,1)`, `SUM(INTEGER)` is `HUGEINT`, `SUM(DECIMAL(18,3))` is +`DECIMAL(38,3)`, `INTEGER / 2` is `DOUBLE`, `[1, NULL]` is `INTEGER[]` with +no inner nullability, and `NULL` is a type of its own. `duckdb_functions()` +has signatures over families and generics — `parameter_types` are +`DECIMAL`, `INTEGER[]`, `ANY`, `T`, `K`, `V` and `return_type` a family — +so the arguments of a result are the binder's, not the catalog's. A +prepared statement's parameter types are `UNKNOWN` until bound. + +**SQL Server** describes a column in `sys.columns` as a family plus decoded +arguments: `system_type_id` and `user_type_id`, `max_length` in bytes with +`-1` for `MAX`, `precision`, `scale`, `collation_name`, `is_nullable`, +`is_identity`. `sys.types` has one row per system type — `decimal` and +`numeric` are two — and one per alias type from `CREATE TYPE ... FROM`, with +`is_user_defined`, its own `max_length`, `precision`, `scale` and +`is_nullable`, and its base's `system_type_id`; `sysname` is such a row over +`nvarchar(128)`, and CLR types like `geography` and `hierarchyid` are +assembly types sharing one `system_type_id`. Canonicalization fills in what +was left out and folds one family into another: `varchar` alone is +`varchar(1)` in a declaration and `varchar(30)` in a `CAST`, `decimal` is +`decimal(18,0)`, `datetime2` is `datetime2(7)`, `FLOAT(24)` is stored as +`real` and `FLOAT(25)` and up as `float`. `sys.all_parameters` describes a +function's parameters the same way as a column. The T-SQL parser sqlc uses +(`teesql`) reports a type as a name with a parameter list in which `MAX` is +a literal node of its own. + +**GoogleSQL** has no catalog sqlc can read offline; its two hosts describe a +column as a whole string. BigQuery's `INFORMATION_SCHEMA.COLUMNS.DATA_TYPE` +is `ARRAY>`, `NUMERIC(10, 2)` or `STRING(10)`, +and `COLUMN_FIELD_PATHS` lists every nested struct field with a path and a +`DATA_TYPE` of its own. Spanner's `SPANNER_TYPE` is `STRING(MAX)`, +`ARRAY`, `PROTO` or `ENUM`, and a column +cannot be a struct. The parser sqlc uses (`zetajones`) has a node per type +form — `SimpleType` with a `TypeParameterList`, `ArrayType`, `StructType` +with named fields, `RangeType`, `MapType`, `FunctionType` — and, as in T-SQL, +`MAX` is a literal node in the parameter list. Arrays do not nest. + +What the review settles: + +| | Unit of identity | Where arguments live | Column spelling reported | Result types | Function signatures | +|---|---|---|---|---|---| +| PostgreSQL | family row, plus one row per array type | opaque typmod and dims on the use site | canonical, decoded by `format_type` | family, typmod only for a table column | full, over families and pseudo-types | +| MySQL | none: a spelling | decoded columns beside the spelling | canonical spelling | full, computed by the binder | none for built-ins | +| SQLite | none: the declared text | none: decoration | verbatim | storage class of the value | arity only | +| ClickHouse | family, with aliases | in the spelling | canonical expression | full, computed by the binder | none | +| DuckDB | family, with aliases | in the spelling, plus decoded columns | canonical expression, some arguments dropped | full, computed by the binder | families and generics | +| SQL Server | family row and alias-type row | decoded columns on the use site | canonical, defaults filled in | family and decoded arguments | families and decoded arguments | +| GoogleSQL | none offline: a spelling | in the spelling | canonical spelling | full | none offline | + +Two conclusions follow. First, no engine keeps arguments inside its type +table: PostgreSQL and SQL Server put them on the use site and everything +else puts them in the spelling. A row per expression is nonetheless the +right shape for sqlc, because sqlc's job is to *report* the expression, and +every engine that decodes its use-site arguments decodes them into exactly +the call expression `TypeExpr` already is; PostgreSQL's typmod is a +per-type encoding that only PostgreSQL can read, so sqlc would store the +decoded form either way. Second, every engine with a catalog canonicalizes +on the way in and reports the canonical form, never the declared spelling, +and the same is true of what `goldeneye` checks the analyze cases against. +The design below changes on that point. + +## The design + +### One row per type expression + +`sql_type` keeps one row per distinct type expression. A row is either a +**family** — a name the dialect or the schema declares, such as `numeric`, +`array`, `struct`, `mood` — or an **instance**, a family applied to +arguments, such as `numeric(10, 2)`, `array(int4)` or +`struct(a: int4, b: text)`. The row's `expr` is the expression's canonical +string, which is its interning key; the row's `name` is the family's name, +so the index that turns `integer` into a row keeps working for instances, +and an instance points at its family. + +```sql +CREATE TABLE sql_type ( + oid INTEGER PRIMARY KEY AUTOINCREMENT, + namespace_oid INTEGER NOT NULL REFERENCES sql_namespace(oid), + dialect_oid INTEGER REFERENCES sql_dialect(oid), + name TEXT NOT NULL, -- the family name: 'numeric', 'array', 'mood' + expr TEXT NOT NULL, -- the whole expression, canonical: 'numeric(10, 2)'; equals name for a family + typtype TEXT NOT NULL DEFAULT 'b', -- b base, c composite, d domain, e enum, r range, p pseudo + category TEXT, + preferred INTEGER NOT NULL DEFAULT 0, + family_oid INTEGER REFERENCES sql_type(oid), -- NULL on a family; the family on an instance + element_oid INTEGER REFERENCES sql_type(oid), -- what the type holds: an array's element, a map's value, a range's subtype + base_oid INTEGER REFERENCES sql_type(oid), -- what the type stands on: a domain's or alias type's base, a wrapper's inner type, a SQLite spelling's affinity + canonical_oid INTEGER REFERENCES sql_type(oid), -- the row the engine reports this one as: integer -> int4, float(24) -> real, mood -> enum('sad', 'ok') in DuckDB + not_null INTEGER NOT NULL DEFAULT 0, -- a domain or alias type declared NOT NULL + UNIQUE (namespace_oid, expr) +); +CREATE INDEX idx_sql_type_name ON sql_type(name); + +-- sql_type_arg: the arguments of an instance, or the fields, labels or +-- members of a declared composite, enum or set, in order. Exactly one of +-- arg_type_oid, int_value, bool_value, string_value and ident is set. +CREATE TABLE sql_type_arg ( + type_oid INTEGER NOT NULL REFERENCES sql_type(oid), + ord INTEGER NOT NULL, + label TEXT NOT NULL DEFAULT '', -- a struct field, tuple element or enum label + arg_type_oid INTEGER REFERENCES sql_type(oid), + nullable INTEGER NOT NULL DEFAULT 0, -- the argument type is nullable here: Array(Nullable(String)) + int_value INTEGER, + bool_value INTEGER, + string_value TEXT, + ident TEXT, -- a bare word that is not a type: max, sum, day to second + PRIMARY KEY (type_oid, ord) +); +``` + +`size` goes: nothing reads it. `type_length` and `type_scale` leave +`sql_attribute`: they were one engine's two arguments, and now every +engine's arguments are rows. `decl_type` stays, since the verbatim spelling +is what the formatter prints back and what SQLite reports. + +The four pointer columns are the denormalization. Each is derivable by +walking `sql_type_arg`, and each is what resolution asks for in one +statement: + +- `family_oid` is what operator and function lookup fall back to when there + is no overload on the instance: `numeric(10, 2) + numeric(5, 1)` finds no + operator on either instance and resolves on `numeric`, which is exactly + what `pg_operator` and `duckdb_functions()` hold. +- `element_oid` is what a subscript, `ANY($1)`, `unnest` and a star over a + map yield, and what `IsArray` was; it is PostgreSQL's `typelem` and + `pg_range.rngsubtype`. +- `base_oid` is what a domain, an alias type, `LowCardinality(T)` or a + SQLite spelling resolves through: `posint = 1` finds no operator on + `posint` and resolves on `int4`; `FOO BAR(3) = 1` resolves on `numeric`. + It is `typbasetype`, SQL Server's `system_type_id` behind a + `user_type_id`, and SQLite's affinity rule. +- `canonical_oid` is the row the engine would report this one as. An alias + spelling points at its family (`integer` at `int4`); a declared type + points at what the engine reports instead of its name when it does so + (DuckDB's `mood` at `enum('sad', 'ok')`); an instance points at the + instance canonicalization rewrote it to when the rewrite changes the + family (SQL Server's `float(24)` at `real`). It replaces the n² implicit + casts between spellings of one type. + +A declared type is a family row with arguments of its own. `CREATE TYPE +point2 AS (x float8, y float8)` is a row named `point2`, `typtype` `c`, with +two labelled type arguments, the way PostgreSQL keeps them as the attributes +of `typrelid`; `CREATE TYPE mood AS ENUM ('sad', 'ok')` is a row with +`typtype` `e` and two string arguments in order, which is `pg_enum` and +DuckDB's `labels`; ClickHouse's `Enum8('active' = 1, 'deleted' = 2)` is an +instance of `enum8` with two labelled integer arguments and `base_oid` at +`int8`; `CREATE DOMAIN posint AS integer` and SQL Server's `CREATE TYPE +PhoneNumber FROM varchar(20) NOT NULL` are rows with `typtype` `d`, +`base_oid` at the base instance and `not_null` set. The same table holds +what the schema names and what it constructs anonymously. + +### Canonicalize on the way in; report the canonical form + +Every engine with a catalog rewrites a declared type before storing it and +reports the rewritten form, and `goldeneye` checks the analyze cases against +what the engine reports. So interning canonicalizes, in three steps that +are dialect data or dialect code: + +1. **Aliases**, which `types.jsonl` already lists: `int` and `integer` + resolve to the canonical family. This also settles what the canonical + *name* is: the one the engine reports, which for PostgreSQL is + `format_type`'s (`integer`, `bigint`, `character varying`) rather than + `pg_type`'s (`int4`, `int8`, `varchar`), so PostgreSQL's `types.jsonl` + flips which spelling is the name and which the alias. Codegen accepts + both spellings already. + + `format_type` is a string and the output is an expression, so the + spelling is read into one, and its grammar is slightly wider than + `name(args)`: the typmod may sit inside a multi-word name + (`timestamp(3) without time zone`, `time(4) with time zone`), after + trailing words (`interval day to second(3)`), or before an array suffix + (`numeric(10,2)[]`, `character varying(255)[]`), and one name is quoted + (`"char"`). The family is the words with the parenthesis lifted out, so + `timestamp(3) without time zone` is `{name: "timestamp without time + zone", args: [3]}`, `interval day to second(3)` is `interval` with an + identifier argument and an integer one, and `numeric(10,2)[]` is + `array(numeric(10, 2))`. Two spellings are the same family under + different typmods, `bpchar` and `character(5)`, and canonicalize to + `character`. The PostgreSQL goldens change with this: `bigserial` + becomes `bigint` (a serial is a default, not a type PostgreSQL reports), + `int4` becomes `integer`, `varchar` becomes `character varying`. +2. **Argument defaults and drops**, which are data: SQL Server's `varchar` + is `varchar(1)` and `decimal` is `decimal(18, 0)`; DuckDB's `numeric` is + `decimal(18, 3)` and `varchar(10)` is `varchar`; PostgreSQL's `int[3]` is + `array(int4)`. A family in `types.jsonl` may say `"defaults": [18, 0]` + or `"args": 0`. +3. **Rewrites that change the family by argument**, which are data too: an + ordered list of pattern, template and bound in `dialect.json` — + `Decimal32($1)` to `Decimal(9, $1)`, `float($1)` to `real` where `$1 <= + 24`, `boolean` to `tinyint(1)`, `sysname` to `nvarchar(128)` — that the + seed loads into a table and the catalog applies before interning. What + only a parser can do stays in the engine's converter, which every engine + has anyway: ClickHouse numbers an Enum's members and sorts a Variant's + when it spells the type, and MySQL's parser folds `varchar(n) character + set binary` into `varbinary(n)`. + +The reported type is the canonical row's expression. The declared spelling +is kept on the attribute in `decl_type`, for the formatter and for SQLite, +whose canonical form is the spelling itself. This reverses the earlier +choice of reporting a column as it was declared: the engines do not, and +the check that keeps the analyzer honest compares against the engines. + +### Nullability is not a type + +A row is never nullable. Outer nullability stays where it is: on the +attribute, on the analyzer's `exprType`, on the reported column. Inner +nullability is a flag on the argument position, so `Array(Nullable(String))` +is an instance of `array` whose one argument is `string` with `nullable` +set, and `Nullable(String)` in a cast is `string` with the expression's own +nullability set. This is what `TypeExpr` already says — `nullable` at +whatever depth it applies, never a wrapper — and it keeps `string` and +`string nullable` from being two types that need their own operators. The +review confirms only ClickHouse spells inner nullability at all: DuckDB's +`[1, NULL]` is `INTEGER[]` and PostgreSQL has no such thing. + +### Array dimensions + +PostgreSQL's type for `int[][]` is `integer[]`, with the dimensions on the +attribute and unenforced; DuckDB and ClickHouse nest, `INTEGER[][]` and +`Array(Array(UInt8))`, and DuckDB distinguishes the fixed-size +`INTEGER[3]`. The expression nests one `array` per declared dimension in +every dialect, with a fixed size as a second argument (`array(integer, 3)`), +because codegen renders one slice per dimension and a two-dimensional +PostgreSQL column has to come out `[][]int32` as it does on the legacy path. +PostgreSQL's canonicalization therefore keeps the dimensions its own +catalog drops, and a future PostgreSQL check in `goldeneye` reads `attndims` +to reproduce them. Subscripting follows the dialect: PostgreSQL yields the +innermost element however many subscripts are applied. + +### The catalog interns at schema time; the analyzer looks up at query time + +The cached catalog is opened read-only (`catalog.go` opens it with +`mode=ro&immutable=1`), and `exprType` carries a bare name precisely so that +analysis never has to write. That constraint stands, and it decides which +expressions become rows: + +- **Interned**: what the dialect seeds and what the schema declares. Every + column type, every declared type's fields and base, every function + signature's argument and return type becomes a row on load, through one + entry point, `ResolveTypeExpr(*TypeExpr) (oid, error)`, which + canonicalizes, then walks the expression bottom-up, interning each + argument type first. `ResolveType` and `ResolveTypeName` become callers + of it. +- **Looked up**: what a query writes. A cast, a constructed array or struct, + a typed placeholder and a function result are resolved by + `LookupTypeExpr(*TypeExpr) (oid, familyOID, bool)`, which canonicalizes, + finds the instance row when the schema happened to declare the same + expression and otherwise the family row, and never writes. + +`exprType` becomes the pair: + +```go +type exprType struct { + typeOID int64 // the instance row when the catalog has one, else the family row, else 0 + expr *core.TypeExpr // the whole expression, whenever anything is known about it + nullable bool + ... +} +``` + +Resolution uses `typeOID` and its `family_oid`, `base_oid` and +`canonical_oid` chain; reporting uses `expr`. The `typeName` fallback and +the `[]` suffix convention go away: an array is `array` applied to its +element, in the catalog as in the output, and `TypeNameString` is replaced +by a function that reads an `ast.TypeName` into a `TypeExpr`, folding +`Typmods` into integer arguments, `ArrayBounds` into one `array` per +dimension, `Names` into a namespace and a name, and `Spelling` through +`ParseTypeExpr`. + +### Result types: the family from the catalog, the arguments from the dialect + +MySQL, ClickHouse and DuckDB compute a full type for every expression in the +binder — `decimal(10,2) + 1` is `decimal(11,2)`, `Int8 + UInt8` is `Int16`, +`SUM(INTEGER)` is `HUGEINT` — and none of them keeps those rules in a +catalog; PostgreSQL's catalog says `numeric + numeric` is `numeric` and its +results drop the typmod. The catalog can only ever answer at the family +level, and that is the baseline every dialect gets: an operator or function +result is the family the overload names, with the arguments of an `$n` +result carried over from the argument it stands for. A result that depends +on an argument's value is a template in the seed — `"returns": "Decimal(18, +$2)"` for `toDecimal64(x, s)` — that the analyzer fills in from the call's +literals. ClickHouse needs it, since its check compares whole expressions; +MySQL's check reads the wire type, which is the family with its flags, so +the baseline passes it. Arithmetic promotion — `Int8 + UInt8` is `Int16` — +is not expressed yet. + +### What each engine hands the core + +The contract with an engine is that its `ast.TypeName` reads into a +`TypeExpr` that says everything the engine's own catalog would. Where an +engine already folds its type into a spelling, `ParseTypeExpr` reads it; +where it does not, the converter has a small change to make. + +| Engine | Form | Expression | +|---|---|---| +| PostgreSQL | `numeric(10,2)`, `varchar(255)`, `timestamp(3) with time zone` | `numeric(10, 2)`, `character varying(255)`, `timestamp with time zone(3)`: typmods become integer arguments on the canonical family, named as `format_type` names it | +| PostgreSQL | `int[]`, `int[][]`, `int[3]` | `array(integer)`, `array(array(integer))`, `array(integer)`: one per array bound, the bound itself dropped as PostgreSQL drops it | +| PostgreSQL | `interval day to second` | `interval('day to second')`: the fields are one identifier argument, as `format_type` prints them | +| PostgreSQL | domain, composite, enum, range | declared rows, as above; `CreateDomainStmt`, `CompositeTypeStmt` and `CreateRangeStmt` gain `schema.Apply` cases | +| PostgreSQL | `myschema.mood` | a row in namespace `myschema`; `Names` resolves to a namespace rather than a dotted name | +| MySQL | `BIGINT UNSIGNED`, `DECIMAL(10,2) UNSIGNED` | `bigint unsigned`, `decimal unsigned(10, 2)`: unsigned is a family of its own, as `COLUMN_TYPE` and the wire flag report it, rather than the alias of the signed type `types.jsonl` lists today; the converter puts it in the name instead of on `ColumnDef.IsUnsigned`, which the core ignores | +| MySQL | `TINYINT(1)`, `DATETIME(6)`, `VARCHAR(255)`, `BOOLEAN` | `tinyint(1)`, `datetime(6)`, `varchar(255)`, `tinyint(1)`: the converter's `Typmods` are read, and `boolean` canonicalizes as MySQL does | +| MySQL | `ENUM('a','b')`, `SET('x','y')` | `enum('a', 'b')`, `set('x', 'y')`: the converter renders `Vals` into the spelling | +| MySQL | `CAST(x AS CHAR(10))` | `char(10)`: the cast converter names the SQL type, not the wire code `var_string` | +| MySQL | `VARCHAR(10) CHARACTER SET binary` | `varbinary(10)`, as the parser folds it; collation is not part of the type | +| SQLite | any spelling | the spelling as an instance, `varchar(255)`, `foo bar(3)`, verbatim as `pragma_table_xinfo` reports it, with `base_oid` set by the affinity rule applied when the dialect resolves an unknown name; `types.jsonl`'s alias lists become the rule | +| SQLite | `STRICT` tables, `ANY` | the family rows; a strict table's column names one of them or fails, as SQLite does | +| SQLite | an expression | its storage class, `integer`, `real`, `text` or `blob`, which is what `typeof()` and the check report | +| ClickHouse | every parametric type | the spelling, read as today, now also for casts, `{p:T}` placeholders and results | +| ClickHouse | `Nullable(T)`, `LowCardinality(T)` | `T` with `nullable`; `lowcardinality(T)` with `base_oid` at `T` | +| ClickHouse | `Decimal32(4)`, `Enum('a', 'b')`, `Variant(String, Int64)`, `INT` | `decimal(9, 4)` by a rewrite, `enum8(a: 1, b: 2)` and `variant(int64, string)` by the converter, `int32` by an alias | +| ClickHouse | `SimpleAggregateFunction(sum, UInt64)` | `simpleaggregatefunction(sum, uint64)` with `sum` an identifier argument | +| ClickHouse | `toDecimal64(x, s)` | `decimal(18, s)`, by the seed's return template | +| ClickHouse | `Nested(a UInt8, b String)` | a relation-shape rule, not a type: the column becomes `n.a array(uint8)` and `n.b array(string)` on load, as `system.columns` has them | +| DuckDB | `STRUCT(a INTEGER, b VARCHAR)`, `MAP(K, V)`, `UNION(...)` | `struct(a: integer, b: varchar)`, `map(varchar, integer)`, `union(num: integer, str: varchar)`: the converter renders the darkwing type expression it already has instead of keeping its name | +| DuckDB | `INTEGER[]`, `INTEGER[3]` | `array(integer)` and `array(integer, 3)`: a list is the cross-dialect array, a fixed size is its second argument | +| DuckDB | `TEXT`, `VARCHAR(10)`, `NUMERIC`, `mood` | `varchar`, `varchar`, `decimal(18, 3)`, `enum('sad', 'ok')`, by aliases, argument rules and `canonical_oid` on the declared enum | +| GoogleSQL | `ARRAY`, `STRUCT`, `RANGE` | `array(int64)`, `struct(a: int64, b: string)`, `range(date)`: the converter renders the zetajones type node in call form, or `ParseTypeExpr` accepts `<...>` | +| GoogleSQL | `STRING(10)`, `STRING(MAX)`, `NUMERIC(10,2)`, `[1, 2]`, `STRUCT(1 AS x)` | the typmods are read, with `max` an identifier argument; the array and struct constructors are typed from their elements | +| SQL Server | `NVARCHAR(MAX)`, `VARCHAR`, `DECIMAL` | `nvarchar(max)` with `max` an identifier argument; `varchar(1)` and `decimal(18, 0)` by the defaults `sys.types` applies | +| SQL Server | `FLOAT(24)` | `real`, by a rewrite | +| SQL Server | `dbo.PhoneNumber`, `sysname` | a row in namespace `dbo`, `typtype` `d`, `base_oid` at `varchar(20)`, `not_null` set; `sysname` seeded the same way over `nvarchar(128)` | + +The `ident` argument is the one addition to `TypeExpr` and to +`goldeneye/analysis.TypeExpr`, which mirrors it. Without it `max`, `sum` and +`day to second` read as types, and today they do: `SimpleAggregateFunction` +reports `sum` as a type. Both parsers that have `MAX` model it as a literal +node, and the converters hand it over as an identifier; `ParseTypeExpr` +writes a bare word that is not a known family as an identifier only when a +dialect says so, since a struct field's type is also a bare word. + +### What the analyzer reports + +`Column` and `Parameter` in `analysis.go` keep `Type` as the expression and +`TypeOID` as the row, instance or family. `DataType` and `IsArray` stay as +the flat view for the legacy compiler bridge, and that bridge derives what +codegen reads from the expression rather than dropping it: `ArrayDims` is +the depth of `array` nesting, `Length` is the first integer argument, +`Unsigned` is a family name ending in ` unsigned`. `sqlc analyze` prints the +expression as it does today, with `ident` as a fifth argument kind. + +`TypeNameString`, `ArraySuffix`, `CreateArrayType`, `TypeLength` and +`TypeScale` are the API that goes; `ResolveTypeExpr`, `LookupTypeExpr` and +`TypeExprOf(oid)` — the expression a row stands for, read back from +`sql_type_arg` — are the API that replaces it. + +### What the seed files gain + +`types.jsonl` is unchanged for a family beyond the optional argument +defaults; an alias becomes a row with `canonical_oid` instead of a mesh of +casts. A function's argument and return types may be expressions, and the +return type may reference an argument's value as well as its type. The +category rules in `dialect.json` apply to families; an instance inherits +its family's category, which is how `numeric(10, 2)` joins the numeric +casts without being seeded. `dialect.json` also carries the dialect's +rewrites, its identifier words and positions, and its affinity rule, so +that nothing about a dialect is code. + +`goldeneye` checks the analyze cases against what each database reports, and +its answer shape is the same `TypeExpr`. ClickHouse and DuckDB report whole +expressions already. MySQL's driver reports the family, unsigned and +nullability but not precision or length, and `ColumnType.DecimalSize` and +`ColumnType.Length` can add them, with the length divided by the charset's +bytes per character since the wire reports bytes. SQLite reports a declared +spelling for a table column and a storage class for an expression, which +are an instance row and a family row respectively. A PostgreSQL check reads +`format_type(atttypid, atttypmod)` and `attndims`. Every check keeps passing +on the way, since a family with no arguments prints as it does now. + +## A worked example: an array of arrays of integers + +```sql +CREATE TABLE grids ( + id bigint PRIMARY KEY, + cells int[][] NOT NULL +); + +-- name: GetGrid :one +SELECT id, cells, cells[1][2] AS cell FROM grids WHERE cells = $1; +``` + +The PostgreSQL parser hands over `pg_catalog.int4` with two array bounds, +which reads into `array(array(int4))`; canonicalization makes it +`array(array(integer))`. Interning walks it bottom-up, so the inner array +gets its row before the outer one. With illustrative OIDs, `sql_type` +holds the seeded families and the two rows the schema added: + +| oid | name | expr | typtype | category | family_oid | element_oid | canonical_oid | +|---|---|---|---|---|---|---|---| +| 23 | integer | integer | b | N | | | | +| 24 | int4 | int4 | b | N | | | 23 | +| 20 | bigint | bigint | b | N | | | | +| 100 | array | array | b | A | | | | +| 1001 | array | array(integer) | b | A | 100 | 23 | | +| 1002 | array | array(array(integer)) | b | A | 100 | 1001 | | + +Row 1001 is what PostgreSQL calls `_int4`; row 1002 is the one PostgreSQL +does not have, since its own type collapses the dimensions onto `attndims`. +An instance takes its family's namespace. `sql_type_arg` has one row per +argument position: + +| type_oid | ord | label | arg_type_oid | nullable | +|---|---|---|---|---| +| 1001 | 1 | | 23 | 0 | +| 1002 | 1 | | 1001 | 0 | + +and `sql_attribute` points `grids.cells` at row 1002, `not_null` set, with +`int[][]` in `decl_type`. + +Analysis resolves `cells` to that attribute, so its `exprType` is +`{typeOID: 1002, expr: array(array(integer)), nullable: false}`, and the +parameter compared with it takes the same type. `cells[1][2]` follows the +dialect's subscript rule — PostgreSQL yields the innermost element however +many subscripts are applied — which is a walk down `element_oid` from 1002 +to 1001 to 23, nullable because a subscript can miss. `sqlc analyze` prints: + +```json +[ + { + "name": "GetGrid", + "cmd": ":one", + "columns": [ + { "name": "id", "type": { "name": "bigint" }, "table": "grids" }, + { + "name": "cells", + "type": { + "name": "array", + "args": [ + { "type": { "name": "array", "args": [ { "type": { "name": "integer" } } ] } } + ] + }, + "table": "grids" + }, + { "name": "cell", "type": { "name": "integer", "nullable": true } } + ], + "params": [ + { + "number": 1, + "column": { + "name": "cells", + "type": { + "name": "array", + "args": [ + { "type": { "name": "array", "args": [ { "type": { "name": "integer" } } ] } } + ] + }, + "table": "grids" + } + } + ] + } +] +``` + +Its string form is `array(array(integer))`; today the same column prints +`array(int4)`, one level, with `type_oid` pointing at a row named `int4[]`. +The legacy bridge derives `DataType` `integer` and `ArrayDims` 2 from the +nesting, so Go codegen renders `[][]int32` as the legacy path does. +DuckDB's `INTEGER[][]` and ClickHouse's `Array(Array(Int32))` produce the +same rows and output, with `int32` in ClickHouse's case. + +## As implemented + +The design above is implemented, engine by engine, with these departures +and details settled on the way: + +- What the note called hooks is data, so that an engine adds a dialect by + writing files and never by registering Go code. `dialect.json` carries + `rewrites`, an ordered list of pattern, template and optional bound — + `float($1)` to `real` where `$1 <= 24`, `decimal` to `decimal(18, 0)`, + `Decimal32($1)` to `Decimal(9, $1)`, `sysname` to `nvarchar(128)` — which + the seed loads into `sql_type_rewrite` and the catalog applies before + interning, first match winning, tried once with the name as spelled and + once with its alias resolved so that `dec` meets a rule on `decimal`; + `idents` and `ident_args`, the words and + argument positions that are identifiers rather than types, kept as dialect + flags; and `affinity`, SQLite's ordered rule for a family the seed does + not list, loaded into `sql_type_affinity` and asked when a schema + declares one. A result that depends on an argument's value is a template + in `functions.jsonl` — `"returns": "Decimal(18, $2)"` — kept on + `sql_proc.return_template` and filled in from the call's literals. What + is genuinely about parsing stays in the engine's converter: ClickHouse + numbers an Enum's members and sorts a Variant's in the canonical + rendering it hands the core, while the spelling the formatter prints stays + the author's. +- A bare type name resolves in the default namespaces only — the catalog's + own, `pg_catalog` and the dialect's default schema — and `CREATE TYPE` + deduplicates within the namespace it names, so `foo.mood` and `mood` are + two types and a bare `mood` never binds to `foo.mood`. A bare `CREATE + TYPE` lands in the dialect's default schema when it has one, so SQL + Server's `PhoneNumber` and `dbo.PhoneNumber` are one row. A type outside + the default namespaces is spelled with its namespace wherever the catalog + spells it, including inside an instance's key, so `array(foo.mood)` and + `array(mood)` are two rows. +- A lookup that may not write — the analyzer's, against the cached catalog + — still canonicalizes an expression whose instance is not a row, however + deep the missing instance sits, so `$1::varchar(10)[]` reports + `array(character varying(10))` against the `array` family. The seed + gives every dialect the `array` family for that reason, whether or not + its `types.jsonl` lists it. +- A family in `types.jsonl` may name a `base` listed before it, which is + how MySQL's unsigned families stand on their signed ones: `bigint + unsigned` is a type of its own, and resolves as a `bigint` where nothing + takes it as itself. +- SQLite's `dialect.json` says `"alias": "base"`, which makes each alias in + its `types.jsonl` a type of its own standing on the type it aliases, + rather than another spelling of it. +- An engine hands the core one of three things: a canonical rendering + (`TypeName.Canonical`, a call expression with fields labelled `a: integer`, + which DuckDB, GoogleSQL and ClickHouse write and the formatter never + prints), the author's spelling (`TypeName.Spelling`, which the formatter + prints back and SQLite hands over as its type), or a name with `Typmods` + and `ArrayBounds`, where an integer constant is an integer argument, a + bare `ast.String` is an identifier and a quoted constant a string. + `ParseTypeExpr` reads a label before a colon, a label before a space only + when a single word follows, and words after a closing parenthesis as part + of the name, as in `decimal(10,2) unsigned`. `ColumnDef.IsUnsigned` and `ColumnDef.Vals` add MySQL's unsigned + and enum members. `ParamRef.Name` carries the name a `{name:Type}` + placeholder gives itself. +- A cast is NULL when its operand is, or when its type says so, as + `Nullable(String)` does; a cast of a placeholder types the placeholder + and takes its name and source from what it is compared with. A cast to + `interval day to second` decodes the field mask the parser reports the + way a column definition does. +- ClickHouse's `LowCardinality(Nullable(T))`, the only order it accepts, + is a nullable column, and the converter and `goldeneye` both read it as + `lowcardinality(T)` with the nullability on the outside, where the + column's nullability lives. +- MySQL types `CAST(x AS CHAR(10))` as `varchar(10)` and `CAST(x AS + BINARY(8))` as `varbinary(8)`, which is what its metadata and a view over + the cast both report, rather than the `char(10)` the table above + proposed. `goldeneye` reads a table column's type from `COLUMN_TYPE`, in + the relations seed and in the analyze check, and compares an expression + by family alone, since the wire carries no arguments. +- SQLite reports a cast to a spelling that is not a storage class, such as + `DECIMAL(5,2)`, as that spelling, while the value's storage class is what + a run would show; the check's cases keep to storage classes. +- DuckDB's `JSON` is grouped under `varchar` by `duckdb_types()`'s logical + type, so a JSON column reports `varchar`; a named enum reports its name, + not its labels, since the canonicalizer cannot see the catalog. A + GoogleSQL array or struct constructor in a select list is still untyped. +- PostgreSQL's `relations.jsonl` spells an array column as its element with + the array flag, which `goldeneye` now writes from `typelem` for the + `_`-prefixed array types alone; `int2vector` and `oidvector` share the + array category but stay types of their own. MySQL's keeps the case of an + enum's members, which are values. + +## Order of work + +1. The tables and the interning entry point: `sql_type.expr`, `family_oid`, + `element_oid`, `base_oid`, `canonical_oid`, `not_null`, `sql_type_arg`, + `ResolveTypeExpr`, `LookupTypeExpr`, `TypeExprOf`, with the alias step + of canonicalization. Arrays become instances of `array`; the `[]` + convention goes. Every existing golden holds, since a bare name prints + the same. +2. The analyzer: `exprType` carries the expression; casts, constructors, + placeholders and function results report it; resolution falls back + through the pointer chain. This is where ClickHouse's casts and + parameters come right. +3. The engines, one at a time, each with an `analyze_types/` case + alongside ClickHouse's and each with its rewrites: PostgreSQL + typmods, dimensions, declared types and `format_type` names; MySQL + unsigned, typmods, members and `boolean`, plus the `var_string` leak; + DuckDB's nested types and dropped arguments; GoogleSQL's angle brackets; + SQL Server's `max`, defaults and alias types; SQLite's affinity rule. +4. The legacy bridge: `parse_core.go` derives `Unsigned`, `Length` and + `ArrayDims` from the expression, and the `experiment_coreanalyzer` cases + grow MySQL unsigned and boolean columns and a PostgreSQL two-dimensional + array, so the core path generates what the legacy path does. +5. Return templates for value-dependent results, ClickHouse first; then + MySQL's precision arithmetic once its check reads precision from the + wire. + +## Open questions + +- How far a return template goes. ClickHouse's arithmetic promotion and + `toDecimal64(x, 4)` are finite rules; `arrayMap(f, arr)` returns an array + of the lambda's result, which needs the lambda typed first. +- Whether DuckDB's dropped `VARCHAR(10)` length and reported anonymous enum + should be canonicalized away as DuckDB does, or kept because a user + declared them. The check decides for the former. diff --git a/internal/endtoend/testdata/analyze_ast/postgresql/stdout.json b/internal/endtoend/testdata/analyze_ast/postgresql/stdout.json index 427fe5af92..0ab1d7e128 100644 --- a/internal/endtoend/testdata/analyze_ast/postgresql/stdout.json +++ b/internal/endtoend/testdata/analyze_ast/postgresql/stdout.json @@ -17,7 +17,7 @@ "column": { "name": "id", "type": { - "name": "bigserial" + "name": "bigint" }, "table": "authors" } diff --git a/internal/endtoend/testdata/analyze_basic/duckdb/stdout.json b/internal/endtoend/testdata/analyze_basic/duckdb/stdout.json index 6b7631c5de..6459e87325 100644 --- a/internal/endtoend/testdata/analyze_basic/duckdb/stdout.json +++ b/internal/endtoend/testdata/analyze_basic/duckdb/stdout.json @@ -13,14 +13,14 @@ { "name": "name", "type": { - "name": "text" + "name": "varchar" }, "table": "authors" }, { "name": "bio", "type": { - "name": "text", + "name": "varchar", "nullable": true }, "table": "authors" @@ -28,7 +28,15 @@ { "name": "royalties", "type": { - "name": "decimal" + "name": "decimal", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] }, "table": "authors" }, diff --git a/internal/endtoend/testdata/analyze_basic/mssql/stdout.json b/internal/endtoend/testdata/analyze_basic/mssql/stdout.json index 181660561a..818c4c26d7 100644 --- a/internal/endtoend/testdata/analyze_basic/mssql/stdout.json +++ b/internal/endtoend/testdata/analyze_basic/mssql/stdout.json @@ -13,7 +13,12 @@ { "name": "name", "type": { - "name": "nvarchar" + "name": "nvarchar", + "args": [ + { + "int": 100 + } + ] }, "table": "authors" }, @@ -21,21 +26,39 @@ "name": "bio", "type": { "name": "nvarchar", - "nullable": true + "nullable": true, + "args": [ + { + "ident": "max" + } + ] }, "table": "authors" }, { "name": "royalties", "type": { - "name": "decimal" + "name": "decimal", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] }, "table": "authors" }, { "name": "created", "type": { - "name": "datetime2" + "name": "datetime2", + "args": [ + { + "int": 7 + } + ] }, "table": "authors" } diff --git a/internal/endtoend/testdata/analyze_basic/mysql/stdout.json b/internal/endtoend/testdata/analyze_basic/mysql/stdout.json index 83dde3e339..56ae2723c3 100644 --- a/internal/endtoend/testdata/analyze_basic/mysql/stdout.json +++ b/internal/endtoend/testdata/analyze_basic/mysql/stdout.json @@ -13,7 +13,12 @@ { "name": "name", "type": { - "name": "varchar" + "name": "varchar", + "args": [ + { + "int": 255 + } + ] }, "table": "users" } diff --git a/internal/endtoend/testdata/analyze_basic/postgresql/stdout.json b/internal/endtoend/testdata/analyze_basic/postgresql/stdout.json index 36356b73c3..faa4c1acd1 100644 --- a/internal/endtoend/testdata/analyze_basic/postgresql/stdout.json +++ b/internal/endtoend/testdata/analyze_basic/postgresql/stdout.json @@ -6,7 +6,7 @@ { "name": "id", "type": { - "name": "bigserial" + "name": "bigint" }, "table": "authors" }, @@ -32,7 +32,7 @@ "column": { "name": "id", "type": { - "name": "bigserial" + "name": "bigint" }, "table": "authors" } diff --git a/internal/endtoend/testdata/analyze_dml/duckdb/stdout.json b/internal/endtoend/testdata/analyze_dml/duckdb/stdout.json index afdd96cfd7..621fdfd260 100644 --- a/internal/endtoend/testdata/analyze_dml/duckdb/stdout.json +++ b/internal/endtoend/testdata/analyze_dml/duckdb/stdout.json @@ -27,7 +27,7 @@ "column": { "name": "name", "type": { - "name": "text" + "name": "varchar" }, "table": "authors" } @@ -37,7 +37,7 @@ "column": { "name": "bio", "type": { - "name": "text", + "name": "varchar", "nullable": true }, "table": "authors" @@ -55,7 +55,7 @@ "column": { "name": "name", "type": { - "name": "text" + "name": "varchar" }, "table": "authors" } @@ -65,7 +65,7 @@ "column": { "name": "bio", "type": { - "name": "text", + "name": "varchar", "nullable": true }, "table": "authors" @@ -93,7 +93,7 @@ "column": { "name": "name", "type": { - "name": "text" + "name": "varchar" }, "table": "authors" } @@ -114,7 +114,7 @@ { "name": "title", "type": { - "name": "text" + "name": "varchar" }, "table": "books" } @@ -126,7 +126,15 @@ "name": "price", "type": { "name": "decimal", - "nullable": true + "nullable": true, + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] }, "table": "books" } diff --git a/internal/endtoend/testdata/analyze_dml/mssql/stdout.json b/internal/endtoend/testdata/analyze_dml/mssql/stdout.json index 24e2efb3e4..74f68505dd 100644 --- a/internal/endtoend/testdata/analyze_dml/mssql/stdout.json +++ b/internal/endtoend/testdata/analyze_dml/mssql/stdout.json @@ -17,7 +17,12 @@ "column": { "name": "name", "type": { - "name": "nvarchar" + "name": "nvarchar", + "args": [ + { + "int": 100 + } + ] }, "table": "authors" } @@ -28,7 +33,12 @@ "name": "bio", "type": { "name": "nvarchar", - "nullable": true + "nullable": true, + "args": [ + { + "ident": "max" + } + ] }, "table": "authors" } @@ -45,7 +55,12 @@ "column": { "name": "name", "type": { - "name": "nvarchar" + "name": "nvarchar", + "args": [ + { + "int": 100 + } + ] }, "table": "authors" } @@ -73,7 +88,15 @@ "name": "price", "type": { "name": "decimal", - "nullable": true + "nullable": true, + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] }, "table": "books" } @@ -83,7 +106,12 @@ "column": { "name": "name", "type": { - "name": "nvarchar" + "name": "nvarchar", + "args": [ + { + "int": 100 + } + ] }, "table": "authors" } @@ -100,7 +128,12 @@ "column": { "name": "name", "type": { - "name": "nvarchar" + "name": "nvarchar", + "args": [ + { + "int": 100 + } + ] }, "table": "authors" } diff --git a/internal/endtoend/testdata/analyze_dml/mysql/stdout.json b/internal/endtoend/testdata/analyze_dml/mysql/stdout.json index e474c04a04..1d5d37e41d 100644 --- a/internal/endtoend/testdata/analyze_dml/mysql/stdout.json +++ b/internal/endtoend/testdata/analyze_dml/mysql/stdout.json @@ -19,7 +19,12 @@ "column": { "name": "name", "type": { - "name": "varchar" + "name": "varchar", + "args": [ + { + "int": 255 + } + ] }, "table": "users" } @@ -92,7 +97,12 @@ "column": { "name": "name", "type": { - "name": "varchar" + "name": "varchar", + "args": [ + { + "int": 255 + } + ] }, "table": "users" } diff --git a/internal/endtoend/testdata/analyze_dml/postgresql/stdout.json b/internal/endtoend/testdata/analyze_dml/postgresql/stdout.json index 876a1ed726..e9f777ced3 100644 --- a/internal/endtoend/testdata/analyze_dml/postgresql/stdout.json +++ b/internal/endtoend/testdata/analyze_dml/postgresql/stdout.json @@ -6,7 +6,7 @@ { "name": "id", "type": { - "name": "bigserial" + "name": "bigint" }, "table": "users" }, @@ -71,7 +71,7 @@ "column": { "name": "id", "type": { - "name": "bigserial" + "name": "bigint" }, "table": "users" } @@ -85,7 +85,7 @@ { "name": "id", "type": { - "name": "bigserial" + "name": "bigint" }, "table": "users" }, @@ -113,7 +113,7 @@ "column": { "name": "id", "type": { - "name": "bigserial" + "name": "bigint" }, "table": "users" } @@ -130,7 +130,7 @@ "column": { "name": "id", "type": { - "name": "bigserial" + "name": "bigint" }, "table": "users" } @@ -144,7 +144,7 @@ { "name": "id", "type": { - "name": "bigserial" + "name": "bigint" }, "table": "users" } @@ -155,7 +155,7 @@ "column": { "name": "id", "type": { - "name": "bigserial" + "name": "bigint" }, "table": "users" } diff --git a/internal/endtoend/testdata/analyze_extension/postgresql/stdout.json b/internal/endtoend/testdata/analyze_extension/postgresql/stdout.json index af10afec06..dd4477e89a 100644 --- a/internal/endtoend/testdata/analyze_extension/postgresql/stdout.json +++ b/internal/endtoend/testdata/analyze_extension/postgresql/stdout.json @@ -6,7 +6,7 @@ { "name": "id", "type": { - "name": "bigserial" + "name": "bigint" }, "table": "users" }, @@ -38,7 +38,7 @@ { "name": "id", "type": { - "name": "bigserial" + "name": "bigint" }, "table": "users" } @@ -52,7 +52,7 @@ { "name": "id", "type": { - "name": "bigserial" + "name": "bigint" }, "table": "users" }, diff --git a/internal/endtoend/testdata/analyze_params/duckdb/stdout.json b/internal/endtoend/testdata/analyze_params/duckdb/stdout.json index 0a85a39358..40037c23d5 100644 --- a/internal/endtoend/testdata/analyze_params/duckdb/stdout.json +++ b/internal/endtoend/testdata/analyze_params/duckdb/stdout.json @@ -13,14 +13,14 @@ { "name": "name", "type": { - "name": "text" + "name": "varchar" }, "table": "authors" }, { "name": "bio", "type": { - "name": "text", + "name": "varchar", "nullable": true }, "table": "authors" @@ -53,7 +53,7 @@ { "name": "name", "type": { - "name": "text" + "name": "varchar" }, "table": "authors" } @@ -64,7 +64,7 @@ "column": { "name": "name", "type": { - "name": "text" + "name": "varchar" }, "table": "authors" } @@ -74,7 +74,15 @@ "column": { "name": "royalties", "type": { - "name": "decimal" + "name": "decimal", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] }, "table": "authors" } @@ -99,7 +107,7 @@ "column": { "name": "name", "type": { - "name": "text" + "name": "varchar" }, "table": "authors" } diff --git a/internal/endtoend/testdata/analyze_params/mssql/stdout.json b/internal/endtoend/testdata/analyze_params/mssql/stdout.json index 1483213369..ab55aa9823 100644 --- a/internal/endtoend/testdata/analyze_params/mssql/stdout.json +++ b/internal/endtoend/testdata/analyze_params/mssql/stdout.json @@ -13,7 +13,12 @@ { "name": "name", "type": { - "name": "nvarchar" + "name": "nvarchar", + "args": [ + { + "int": 100 + } + ] }, "table": "authors" }, @@ -21,7 +26,12 @@ "name": "bio", "type": { "name": "nvarchar", - "nullable": true + "nullable": true, + "args": [ + { + "ident": "max" + } + ] }, "table": "authors" } @@ -53,7 +63,12 @@ { "name": "name", "type": { - "name": "nvarchar" + "name": "nvarchar", + "args": [ + { + "int": 100 + } + ] }, "table": "authors" } @@ -64,7 +79,12 @@ "column": { "name": "name", "type": { - "name": "nvarchar" + "name": "nvarchar", + "args": [ + { + "int": 100 + } + ] }, "table": "authors" } @@ -74,7 +94,15 @@ "column": { "name": "royalties", "type": { - "name": "decimal" + "name": "decimal", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] }, "table": "authors" } diff --git a/internal/endtoend/testdata/analyze_params/mysql/stdout.json b/internal/endtoend/testdata/analyze_params/mysql/stdout.json index 7ff80429a7..6232a4d26e 100644 --- a/internal/endtoend/testdata/analyze_params/mysql/stdout.json +++ b/internal/endtoend/testdata/analyze_params/mysql/stdout.json @@ -13,7 +13,12 @@ { "name": "name", "type": { - "name": "varchar" + "name": "varchar", + "args": [ + { + "int": 255 + } + ] }, "table": "users" } @@ -45,7 +50,12 @@ { "name": "name", "type": { - "name": "varchar" + "name": "varchar", + "args": [ + { + "int": 255 + } + ] }, "table": "users" } @@ -56,7 +66,12 @@ "column": { "name": "name", "type": { - "name": "varchar" + "name": "varchar", + "args": [ + { + "int": 255 + } + ] }, "table": "users" } @@ -88,7 +103,12 @@ { "name": "name", "type": { - "name": "varchar" + "name": "varchar", + "args": [ + { + "int": 255 + } + ] }, "table": "users" } diff --git a/internal/endtoend/testdata/analyze_params/postgresql/stdout.json b/internal/endtoend/testdata/analyze_params/postgresql/stdout.json index 3d98c7ff65..fd46e40a84 100644 --- a/internal/endtoend/testdata/analyze_params/postgresql/stdout.json +++ b/internal/endtoend/testdata/analyze_params/postgresql/stdout.json @@ -6,7 +6,7 @@ { "name": "id", "type": { - "name": "bigserial" + "name": "bigint" }, "table": "users" }, @@ -24,7 +24,7 @@ "column": { "name": "id", "type": { - "name": "bigserial" + "name": "bigint" }, "table": "users" } @@ -38,7 +38,7 @@ { "name": "id", "type": { - "name": "bigserial" + "name": "bigint" }, "table": "users" }, @@ -81,7 +81,7 @@ { "name": "id", "type": { - "name": "bigserial" + "name": "bigint" }, "table": "users" }, @@ -99,7 +99,7 @@ "column": { "name": "ids", "type": { - "name": "bigserial" + "name": "bigint" }, "table": "users" } @@ -113,15 +113,20 @@ { "name": "id", "type": { - "name": "bigserial" + "name": "bigint" }, "table": "posts" }, { "name": "title", "type": { - "name": "varchar", - "nullable": true + "name": "character varying", + "nullable": true, + "args": [ + { + "int": 255 + } + ] }, "table": "posts" } @@ -132,7 +137,7 @@ "column": { "name": "created", "type": { - "name": "timestamptz" + "name": "timestamp with time zone" }, "table": "posts" } @@ -142,7 +147,7 @@ "column": { "name": "created", "type": { - "name": "timestamptz" + "name": "timestamp with time zone" }, "table": "posts" } diff --git a/internal/endtoend/testdata/analyze_select/duckdb/stdout.json b/internal/endtoend/testdata/analyze_select/duckdb/stdout.json index 2b0e161be2..e0744b9ecd 100644 --- a/internal/endtoend/testdata/analyze_select/duckdb/stdout.json +++ b/internal/endtoend/testdata/analyze_select/duckdb/stdout.json @@ -13,7 +13,7 @@ { "name": "name", "type": { - "name": "text" + "name": "varchar" }, "table": "users" }, @@ -48,7 +48,7 @@ { "name": "name", "type": { - "name": "text" + "name": "varchar" }, "table": "users" }, @@ -69,14 +69,14 @@ { "name": "title", "type": { - "name": "text" + "name": "varchar" }, "table": "posts" }, { "name": "body", "type": { - "name": "text", + "name": "varchar", "nullable": true }, "table": "posts" @@ -88,7 +88,7 @@ "column": { "name": "name", "type": { - "name": "text" + "name": "varchar" }, "table": "users" } @@ -102,7 +102,7 @@ { "name": "name", "type": { - "name": "text" + "name": "varchar" }, "table": "users" }, diff --git a/internal/endtoend/testdata/analyze_select/googlesql/stdout.json b/internal/endtoend/testdata/analyze_select/googlesql/stdout.json index 0bd71ba16a..7f112f964b 100644 --- a/internal/endtoend/testdata/analyze_select/googlesql/stdout.json +++ b/internal/endtoend/testdata/analyze_select/googlesql/stdout.json @@ -70,7 +70,12 @@ "name": "title", "type": { "name": "string", - "nullable": true + "nullable": true, + "args": [ + { + "int": 255 + } + ] }, "table": "posts" }, diff --git a/internal/endtoend/testdata/analyze_select/mysql/stdout.json b/internal/endtoend/testdata/analyze_select/mysql/stdout.json index f50d00465d..3e679fd261 100644 --- a/internal/endtoend/testdata/analyze_select/mysql/stdout.json +++ b/internal/endtoend/testdata/analyze_select/mysql/stdout.json @@ -13,7 +13,12 @@ { "name": "name", "type": { - "name": "varchar" + "name": "varchar", + "args": [ + { + "int": 255 + } + ] }, "table": "users" }, @@ -48,7 +53,12 @@ { "name": "name", "type": { - "name": "varchar" + "name": "varchar", + "args": [ + { + "int": 255 + } + ] }, "table": "users" }, @@ -70,7 +80,12 @@ "name": "title", "type": { "name": "varchar", - "nullable": true + "nullable": true, + "args": [ + { + "int": 255 + } + ] }, "table": "posts" }, @@ -88,7 +103,12 @@ "column": { "name": "name", "type": { - "name": "varchar" + "name": "varchar", + "args": [ + { + "int": 255 + } + ] }, "table": "users" } @@ -110,7 +130,12 @@ "name": "title", "type": { "name": "varchar", - "nullable": true + "nullable": true, + "args": [ + { + "int": 255 + } + ] }, "table": "posts" } @@ -122,7 +147,12 @@ "name": "title", "type": { "name": "varchar", - "nullable": true + "nullable": true, + "args": [ + { + "int": 255 + } + ] }, "table": "posts" } @@ -146,7 +176,12 @@ { "name": "name", "type": { - "name": "varchar" + "name": "varchar", + "args": [ + { + "int": 255 + } + ] }, "table": "users" }, diff --git a/internal/endtoend/testdata/analyze_select/postgresql/stdout.json b/internal/endtoend/testdata/analyze_select/postgresql/stdout.json index 75ae4486c3..95f2d691a6 100644 --- a/internal/endtoend/testdata/analyze_select/postgresql/stdout.json +++ b/internal/endtoend/testdata/analyze_select/postgresql/stdout.json @@ -6,7 +6,7 @@ { "name": "id", "type": { - "name": "bigserial" + "name": "bigint" }, "table": "users" }, @@ -55,29 +55,34 @@ { "name": "id", "type": { - "name": "bigserial" + "name": "bigint" }, "table": "posts" }, { "name": "user_id", "type": { - "name": "int8" + "name": "bigint" }, "table": "posts" }, { "name": "title", "type": { - "name": "varchar", - "nullable": true + "name": "character varying", + "nullable": true, + "args": [ + { + "int": 255 + } + ] }, "table": "posts" }, { "name": "created", "type": { - "name": "timestamptz" + "name": "timestamp with time zone" }, "table": "posts" } @@ -102,15 +107,20 @@ { "name": "id", "type": { - "name": "bigserial" + "name": "bigint" }, "table": "posts" }, { "name": "title", "type": { - "name": "varchar", - "nullable": true + "name": "character varying", + "nullable": true, + "args": [ + { + "int": 255 + } + ] }, "table": "posts" } @@ -121,8 +131,13 @@ "column": { "name": "title", "type": { - "name": "varchar", - "nullable": true + "name": "character varying", + "nullable": true, + "args": [ + { + "int": 255 + } + ] }, "table": "posts" } @@ -132,7 +147,7 @@ "column": { "name": "created", "type": { - "name": "timestamptz" + "name": "timestamp with time zone" }, "table": "posts" } @@ -153,7 +168,7 @@ { "name": "created", "type": { - "name": "timestamptz" + "name": "timestamp with time zone" } } ], diff --git a/internal/endtoend/testdata/analyze_system_catalog/mysql/stdout.json b/internal/endtoend/testdata/analyze_system_catalog/mysql/stdout.json index cd3116fa44..134b5b11f8 100644 --- a/internal/endtoend/testdata/analyze_system_catalog/mysql/stdout.json +++ b/internal/endtoend/testdata/analyze_system_catalog/mysql/stdout.json @@ -6,7 +6,12 @@ { "name": "table_name", "type": { - "name": "varchar" + "name": "varchar", + "args": [ + { + "int": 64 + } + ] }, "table": "columns" }, @@ -14,7 +19,12 @@ "name": "column_name", "type": { "name": "varchar", - "nullable": true + "nullable": true, + "args": [ + { + "int": 64 + } + ] }, "table": "columns" }, @@ -33,7 +43,12 @@ "column": { "name": "table_schema", "type": { - "name": "varchar" + "name": "varchar", + "args": [ + { + "int": 64 + } + ] }, "table": "columns" } @@ -57,7 +72,18 @@ "column": { "name": "table_type", "type": { - "name": "enum" + "name": "enum", + "args": [ + { + "string": "BASE TABLE" + }, + { + "string": "VIEW" + }, + { + "string": "SYSTEM VIEW" + } + ] }, "table": "tables" } diff --git a/internal/endtoend/testdata/analyze_system_catalog/postgresql/stdout.json b/internal/endtoend/testdata/analyze_system_catalog/postgresql/stdout.json index 0432abd33e..dc48b00653 100644 --- a/internal/endtoend/testdata/analyze_system_catalog/postgresql/stdout.json +++ b/internal/endtoend/testdata/analyze_system_catalog/postgresql/stdout.json @@ -59,7 +59,7 @@ "column": { "name": "relkind", "type": { - "name": "char" + "name": "character" }, "table": "pg_class" } diff --git a/internal/endtoend/testdata/analyze_types/clickhouse/fixture.sql b/internal/endtoend/testdata/analyze_types/clickhouse/fixture.sql index bb958af8a2..d4353b2dc8 100644 --- a/internal/endtoend/testdata/analyze_types/clickhouse/fixture.sql +++ b/internal/endtoend/testdata/analyze_types/clickhouse/fixture.sql @@ -1 +1 @@ -INSERT INTO things VALUES (1, 'a', NULL, 1.5, ['x'], [NULL, 'y'], [[1, 2]], 'k', '2024-01-01 00:00:00', '2024-01-01 00:00:00.123', 1.25, 'active', {'k': 1}, (1.0, 2.0), (51.5, -0.1), {'a': NULL}, '127.0.0.1', '00000000-0000-0000-0000-000000000000', 'abcd', true); +INSERT INTO things VALUES (1, 'a', NULL, 1.5, ['x'], [NULL, 'y'], [[1, 2]], 'k', '2024-01-01 00:00:00', '2024-01-01 00:00:00.123', 1.25, 'active', {'k': 1}, (1.0, 2.0), (51.5, -0.1), {'a': NULL}, '127.0.0.1', '00000000-0000-0000-0000-000000000000', 'abcd', true, 1.5, 'x', 'v', [1], ['s'], 3, 7); diff --git a/internal/endtoend/testdata/analyze_types/clickhouse/query.sql b/internal/endtoend/testdata/analyze_types/clickhouse/query.sql index c55355e50d..8a4ff3e8be 100644 --- a/internal/endtoend/testdata/analyze_types/clickhouse/query.sql +++ b/internal/endtoend/testdata/analyze_types/clickhouse/query.sql @@ -2,4 +2,18 @@ SELECT * FROM things; -- name: StarColumns :many -SELECT id, name, tag, amount, tags, labels, matrix, kind, created, updated, price, status, attrs, pos, geo, scores, ip, uid, fixed, flag FROM things; +SELECT id, name, tag, amount, tags, labels, matrix, kind, created, updated, price, status, attrs, pos, geo, scores, ip, uid, fixed, flag, small, plain, either, n.a, n.b, total, whole FROM things; + +-- name: Casts :one +SELECT + CAST(id AS String) AS a, + toDecimal64(id, 4) AS b, + CAST(name AS Nullable(String)) AS c, + toDateTime64(created, 3) AS d, + CAST(tags AS Array(String)) AS e, + CAST(tag AS Nullable(String)) AS f +FROM things; + +-- name: Placeholders :many +SELECT id FROM things +WHERE id = {p1:UInt64} AND name = {p2:String} AND amount > {p3:Float64} AND tag = {p4:Nullable(String)} AND price = {p5:Decimal(10, 2)}; diff --git a/internal/endtoend/testdata/analyze_types/clickhouse/schema.sql b/internal/endtoend/testdata/analyze_types/clickhouse/schema.sql index 5f78064628..1dddddd5c9 100644 --- a/internal/endtoend/testdata/analyze_types/clickhouse/schema.sql +++ b/internal/endtoend/testdata/analyze_types/clickhouse/schema.sql @@ -18,5 +18,11 @@ CREATE TABLE things ( ip IPv4, uid UUID, fixed FixedString(4), - flag Bool + flag Bool, + small Decimal32(4), + plain Enum('x', 'y'), + either Variant(String, Int64), + n Nested(a UInt8, b String), + total SimpleAggregateFunction(sum, UInt64), + whole INT ) ENGINE = MergeTree ORDER BY id; diff --git a/internal/endtoend/testdata/analyze_types/clickhouse/stdout.json b/internal/endtoend/testdata/analyze_types/clickhouse/stdout.json index 5ef32d6b93..9c597de0c0 100644 --- a/internal/endtoend/testdata/analyze_types/clickhouse/stdout.json +++ b/internal/endtoend/testdata/analyze_types/clickhouse/stdout.json @@ -86,11 +86,11 @@ "name": "kind", "type": { "name": "lowcardinality", + "nullable": true, "args": [ { "type": { - "name": "string", - "nullable": true + "name": "string" } } ] @@ -262,6 +262,109 @@ "name": "bool" }, "table": "things" + }, + { + "name": "small", + "type": { + "name": "decimal", + "args": [ + { + "int": 9 + }, + { + "int": 4 + } + ] + }, + "table": "things" + }, + { + "name": "plain", + "type": { + "name": "enum8", + "args": [ + { + "label": "x", + "int": 1 + }, + { + "label": "y", + "int": 2 + } + ] + }, + "table": "things" + }, + { + "name": "either", + "type": { + "name": "variant", + "args": [ + { + "type": { + "name": "int64" + } + }, + { + "type": { + "name": "string" + } + } + ] + }, + "table": "things" + }, + { + "name": "n.a", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "uint8" + } + } + ] + }, + "table": "things" + }, + { + "name": "n.b", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "string" + } + } + ] + }, + "table": "things" + }, + { + "name": "total", + "type": { + "name": "simpleaggregatefunction", + "args": [ + { + "ident": "sum" + }, + { + "type": { + "name": "uint64" + } + } + ] + }, + "table": "things" + }, + { + "name": "whole", + "type": { + "name": "int32" + }, + "table": "things" } ], "params": [] @@ -353,11 +456,11 @@ "name": "kind", "type": { "name": "lowcardinality", + "nullable": true, "args": [ { "type": { - "name": "string", - "nullable": true + "name": "string" } } ] @@ -529,8 +632,250 @@ "name": "bool" }, "table": "things" + }, + { + "name": "small", + "type": { + "name": "decimal", + "args": [ + { + "int": 9 + }, + { + "int": 4 + } + ] + }, + "table": "things" + }, + { + "name": "plain", + "type": { + "name": "enum8", + "args": [ + { + "label": "x", + "int": 1 + }, + { + "label": "y", + "int": 2 + } + ] + }, + "table": "things" + }, + { + "name": "either", + "type": { + "name": "variant", + "args": [ + { + "type": { + "name": "int64" + } + }, + { + "type": { + "name": "string" + } + } + ] + }, + "table": "things" + }, + { + "name": "n.a", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "uint8" + } + } + ] + }, + "table": "things" + }, + { + "name": "n.b", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "string" + } + } + ] + }, + "table": "things" + }, + { + "name": "total", + "type": { + "name": "simpleaggregatefunction", + "args": [ + { + "ident": "sum" + }, + { + "type": { + "name": "uint64" + } + } + ] + }, + "table": "things" + }, + { + "name": "whole", + "type": { + "name": "int32" + }, + "table": "things" } ], "params": [] + }, + { + "name": "Casts", + "cmd": ":one", + "columns": [ + { + "name": "a", + "type": { + "name": "string" + } + }, + { + "name": "b", + "type": { + "name": "decimal", + "args": [ + { + "int": 18 + }, + { + "int": 4 + } + ] + } + }, + { + "name": "c", + "type": { + "name": "string", + "nullable": true + } + }, + { + "name": "d", + "type": { + "name": "datetime64", + "args": [ + { + "int": 3 + } + ] + } + }, + { + "name": "e", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "string" + } + } + ] + } + }, + { + "name": "f", + "type": { + "name": "string", + "nullable": true + } + } + ], + "params": [] + }, + { + "name": "Placeholders", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "uint64" + }, + "table": "things" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "p1", + "type": { + "name": "uint64" + }, + "table": "things" + } + }, + { + "number": 2, + "column": { + "name": "p2", + "type": { + "name": "string" + }, + "table": "things" + } + }, + { + "number": 3, + "column": { + "name": "p3", + "type": { + "name": "float64" + }, + "table": "things" + } + }, + { + "number": 4, + "column": { + "name": "p4", + "type": { + "name": "string", + "nullable": true + }, + "table": "things" + } + }, + { + "number": 5, + "column": { + "name": "p5", + "type": { + "name": "decimal", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "things" + } + } + ] } ] diff --git a/internal/endtoend/testdata/analyze_types/duckdb/exec.json b/internal/endtoend/testdata/analyze_types/duckdb/exec.json new file mode 100644 index 0000000000..56cb4b3fff --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/duckdb/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "duckdb", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_types/duckdb/query.sql b/internal/endtoend/testdata/analyze_types/duckdb/query.sql new file mode 100644 index 0000000000..3e232d263f --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/duckdb/query.sql @@ -0,0 +1,18 @@ +-- name: AllTypes :many +SELECT * FROM things; + +-- name: Casts :one +SELECT + $1::DECIMAL(5,2) AS a, + $2::INTEGER[] AS b, + $3::STRUCT(a INTEGER) AS c, + $4::mood AS d, + CAST($5 AS VARCHAR(5)) AS e, + $6::MAP(VARCHAR, INTEGER) AS f, + $7::INTEGER[3] AS g, + $8::main.mood AS h +FROM things; + +-- name: Params :one +SELECT id FROM things +WHERE ints = $1 AND point = $2 AND price = $3 AND m = $4 AND either = $5 AND grid = $6; diff --git a/internal/endtoend/testdata/analyze_types/duckdb/schema.sql b/internal/endtoend/testdata/analyze_types/duckdb/schema.sql new file mode 100644 index 0000000000..0a8a1b4147 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/duckdb/schema.sql @@ -0,0 +1,31 @@ +CREATE TYPE mood AS ENUM ('sad', 'ok'); + +CREATE TABLE things ( + id INTEGER PRIMARY KEY, + ints INTEGER[], + fixed INTEGER[3], + point STRUCT(a INTEGER, b VARCHAR), + attrs MAP(VARCHAR, INTEGER), + either UNION(num INTEGER, str VARCHAR), + price DECIMAL(18,3), + title VARCHAR(10), + kind ENUM('a','b'), + m mood, + mm main.mood, + big HUGEINT, + ubig UHUGEINT, + data BLOB, + bits BIT, + uid UUID, + tstz TIMESTAMP WITH TIME ZONE, + tsns TIMESTAMP_NS, + iv INTERVAL, + doc JSON, + grid INTEGER[][], + vi VARINT, + f4 FLOAT4, + points STRUCT(a INTEGER)[], + lists MAP(VARCHAR, INTEGER[]), + body TEXT, + n NUMERIC +); diff --git a/internal/endtoend/testdata/analyze_types/duckdb/stdout.json b/internal/endtoend/testdata/analyze_types/duckdb/stdout.json new file mode 100644 index 0000000000..fff8ac0228 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/duckdb/stdout.json @@ -0,0 +1,709 @@ +[ + { + "name": "AllTypes", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "integer" + }, + "table": "things" + }, + { + "name": "ints", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "integer" + } + } + ] + }, + "table": "things" + }, + { + "name": "fixed", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "integer" + } + }, + { + "int": 3 + } + ] + }, + "table": "things" + }, + { + "name": "point", + "type": { + "name": "struct", + "nullable": true, + "args": [ + { + "label": "a", + "type": { + "name": "integer" + } + }, + { + "label": "b", + "type": { + "name": "varchar" + } + } + ] + }, + "table": "things" + }, + { + "name": "attrs", + "type": { + "name": "map", + "nullable": true, + "args": [ + { + "type": { + "name": "varchar" + } + }, + { + "type": { + "name": "integer" + } + } + ] + }, + "table": "things" + }, + { + "name": "either", + "type": { + "name": "union", + "nullable": true, + "args": [ + { + "label": "num", + "type": { + "name": "integer" + } + }, + { + "label": "str", + "type": { + "name": "varchar" + } + } + ] + }, + "table": "things" + }, + { + "name": "price", + "type": { + "name": "decimal", + "nullable": true, + "args": [ + { + "int": 18 + }, + { + "int": 3 + } + ] + }, + "table": "things" + }, + { + "name": "title", + "type": { + "name": "varchar", + "nullable": true + }, + "table": "things" + }, + { + "name": "kind", + "type": { + "name": "enum", + "nullable": true, + "args": [ + { + "string": "a" + }, + { + "string": "b" + } + ] + }, + "table": "things" + }, + { + "name": "m", + "type": { + "name": "mood", + "nullable": true + }, + "table": "things" + }, + { + "name": "mm", + "type": { + "name": "mood", + "nullable": true + }, + "table": "things" + }, + { + "name": "big", + "type": { + "name": "hugeint", + "nullable": true + }, + "table": "things" + }, + { + "name": "ubig", + "type": { + "name": "uhugeint", + "nullable": true + }, + "table": "things" + }, + { + "name": "data", + "type": { + "name": "blob", + "nullable": true + }, + "table": "things" + }, + { + "name": "bits", + "type": { + "name": "bit", + "nullable": true + }, + "table": "things" + }, + { + "name": "uid", + "type": { + "name": "uuid", + "nullable": true + }, + "table": "things" + }, + { + "name": "tstz", + "type": { + "name": "timestamp with time zone", + "nullable": true + }, + "table": "things" + }, + { + "name": "tsns", + "type": { + "name": "timestamp_ns", + "nullable": true + }, + "table": "things" + }, + { + "name": "iv", + "type": { + "name": "interval", + "nullable": true + }, + "table": "things" + }, + { + "name": "doc", + "type": { + "name": "varchar", + "nullable": true + }, + "table": "things" + }, + { + "name": "grid", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "integer" + } + } + ] + } + } + ] + }, + "table": "things" + }, + { + "name": "vi", + "type": { + "name": "bignum", + "nullable": true + }, + "table": "things" + }, + { + "name": "f4", + "type": { + "name": "float", + "nullable": true + }, + "table": "things" + }, + { + "name": "points", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "struct", + "args": [ + { + "label": "a", + "type": { + "name": "integer" + } + } + ] + } + } + ] + }, + "table": "things" + }, + { + "name": "lists", + "type": { + "name": "map", + "nullable": true, + "args": [ + { + "type": { + "name": "varchar" + } + }, + { + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "integer" + } + } + ] + } + } + ] + }, + "table": "things" + }, + { + "name": "body", + "type": { + "name": "varchar", + "nullable": true + }, + "table": "things" + }, + { + "name": "n", + "type": { + "name": "decimal", + "nullable": true, + "args": [ + { + "int": 18 + }, + { + "int": 3 + } + ] + }, + "table": "things" + } + ], + "params": [] + }, + { + "name": "Casts", + "cmd": ":one", + "columns": [ + { + "name": "a", + "type": { + "name": "decimal", + "args": [ + { + "int": 5 + }, + { + "int": 2 + } + ] + } + }, + { + "name": "b", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "integer" + } + } + ] + } + }, + { + "name": "c", + "type": { + "name": "struct", + "args": [ + { + "label": "a", + "type": { + "name": "integer" + } + } + ] + } + }, + { + "name": "d", + "type": { + "name": "mood" + } + }, + { + "name": "e", + "type": { + "name": "varchar" + } + }, + { + "name": "f", + "type": { + "name": "map", + "args": [ + { + "type": { + "name": "varchar" + } + }, + { + "type": { + "name": "integer" + } + } + ] + } + }, + { + "name": "g", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "integer" + } + }, + { + "int": 3 + } + ] + } + }, + { + "name": "h", + "type": { + "name": "mood" + } + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "", + "type": { + "name": "decimal", + "args": [ + { + "int": 5 + }, + { + "int": 2 + } + ] + } + } + }, + { + "number": 2, + "column": { + "name": "", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "integer" + } + } + ] + } + } + }, + { + "number": 3, + "column": { + "name": "", + "type": { + "name": "struct", + "args": [ + { + "label": "a", + "type": { + "name": "integer" + } + } + ] + } + } + }, + { + "number": 4, + "column": { + "name": "", + "type": { + "name": "mood" + } + } + }, + { + "number": 5, + "column": { + "name": "", + "type": { + "name": "varchar" + } + } + }, + { + "number": 6, + "column": { + "name": "", + "type": { + "name": "map", + "args": [ + { + "type": { + "name": "varchar" + } + }, + { + "type": { + "name": "integer" + } + } + ] + } + } + }, + { + "number": 7, + "column": { + "name": "", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "integer" + } + }, + { + "int": 3 + } + ] + } + } + }, + { + "number": 8, + "column": { + "name": "", + "type": { + "name": "mood" + } + } + } + ] + }, + { + "name": "Params", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "integer" + }, + "table": "things" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "ints", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "integer" + } + } + ] + }, + "table": "things" + } + }, + { + "number": 2, + "column": { + "name": "point", + "type": { + "name": "struct", + "nullable": true, + "args": [ + { + "label": "a", + "type": { + "name": "integer" + } + }, + { + "label": "b", + "type": { + "name": "varchar" + } + } + ] + }, + "table": "things" + } + }, + { + "number": 3, + "column": { + "name": "price", + "type": { + "name": "decimal", + "nullable": true, + "args": [ + { + "int": 18 + }, + { + "int": 3 + } + ] + }, + "table": "things" + } + }, + { + "number": 4, + "column": { + "name": "m", + "type": { + "name": "mood", + "nullable": true + }, + "table": "things" + } + }, + { + "number": 5, + "column": { + "name": "either", + "type": { + "name": "union", + "nullable": true, + "args": [ + { + "label": "num", + "type": { + "name": "integer" + } + }, + { + "label": "str", + "type": { + "name": "varchar" + } + } + ] + }, + "table": "things" + } + }, + { + "number": 6, + "column": { + "name": "grid", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "integer" + } + } + ] + } + } + ] + }, + "table": "things" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_types/googlesql/exec.json b/internal/endtoend/testdata/analyze_types/googlesql/exec.json new file mode 100644 index 0000000000..a53ddddc6d --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/googlesql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "googlesql", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_types/googlesql/query.sql b/internal/endtoend/testdata/analyze_types/googlesql/query.sql new file mode 100644 index 0000000000..c798e56371 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/googlesql/query.sql @@ -0,0 +1,16 @@ +-- name: AllTypes :many +SELECT * FROM things; + +-- name: Casts :one +SELECT + CAST(@a AS NUMERIC(5,2)) AS a, + CAST(@b AS ARRAY) AS b, + CAST(@c AS STRUCT) AS c, + CAST(@d AS STRING(5)) AS d, + SAFE_CAST(@e AS BIGNUMERIC) AS e, + [1, 2] AS f +FROM things; + +-- name: Params :one +SELECT id FROM things +WHERE s = @s AND ai = @ai AND n = @n AND st = @st AND smax = @smax; diff --git a/internal/endtoend/testdata/analyze_types/googlesql/schema.sql b/internal/endtoend/testdata/analyze_types/googlesql/schema.sql new file mode 100644 index 0000000000..feb846800a --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/googlesql/schema.sql @@ -0,0 +1,21 @@ +CREATE TABLE things ( + id INT64 NOT NULL, + s STRING(10), + smax STRING(MAX), + n NUMERIC(10,2), + bn BIGNUMERIC, + byt BYTES(MAX), + ai ARRAY, + as2 ARRAY, + st STRUCT, + ast ARRAY>, + ts TIMESTAMP, + d DATE, + j JSON, + g GEOGRAPHY, + iv INTERVAL, + b BOOL, + f FLOAT64, + f32 FLOAT32, + tl TOKENLIST +) PRIMARY KEY (id); diff --git a/internal/endtoend/testdata/analyze_types/googlesql/stdout.json b/internal/endtoend/testdata/analyze_types/googlesql/stdout.json new file mode 100644 index 0000000000..bae5a9082a --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/googlesql/stdout.json @@ -0,0 +1,482 @@ +[ + { + "name": "AllTypes", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "int64" + }, + "table": "things" + }, + { + "name": "s", + "type": { + "name": "string", + "nullable": true, + "args": [ + { + "int": 10 + } + ] + }, + "table": "things" + }, + { + "name": "smax", + "type": { + "name": "string", + "nullable": true, + "args": [ + { + "ident": "max" + } + ] + }, + "table": "things" + }, + { + "name": "n", + "type": { + "name": "numeric", + "nullable": true, + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "things" + }, + { + "name": "bn", + "type": { + "name": "bignumeric", + "nullable": true + }, + "table": "things" + }, + { + "name": "byt", + "type": { + "name": "bytes", + "nullable": true, + "args": [ + { + "ident": "max" + } + ] + }, + "table": "things" + }, + { + "name": "ai", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "int64" + } + } + ] + }, + "table": "things" + }, + { + "name": "as2", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "string", + "args": [ + { + "ident": "max" + } + ] + } + } + ] + }, + "table": "things" + }, + { + "name": "st", + "type": { + "name": "struct", + "nullable": true, + "args": [ + { + "label": "a", + "type": { + "name": "int64" + } + }, + { + "label": "b", + "type": { + "name": "string" + } + } + ] + }, + "table": "things" + }, + { + "name": "ast", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "struct", + "args": [ + { + "label": "x", + "type": { + "name": "int64" + } + } + ] + } + } + ] + }, + "table": "things" + }, + { + "name": "ts", + "type": { + "name": "timestamp", + "nullable": true + }, + "table": "things" + }, + { + "name": "d", + "type": { + "name": "date", + "nullable": true + }, + "table": "things" + }, + { + "name": "j", + "type": { + "name": "json", + "nullable": true + }, + "table": "things" + }, + { + "name": "g", + "type": { + "name": "geography", + "nullable": true + }, + "table": "things" + }, + { + "name": "iv", + "type": { + "name": "interval", + "nullable": true + }, + "table": "things" + }, + { + "name": "b", + "type": { + "name": "bool", + "nullable": true + }, + "table": "things" + }, + { + "name": "f", + "type": { + "name": "float64", + "nullable": true + }, + "table": "things" + }, + { + "name": "f32", + "type": { + "name": "float32", + "nullable": true + }, + "table": "things" + }, + { + "name": "tl", + "type": { + "name": "tokenlist", + "nullable": true + }, + "table": "things" + } + ], + "params": [] + }, + { + "name": "Casts", + "cmd": ":one", + "columns": [ + { + "name": "a", + "type": { + "name": "numeric", + "args": [ + { + "int": 5 + }, + { + "int": 2 + } + ] + } + }, + { + "name": "b", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "int64" + } + } + ] + } + }, + { + "name": "c", + "type": { + "name": "struct", + "args": [ + { + "label": "x", + "type": { + "name": "int64" + } + } + ] + } + }, + { + "name": "d", + "type": { + "name": "string", + "args": [ + { + "int": 5 + } + ] + } + }, + { + "name": "e", + "type": { + "name": "bignumeric" + } + }, + { + "name": "f" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "", + "type": { + "name": "numeric", + "args": [ + { + "int": 5 + }, + { + "int": 2 + } + ] + } + } + }, + { + "number": 2, + "column": { + "name": "", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "int64" + } + } + ] + } + } + }, + { + "number": 3, + "column": { + "name": "", + "type": { + "name": "struct", + "args": [ + { + "label": "x", + "type": { + "name": "int64" + } + } + ] + } + } + }, + { + "number": 4, + "column": { + "name": "", + "type": { + "name": "string", + "args": [ + { + "int": 5 + } + ] + } + } + }, + { + "number": 5, + "column": { + "name": "", + "type": { + "name": "bignumeric" + } + } + } + ] + }, + { + "name": "Params", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "int64" + }, + "table": "things" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "s", + "type": { + "name": "string", + "nullable": true, + "args": [ + { + "int": 10 + } + ] + }, + "table": "things" + } + }, + { + "number": 2, + "column": { + "name": "ai", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "int64" + } + } + ] + }, + "table": "things" + } + }, + { + "number": 3, + "column": { + "name": "n", + "type": { + "name": "numeric", + "nullable": true, + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "things" + } + }, + { + "number": 4, + "column": { + "name": "st", + "type": { + "name": "struct", + "nullable": true, + "args": [ + { + "label": "a", + "type": { + "name": "int64" + } + }, + { + "label": "b", + "type": { + "name": "string" + } + } + ] + }, + "table": "things" + } + }, + { + "number": 5, + "column": { + "name": "smax", + "type": { + "name": "string", + "nullable": true, + "args": [ + { + "ident": "max" + } + ] + }, + "table": "things" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_types/mssql/exec.json b/internal/endtoend/testdata/analyze_types/mssql/exec.json new file mode 100644 index 0000000000..253b05abbf --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/mssql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "mssql", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_types/mssql/query.sql b/internal/endtoend/testdata/analyze_types/mssql/query.sql new file mode 100644 index 0000000000..98d4e849db --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/mssql/query.sql @@ -0,0 +1,17 @@ +-- name: AllTypes :many +SELECT * FROM things; + +-- name: Casts :one +SELECT + CAST(@a AS DECIMAL(5,2)) AS a, + CAST(@b AS NVARCHAR(MAX)) AS b, + CAST(@c AS VARCHAR(10)) AS c, + CONVERT(DATETIME2(3), @d) AS d, + CAST(@e AS dbo.PhoneNumber) AS e, + TRY_CAST(@f AS FLOAT(24)) AS f, + CAST(@g AS dbo.Code) AS g +FROM things; + +-- name: Params :one +SELECT id FROM things +WHERE price = @price AND body = @body AND phone = @phone AND vec = @vec AND offset_at = @offset_at; diff --git a/internal/endtoend/testdata/analyze_types/mssql/schema.sql b/internal/endtoend/testdata/analyze_types/mssql/schema.sql new file mode 100644 index 0000000000..1e65802777 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/mssql/schema.sql @@ -0,0 +1,37 @@ +CREATE TYPE dbo.PhoneNumber FROM varchar(20) NOT NULL; +CREATE TYPE Code FROM char(3); + +CREATE TABLE things ( + id BIGINT IDENTITY(1,1) PRIMARY KEY, + price DECIMAL(10,2) NOT NULL, + amount NUMERIC(18,4), + plain DECIMAL, + body NVARCHAR(MAX), + title VARCHAR(50), + code CHAR(10), + ncode NCHAR(5), + blob VARBINARY(MAX), + key16 BINARY(16), + created DATETIME2(3), + updated DATETIME2, + offset_at DATETIMEOFFSET(7), + tm TIME(4), + f FLOAT(24), + f53 FLOAT, + r REAL, + m MONEY, + b BIT, + u UNIQUEIDENTIFIER, + x XML, + j JSON, + sv SQL_VARIANT, + rv ROWVERSION, + g GEOGRAPHY, + h HIERARCHYID, + vec VECTOR(3), + sn sysname, + phone dbo.PhoneNumber, + code2 dbo.Code, + code3 Code, + bare VARCHAR +); diff --git a/internal/endtoend/testdata/analyze_types/mssql/stdout.json b/internal/endtoend/testdata/analyze_types/mssql/stdout.json new file mode 100644 index 0000000000..e5cad94250 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/mssql/stdout.json @@ -0,0 +1,601 @@ +[ + { + "name": "AllTypes", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "things" + }, + { + "name": "price", + "type": { + "name": "decimal", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "things" + }, + { + "name": "amount", + "type": { + "name": "decimal", + "nullable": true, + "args": [ + { + "int": 18 + }, + { + "int": 4 + } + ] + }, + "table": "things" + }, + { + "name": "plain", + "type": { + "name": "decimal", + "nullable": true, + "args": [ + { + "int": 18 + }, + { + "int": 0 + } + ] + }, + "table": "things" + }, + { + "name": "body", + "type": { + "name": "nvarchar", + "nullable": true, + "args": [ + { + "ident": "max" + } + ] + }, + "table": "things" + }, + { + "name": "title", + "type": { + "name": "varchar", + "nullable": true, + "args": [ + { + "int": 50 + } + ] + }, + "table": "things" + }, + { + "name": "code", + "type": { + "name": "char", + "nullable": true, + "args": [ + { + "int": 10 + } + ] + }, + "table": "things" + }, + { + "name": "ncode", + "type": { + "name": "nchar", + "nullable": true, + "args": [ + { + "int": 5 + } + ] + }, + "table": "things" + }, + { + "name": "blob", + "type": { + "name": "varbinary", + "nullable": true, + "args": [ + { + "ident": "max" + } + ] + }, + "table": "things" + }, + { + "name": "key16", + "type": { + "name": "binary", + "nullable": true, + "args": [ + { + "int": 16 + } + ] + }, + "table": "things" + }, + { + "name": "created", + "type": { + "name": "datetime2", + "nullable": true, + "args": [ + { + "int": 3 + } + ] + }, + "table": "things" + }, + { + "name": "updated", + "type": { + "name": "datetime2", + "nullable": true, + "args": [ + { + "int": 7 + } + ] + }, + "table": "things" + }, + { + "name": "offset_at", + "type": { + "name": "datetimeoffset", + "nullable": true, + "args": [ + { + "int": 7 + } + ] + }, + "table": "things" + }, + { + "name": "tm", + "type": { + "name": "time", + "nullable": true, + "args": [ + { + "int": 4 + } + ] + }, + "table": "things" + }, + { + "name": "f", + "type": { + "name": "real", + "nullable": true + }, + "table": "things" + }, + { + "name": "f53", + "type": { + "name": "float", + "nullable": true + }, + "table": "things" + }, + { + "name": "r", + "type": { + "name": "real", + "nullable": true + }, + "table": "things" + }, + { + "name": "m", + "type": { + "name": "money", + "nullable": true + }, + "table": "things" + }, + { + "name": "b", + "type": { + "name": "bit", + "nullable": true + }, + "table": "things" + }, + { + "name": "u", + "type": { + "name": "uniqueidentifier", + "nullable": true + }, + "table": "things" + }, + { + "name": "x", + "type": { + "name": "xml", + "nullable": true + }, + "table": "things" + }, + { + "name": "j", + "type": { + "name": "json", + "nullable": true + }, + "table": "things" + }, + { + "name": "sv", + "type": { + "name": "sql_variant", + "nullable": true + }, + "table": "things" + }, + { + "name": "rv", + "type": { + "name": "rowversion", + "nullable": true + }, + "table": "things" + }, + { + "name": "g", + "type": { + "name": "geography", + "nullable": true + }, + "table": "things" + }, + { + "name": "h", + "type": { + "name": "hierarchyid", + "nullable": true + }, + "table": "things" + }, + { + "name": "vec", + "type": { + "name": "vector", + "nullable": true, + "args": [ + { + "int": 3 + } + ] + }, + "table": "things" + }, + { + "name": "sn", + "type": { + "name": "nvarchar", + "nullable": true, + "args": [ + { + "int": 128 + } + ] + }, + "table": "things" + }, + { + "name": "phone", + "type": { + "name": "phonenumber" + }, + "table": "things" + }, + { + "name": "code2", + "type": { + "name": "code", + "nullable": true + }, + "table": "things" + }, + { + "name": "code3", + "type": { + "name": "code", + "nullable": true + }, + "table": "things" + }, + { + "name": "bare", + "type": { + "name": "varchar", + "nullable": true, + "args": [ + { + "int": 1 + } + ] + }, + "table": "things" + } + ], + "params": [] + }, + { + "name": "Casts", + "cmd": ":one", + "columns": [ + { + "name": "a", + "type": { + "name": "decimal", + "args": [ + { + "int": 5 + }, + { + "int": 2 + } + ] + } + }, + { + "name": "b", + "type": { + "name": "nvarchar", + "args": [ + { + "ident": "max" + } + ] + } + }, + { + "name": "c", + "type": { + "name": "varchar", + "args": [ + { + "int": 10 + } + ] + } + }, + { + "name": "d", + "type": { + "name": "datetime2", + "args": [ + { + "int": 3 + } + ] + } + }, + { + "name": "e", + "type": { + "name": "phonenumber" + } + }, + { + "name": "f", + "type": { + "name": "real" + } + }, + { + "name": "g", + "type": { + "name": "code" + } + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "", + "type": { + "name": "decimal", + "args": [ + { + "int": 5 + }, + { + "int": 2 + } + ] + } + } + }, + { + "number": 2, + "column": { + "name": "", + "type": { + "name": "nvarchar", + "args": [ + { + "ident": "max" + } + ] + } + } + }, + { + "number": 3, + "column": { + "name": "", + "type": { + "name": "varchar", + "args": [ + { + "int": 10 + } + ] + } + } + }, + { + "number": 4, + "column": { + "name": "", + "type": { + "name": "datetime2", + "args": [ + { + "int": 3 + } + ] + } + } + }, + { + "number": 5, + "column": { + "name": "", + "type": { + "name": "phonenumber" + } + } + }, + { + "number": 6, + "column": { + "name": "", + "type": { + "name": "real" + } + } + }, + { + "number": 7, + "column": { + "name": "", + "type": { + "name": "code" + } + } + } + ] + }, + { + "name": "Params", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "things" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "price", + "type": { + "name": "decimal", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "things" + } + }, + { + "number": 2, + "column": { + "name": "body", + "type": { + "name": "nvarchar", + "nullable": true, + "args": [ + { + "ident": "max" + } + ] + }, + "table": "things" + } + }, + { + "number": 3, + "column": { + "name": "phone", + "type": { + "name": "phonenumber" + }, + "table": "things" + } + }, + { + "number": 4, + "column": { + "name": "vec", + "type": { + "name": "vector", + "nullable": true, + "args": [ + { + "int": 3 + } + ] + }, + "table": "things" + } + }, + { + "number": 5, + "column": { + "name": "offset_at", + "type": { + "name": "datetimeoffset", + "nullable": true, + "args": [ + { + "int": 7 + } + ] + }, + "table": "things" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_types/mysql/exec.json b/internal/endtoend/testdata/analyze_types/mysql/exec.json new file mode 100644 index 0000000000..a5b24d3361 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/mysql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "mysql", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_types/mysql/query.sql b/internal/endtoend/testdata/analyze_types/mysql/query.sql new file mode 100644 index 0000000000..3b3c2a4fd1 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/mysql/query.sql @@ -0,0 +1,22 @@ +-- name: AllTypes :many +SELECT * FROM things; + +-- name: Casts :one +SELECT + CAST(count AS UNSIGNED) AS a, + CAST(price AS DECIMAL(5,2)) AS b, + CAST(title AS CHAR(10)) AS c, + CAST(count AS SIGNED) AS d, + CAST(doc AS JSON) AS e, + CAST(created AS DATETIME(3)) AS f, + CAST(price AS DECIMAL) AS g, + CAST(key16 AS BINARY(8)) AS h, + CAST(d AS DOUBLE) AS i, + CAST(f AS FLOAT) AS j, + CAST(price AS DEC(6,1)) AS k, + CAST(price AS DECIMAL(5)) AS l +FROM things; + +-- name: Params :one +SELECT id FROM things +WHERE count = ? AND price = ? AND kind = ? AND flags = ? AND title = ? AND uprice = ? AND flag = ? AND created = ?; diff --git a/internal/endtoend/testdata/analyze_types/mysql/schema.sql b/internal/endtoend/testdata/analyze_types/mysql/schema.sql new file mode 100644 index 0000000000..880de33be2 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/mysql/schema.sql @@ -0,0 +1,29 @@ +CREATE TABLE things ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + flag TINYINT(1), + count INT UNSIGNED NOT NULL, + price DECIMAL(10,2) NOT NULL, + uprice DECIMAL(10,2) UNSIGNED, + plain DECIMAL, + dd DEC(7,2), + ratio FLOAT(7,4), + f FLOAT, + title VARCHAR(255), + code CHAR(3), + kind ENUM('a','b'), + flags SET('x','y'), + doc JSON, + key16 BINARY(16), + blob255 VARBINARY(255), + created DATETIME(6), + updated TIMESTAMP(3), + y YEAR, + bits BIT(8), + body TEXT, + bin VARCHAR(10) CHARACTER SET binary, + geo GEOMETRY, + ok BOOLEAN, + d DOUBLE, + small MEDIUMINT UNSIGNED, + i INT +); diff --git a/internal/endtoend/testdata/analyze_types/mysql/stdout.json b/internal/endtoend/testdata/analyze_types/mysql/stdout.json new file mode 100644 index 0000000000..1e031b3570 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/mysql/stdout.json @@ -0,0 +1,608 @@ +[ + { + "name": "AllTypes", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint unsigned" + }, + "table": "things" + }, + { + "name": "flag", + "type": { + "name": "tinyint", + "nullable": true, + "args": [ + { + "int": 1 + } + ] + }, + "table": "things" + }, + { + "name": "count", + "type": { + "name": "int unsigned" + }, + "table": "things" + }, + { + "name": "price", + "type": { + "name": "decimal", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "things" + }, + { + "name": "uprice", + "type": { + "name": "decimal unsigned", + "nullable": true, + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "things" + }, + { + "name": "plain", + "type": { + "name": "decimal", + "nullable": true, + "args": [ + { + "int": 10 + }, + { + "int": 0 + } + ] + }, + "table": "things" + }, + { + "name": "dd", + "type": { + "name": "decimal", + "nullable": true, + "args": [ + { + "int": 7 + }, + { + "int": 2 + } + ] + }, + "table": "things" + }, + { + "name": "ratio", + "type": { + "name": "float", + "nullable": true, + "args": [ + { + "int": 7 + }, + { + "int": 4 + } + ] + }, + "table": "things" + }, + { + "name": "f", + "type": { + "name": "float", + "nullable": true + }, + "table": "things" + }, + { + "name": "title", + "type": { + "name": "varchar", + "nullable": true, + "args": [ + { + "int": 255 + } + ] + }, + "table": "things" + }, + { + "name": "code", + "type": { + "name": "char", + "nullable": true, + "args": [ + { + "int": 3 + } + ] + }, + "table": "things" + }, + { + "name": "kind", + "type": { + "name": "enum", + "nullable": true, + "args": [ + { + "string": "a" + }, + { + "string": "b" + } + ] + }, + "table": "things" + }, + { + "name": "flags", + "type": { + "name": "set", + "nullable": true, + "args": [ + { + "string": "x" + }, + { + "string": "y" + } + ] + }, + "table": "things" + }, + { + "name": "doc", + "type": { + "name": "json", + "nullable": true + }, + "table": "things" + }, + { + "name": "key16", + "type": { + "name": "binary", + "nullable": true, + "args": [ + { + "int": 16 + } + ] + }, + "table": "things" + }, + { + "name": "blob255", + "type": { + "name": "varbinary", + "nullable": true, + "args": [ + { + "int": 255 + } + ] + }, + "table": "things" + }, + { + "name": "created", + "type": { + "name": "datetime", + "nullable": true, + "args": [ + { + "int": 6 + } + ] + }, + "table": "things" + }, + { + "name": "updated", + "type": { + "name": "timestamp", + "nullable": true, + "args": [ + { + "int": 3 + } + ] + }, + "table": "things" + }, + { + "name": "y", + "type": { + "name": "year", + "nullable": true + }, + "table": "things" + }, + { + "name": "bits", + "type": { + "name": "bit", + "nullable": true, + "args": [ + { + "int": 8 + } + ] + }, + "table": "things" + }, + { + "name": "body", + "type": { + "name": "text", + "nullable": true + }, + "table": "things" + }, + { + "name": "bin", + "type": { + "name": "varbinary", + "nullable": true, + "args": [ + { + "int": 10 + } + ] + }, + "table": "things" + }, + { + "name": "geo", + "type": { + "name": "geometry", + "nullable": true + }, + "table": "things" + }, + { + "name": "ok", + "type": { + "name": "tinyint", + "nullable": true, + "args": [ + { + "int": 1 + } + ] + }, + "table": "things" + }, + { + "name": "d", + "type": { + "name": "double", + "nullable": true + }, + "table": "things" + }, + { + "name": "small", + "type": { + "name": "mediumint unsigned", + "nullable": true + }, + "table": "things" + }, + { + "name": "i", + "type": { + "name": "int", + "nullable": true + }, + "table": "things" + } + ], + "params": [] + }, + { + "name": "Casts", + "cmd": ":one", + "columns": [ + { + "name": "a", + "type": { + "name": "bigint unsigned" + } + }, + { + "name": "b", + "type": { + "name": "decimal", + "args": [ + { + "int": 5 + }, + { + "int": 2 + } + ] + } + }, + { + "name": "c", + "type": { + "name": "varchar", + "nullable": true, + "args": [ + { + "int": 10 + } + ] + } + }, + { + "name": "d", + "type": { + "name": "bigint" + } + }, + { + "name": "e", + "type": { + "name": "json", + "nullable": true + } + }, + { + "name": "f", + "type": { + "name": "datetime", + "nullable": true, + "args": [ + { + "int": 3 + } + ] + } + }, + { + "name": "g", + "type": { + "name": "decimal", + "args": [ + { + "int": 10 + }, + { + "int": 0 + } + ] + } + }, + { + "name": "h", + "type": { + "name": "varbinary", + "nullable": true, + "args": [ + { + "int": 8 + } + ] + } + }, + { + "name": "i", + "type": { + "name": "double", + "nullable": true + } + }, + { + "name": "j", + "type": { + "name": "float", + "nullable": true + } + }, + { + "name": "k", + "type": { + "name": "decimal", + "args": [ + { + "int": 6 + }, + { + "int": 1 + } + ] + } + }, + { + "name": "l", + "type": { + "name": "decimal", + "args": [ + { + "int": 5 + }, + { + "int": 0 + } + ] + } + } + ], + "params": [] + }, + { + "name": "Params", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint unsigned" + }, + "table": "things" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "count", + "type": { + "name": "int unsigned" + }, + "table": "things" + } + }, + { + "number": 2, + "column": { + "name": "price", + "type": { + "name": "decimal", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "things" + } + }, + { + "number": 3, + "column": { + "name": "kind", + "type": { + "name": "enum", + "nullable": true, + "args": [ + { + "string": "a" + }, + { + "string": "b" + } + ] + }, + "table": "things" + } + }, + { + "number": 4, + "column": { + "name": "flags", + "type": { + "name": "set", + "nullable": true, + "args": [ + { + "string": "x" + }, + { + "string": "y" + } + ] + }, + "table": "things" + } + }, + { + "number": 5, + "column": { + "name": "title", + "type": { + "name": "varchar", + "nullable": true, + "args": [ + { + "int": 255 + } + ] + }, + "table": "things" + } + }, + { + "number": 6, + "column": { + "name": "uprice", + "type": { + "name": "decimal unsigned", + "nullable": true, + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "things" + } + }, + { + "number": 7, + "column": { + "name": "flag", + "type": { + "name": "tinyint", + "nullable": true, + "args": [ + { + "int": 1 + } + ] + }, + "table": "things" + } + }, + { + "number": 8, + "column": { + "name": "created", + "type": { + "name": "datetime", + "nullable": true, + "args": [ + { + "int": 6 + } + ] + }, + "table": "things" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_types/postgresql/exec.json b/internal/endtoend/testdata/analyze_types/postgresql/exec.json new file mode 100644 index 0000000000..b102755fb6 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/postgresql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "postgresql", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_types/postgresql/query.sql b/internal/endtoend/testdata/analyze_types/postgresql/query.sql new file mode 100644 index 0000000000..ad7746ed08 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/postgresql/query.sql @@ -0,0 +1,25 @@ +-- name: AllTypes :many +SELECT * FROM things; + +-- name: Casts :one +SELECT + $1::numeric(10,2) AS a, + $2::int[] AS b, + price::text AS c, + $3::mood AS d, + $4::varchar(20) AS e, + $5::posint AS f, + 1::int8 AS g, + $6::int4[][] AS h, + $7::numeric(5,1) AS i, + ARRAY[1, 2] AS j, + $8::myschema.mood AS k, + $9::varchar(10)[] AS l, + $10::interval day to second AS m, + $11::myschema.mood[] AS n, + $12::mood[] AS o +FROM things; + +-- name: Params :one +SELECT id FROM things +WHERE price = $1 AND ints = $2 AND m = $3 AND p = $4 AND title = $5 AND grid = $6 AND sn = $7 AND fr = $8 AND ivd = $9; diff --git a/internal/endtoend/testdata/analyze_types/postgresql/schema.sql b/internal/endtoend/testdata/analyze_types/postgresql/schema.sql new file mode 100644 index 0000000000..0db7266d6b --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/postgresql/schema.sql @@ -0,0 +1,47 @@ +CREATE EXTENSION hstore; +CREATE SCHEMA myschema; +CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy'); +CREATE TYPE myschema.mood AS ENUM ('x', 'y'); +CREATE DOMAIN posint AS integer CHECK (VALUE > 0); +CREATE DOMAIN shortname AS varchar(20) NOT NULL; +CREATE TYPE point2 AS (x float8, y float8); +CREATE TYPE floatrange AS RANGE (subtype = float8); + +CREATE TABLE things ( + id bigserial PRIMARY KEY, + price numeric(10,2) NOT NULL, + amount numeric, + title varchar(255), + code character varying(10), + tag char(5), + raw bpchar, + count pg_catalog.int4, + ints int[], + grid int[][], + bounded int[3], + words text[] NOT NULL, + prices numeric(10,2)[], + ts timestamp(3), + tstz timestamptz NOT NULL, + ttz time with time zone, + iv interval, + ivd interval day to second, + iv3 interval(3), + m mood, + mm myschema.mood, + mms myschema.mood[], + p posint, + sn shortname, + pt point2, + pts point2[], + fr floatrange, + ir int4range, + b bit(8), + vb varbit(16), + js jsonb, + u uuid, + h hstore, + moods mood[], + dp double precision, + ts2 timestamp without time zone +); diff --git a/internal/endtoend/testdata/analyze_types/postgresql/stdout.json b/internal/endtoend/testdata/analyze_types/postgresql/stdout.json new file mode 100644 index 0000000000..6091af1641 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/postgresql/stdout.json @@ -0,0 +1,921 @@ +[ + { + "name": "AllTypes", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "things" + }, + { + "name": "price", + "type": { + "name": "numeric", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "things" + }, + { + "name": "amount", + "type": { + "name": "numeric", + "nullable": true + }, + "table": "things" + }, + { + "name": "title", + "type": { + "name": "character varying", + "nullable": true, + "args": [ + { + "int": 255 + } + ] + }, + "table": "things" + }, + { + "name": "code", + "type": { + "name": "character varying", + "nullable": true, + "args": [ + { + "int": 10 + } + ] + }, + "table": "things" + }, + { + "name": "tag", + "type": { + "name": "character", + "nullable": true, + "args": [ + { + "int": 5 + } + ] + }, + "table": "things" + }, + { + "name": "raw", + "type": { + "name": "character", + "nullable": true + }, + "table": "things" + }, + { + "name": "count", + "type": { + "name": "integer", + "nullable": true + }, + "table": "things" + }, + { + "name": "ints", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "integer" + } + } + ] + }, + "table": "things" + }, + { + "name": "grid", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "integer" + } + } + ] + } + } + ] + }, + "table": "things" + }, + { + "name": "bounded", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "integer" + } + } + ] + }, + "table": "things" + }, + { + "name": "words", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "text" + } + } + ] + }, + "table": "things" + }, + { + "name": "prices", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "numeric", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + } + } + ] + }, + "table": "things" + }, + { + "name": "ts", + "type": { + "name": "timestamp without time zone", + "nullable": true, + "args": [ + { + "int": 3 + } + ] + }, + "table": "things" + }, + { + "name": "tstz", + "type": { + "name": "timestamp with time zone" + }, + "table": "things" + }, + { + "name": "ttz", + "type": { + "name": "time with time zone", + "nullable": true + }, + "table": "things" + }, + { + "name": "iv", + "type": { + "name": "interval", + "nullable": true + }, + "table": "things" + }, + { + "name": "ivd", + "type": { + "name": "interval", + "nullable": true, + "args": [ + { + "ident": "day to second" + } + ] + }, + "table": "things" + }, + { + "name": "iv3", + "type": { + "name": "interval", + "nullable": true, + "args": [ + { + "int": 3 + } + ] + }, + "table": "things" + }, + { + "name": "m", + "type": { + "name": "mood", + "nullable": true + }, + "table": "things" + }, + { + "name": "mm", + "type": { + "name": "myschema.mood", + "nullable": true + }, + "table": "things" + }, + { + "name": "mms", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "myschema.mood" + } + } + ] + }, + "table": "things" + }, + { + "name": "p", + "type": { + "name": "posint", + "nullable": true + }, + "table": "things" + }, + { + "name": "sn", + "type": { + "name": "shortname" + }, + "table": "things" + }, + { + "name": "pt", + "type": { + "name": "point2", + "nullable": true + }, + "table": "things" + }, + { + "name": "pts", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "point2" + } + } + ] + }, + "table": "things" + }, + { + "name": "fr", + "type": { + "name": "floatrange", + "nullable": true + }, + "table": "things" + }, + { + "name": "ir", + "type": { + "name": "int4range", + "nullable": true + }, + "table": "things" + }, + { + "name": "b", + "type": { + "name": "bit", + "nullable": true, + "args": [ + { + "int": 8 + } + ] + }, + "table": "things" + }, + { + "name": "vb", + "type": { + "name": "bit varying", + "nullable": true, + "args": [ + { + "int": 16 + } + ] + }, + "table": "things" + }, + { + "name": "js", + "type": { + "name": "jsonb", + "nullable": true + }, + "table": "things" + }, + { + "name": "u", + "type": { + "name": "uuid", + "nullable": true + }, + "table": "things" + }, + { + "name": "h", + "type": { + "name": "hstore", + "nullable": true + }, + "table": "things" + }, + { + "name": "moods", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "mood" + } + } + ] + }, + "table": "things" + }, + { + "name": "dp", + "type": { + "name": "double precision", + "nullable": true + }, + "table": "things" + }, + { + "name": "ts2", + "type": { + "name": "timestamp without time zone", + "nullable": true + }, + "table": "things" + } + ], + "params": [] + }, + { + "name": "Casts", + "cmd": ":one", + "columns": [ + { + "name": "a", + "type": { + "name": "numeric", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + } + }, + { + "name": "b", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "integer" + } + } + ] + } + }, + { + "name": "c", + "type": { + "name": "text" + } + }, + { + "name": "d", + "type": { + "name": "mood" + } + }, + { + "name": "e", + "type": { + "name": "character varying", + "args": [ + { + "int": 20 + } + ] + } + }, + { + "name": "f", + "type": { + "name": "posint" + } + }, + { + "name": "g", + "type": { + "name": "bigint" + } + }, + { + "name": "h", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "integer" + } + } + ] + } + } + ] + } + }, + { + "name": "i", + "type": { + "name": "numeric", + "args": [ + { + "int": 5 + }, + { + "int": 1 + } + ] + } + }, + { + "name": "j", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "integer" + } + } + ] + } + }, + { + "name": "k", + "type": { + "name": "myschema.mood" + } + }, + { + "name": "l", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "character varying", + "args": [ + { + "int": 10 + } + ] + } + } + ] + } + }, + { + "name": "m", + "type": { + "name": "interval", + "args": [ + { + "ident": "day to second" + } + ] + } + }, + { + "name": "n", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "myschema.mood" + } + } + ] + } + }, + { + "name": "o", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "mood" + } + } + ] + } + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "", + "type": { + "name": "numeric", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + } + } + }, + { + "number": 2, + "column": { + "name": "", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "integer" + } + } + ] + } + } + }, + { + "number": 3, + "column": { + "name": "", + "type": { + "name": "mood" + } + } + }, + { + "number": 4, + "column": { + "name": "", + "type": { + "name": "character varying", + "args": [ + { + "int": 20 + } + ] + } + } + }, + { + "number": 5, + "column": { + "name": "", + "type": { + "name": "posint" + } + } + }, + { + "number": 6, + "column": { + "name": "", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "integer" + } + } + ] + } + } + ] + } + } + }, + { + "number": 7, + "column": { + "name": "", + "type": { + "name": "numeric", + "args": [ + { + "int": 5 + }, + { + "int": 1 + } + ] + } + } + }, + { + "number": 8, + "column": { + "name": "", + "type": { + "name": "myschema.mood" + } + } + }, + { + "number": 9, + "column": { + "name": "", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "character varying", + "args": [ + { + "int": 10 + } + ] + } + } + ] + } + } + }, + { + "number": 10, + "column": { + "name": "", + "type": { + "name": "interval", + "args": [ + { + "ident": "day to second" + } + ] + } + } + }, + { + "number": 11, + "column": { + "name": "", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "myschema.mood" + } + } + ] + } + } + }, + { + "number": 12, + "column": { + "name": "", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "mood" + } + } + ] + } + } + } + ] + }, + { + "name": "Params", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "things" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "price", + "type": { + "name": "numeric", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "things" + } + }, + { + "number": 2, + "column": { + "name": "ints", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "integer" + } + } + ] + }, + "table": "things" + } + }, + { + "number": 3, + "column": { + "name": "m", + "type": { + "name": "mood", + "nullable": true + }, + "table": "things" + } + }, + { + "number": 4, + "column": { + "name": "p", + "type": { + "name": "posint", + "nullable": true + }, + "table": "things" + } + }, + { + "number": 5, + "column": { + "name": "title", + "type": { + "name": "character varying", + "nullable": true, + "args": [ + { + "int": 255 + } + ] + }, + "table": "things" + } + }, + { + "number": 6, + "column": { + "name": "grid", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "integer" + } + } + ] + } + } + ] + }, + "table": "things" + } + }, + { + "number": 7, + "column": { + "name": "sn", + "type": { + "name": "shortname" + }, + "table": "things" + } + }, + { + "number": 8, + "column": { + "name": "fr", + "type": { + "name": "floatrange", + "nullable": true + }, + "table": "things" + } + }, + { + "number": 9, + "column": { + "name": "ivd", + "type": { + "name": "interval", + "nullable": true, + "args": [ + { + "ident": "day to second" + } + ] + }, + "table": "things" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_types/sqlite/exec.json b/internal/endtoend/testdata/analyze_types/sqlite/exec.json new file mode 100644 index 0000000000..aa77909cb2 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/sqlite/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "sqlite", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_types/sqlite/fixture.sql b/internal/endtoend/testdata/analyze_types/sqlite/fixture.sql new file mode 100644 index 0000000000..122acdd435 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/sqlite/fixture.sql @@ -0,0 +1,4 @@ +INSERT INTO things (id, title, code, price, flag, big, data, untyped, ratio, weird, created, n, label) +VALUES (1, 'abc', 'xy', 1.5, 1, 9000000000, x'00ff', 7, 2.5, '12', '2024-01-01 00:00:00', 3, 'ab'); +INSERT INTO strict_things (id, anything, body, amount, raw, n) VALUES (1, 'x', 'b', 1.5, x'00', 2); +INSERT INTO things (id, n) VALUES (2, 0); diff --git a/internal/endtoend/testdata/analyze_types/sqlite/query.sql b/internal/endtoend/testdata/analyze_types/sqlite/query.sql new file mode 100644 index 0000000000..315331198b --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/sqlite/query.sql @@ -0,0 +1,18 @@ +-- name: AllTypes :many +SELECT * FROM things; + +-- name: StrictTypes :many +SELECT * FROM strict_things; + +-- name: Casts :one +SELECT + CAST(title AS INTEGER) AS a, + CAST(n AS TEXT) AS b, + CAST(title AS REAL) AS d, + weird + 1 AS e, + title || 'x' AS f +FROM things; + +-- name: Params :one +SELECT id FROM things +WHERE title = ? AND price = ? AND untyped = ? AND weird = ? AND big = ? AND n = ?; diff --git a/internal/endtoend/testdata/analyze_types/sqlite/schema.sql b/internal/endtoend/testdata/analyze_types/sqlite/schema.sql new file mode 100644 index 0000000000..675a8d602a --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/sqlite/schema.sql @@ -0,0 +1,24 @@ +CREATE TABLE things ( + id INTEGER PRIMARY KEY, + title VARCHAR(255), + code VARYING CHARACTER(10), + price DECIMAL(10,5), + flag BOOLEAN, + big UNSIGNED BIG INT, + data BLOB, + untyped, + ratio DOUBLE PRECISION, + weird FOO BAR(3), + created DATETIME, + n INT NOT NULL, + label NCHAR(5) +); + +CREATE TABLE strict_things ( + id INTEGER, + anything ANY, + body TEXT, + amount REAL, + raw BLOB, + n INT +) STRICT; diff --git a/internal/endtoend/testdata/analyze_types/sqlite/stdout.json b/internal/endtoend/testdata/analyze_types/sqlite/stdout.json new file mode 100644 index 0000000000..7d992f9f73 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/sqlite/stdout.json @@ -0,0 +1,333 @@ +[ + { + "name": "AllTypes", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "integer" + }, + "table": "things" + }, + { + "name": "title", + "type": { + "name": "varchar", + "nullable": true, + "args": [ + { + "int": 255 + } + ] + }, + "table": "things" + }, + { + "name": "code", + "type": { + "name": "varying character", + "nullable": true, + "args": [ + { + "int": 10 + } + ] + }, + "table": "things" + }, + { + "name": "price", + "type": { + "name": "decimal", + "nullable": true, + "args": [ + { + "int": 10 + }, + { + "int": 5 + } + ] + }, + "table": "things" + }, + { + "name": "flag", + "type": { + "name": "boolean", + "nullable": true + }, + "table": "things" + }, + { + "name": "big", + "type": { + "name": "unsigned big int", + "nullable": true + }, + "table": "things" + }, + { + "name": "data", + "type": { + "name": "blob", + "nullable": true + }, + "table": "things" + }, + { + "name": "untyped", + "type": { + "name": "any", + "nullable": true + }, + "table": "things" + }, + { + "name": "ratio", + "type": { + "name": "double precision", + "nullable": true + }, + "table": "things" + }, + { + "name": "weird", + "type": { + "name": "foo bar", + "nullable": true, + "args": [ + { + "int": 3 + } + ] + }, + "table": "things" + }, + { + "name": "created", + "type": { + "name": "datetime", + "nullable": true + }, + "table": "things" + }, + { + "name": "n", + "type": { + "name": "int" + }, + "table": "things" + }, + { + "name": "label", + "type": { + "name": "nchar", + "nullable": true, + "args": [ + { + "int": 5 + } + ] + }, + "table": "things" + } + ], + "params": [] + }, + { + "name": "StrictTypes", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "integer", + "nullable": true + }, + "table": "strict_things" + }, + { + "name": "anything", + "type": { + "name": "any", + "nullable": true + }, + "table": "strict_things" + }, + { + "name": "body", + "type": { + "name": "text", + "nullable": true + }, + "table": "strict_things" + }, + { + "name": "amount", + "type": { + "name": "real", + "nullable": true + }, + "table": "strict_things" + }, + { + "name": "raw", + "type": { + "name": "blob", + "nullable": true + }, + "table": "strict_things" + }, + { + "name": "n", + "type": { + "name": "int", + "nullable": true + }, + "table": "strict_things" + } + ], + "params": [] + }, + { + "name": "Casts", + "cmd": ":one", + "columns": [ + { + "name": "a", + "type": { + "name": "integer", + "nullable": true + } + }, + { + "name": "b", + "type": { + "name": "text" + } + }, + { + "name": "d", + "type": { + "name": "real", + "nullable": true + } + }, + { + "name": "e", + "type": { + "name": "integer", + "nullable": true + } + }, + { + "name": "f", + "type": { + "name": "text", + "nullable": true + } + } + ], + "params": [] + }, + { + "name": "Params", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "integer" + }, + "table": "things" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "title", + "type": { + "name": "varchar", + "nullable": true, + "args": [ + { + "int": 255 + } + ] + }, + "table": "things" + } + }, + { + "number": 2, + "column": { + "name": "price", + "type": { + "name": "decimal", + "nullable": true, + "args": [ + { + "int": 10 + }, + { + "int": 5 + } + ] + }, + "table": "things" + } + }, + { + "number": 3, + "column": { + "name": "untyped", + "type": { + "name": "any", + "nullable": true + }, + "table": "things" + } + }, + { + "number": 4, + "column": { + "name": "weird", + "type": { + "name": "foo bar", + "nullable": true, + "args": [ + { + "int": 3 + } + ] + }, + "table": "things" + } + }, + { + "number": 5, + "column": { + "name": "big", + "type": { + "name": "unsigned big int", + "nullable": true + }, + "table": "things" + } + }, + { + "number": 6, + "column": { + "name": "n", + "type": { + "name": "int" + }, + "table": "things" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/codegen_json/gen/codegen.json b/internal/endtoend/testdata/codegen_json/gen/codegen.json index 1e3a217541..47a6e3a39c 100644 --- a/internal/endtoend/testdata/codegen_json/gen/codegen.json +++ b/internal/endtoend/testdata/codegen_json/gen/codegen.json @@ -2869,7 +2869,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 16, "is_named_param": false, "is_func_call": false, "scope": "", @@ -2882,13 +2882,13 @@ "type": { "catalog": "", "schema": "", - "name": "_aclitem" + "name": "aclitem" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "attoptions", @@ -2908,13 +2908,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "attfdwoptions", @@ -2934,13 +2934,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "attmissingval", @@ -3991,7 +3991,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 64, "is_named_param": false, "is_func_call": false, "scope": "", @@ -4004,13 +4004,13 @@ "type": { "catalog": "", "schema": "", - "name": "_name" + "name": "name" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "comment", @@ -5669,7 +5669,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 16, "is_named_param": false, "is_func_call": false, "scope": "", @@ -5682,13 +5682,13 @@ "type": { "catalog": "", "schema": "", - "name": "_aclitem" + "name": "aclitem" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "reloptions", @@ -5708,13 +5708,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "relpartbound", @@ -6921,7 +6921,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 2, "is_named_param": false, "is_func_call": false, "scope": "", @@ -6934,20 +6934,20 @@ "type": { "catalog": "", "schema": "", - "name": "_int2" + "name": "int2" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "confkey", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 2, "is_named_param": false, "is_func_call": false, "scope": "", @@ -6960,20 +6960,20 @@ "type": { "catalog": "", "schema": "", - "name": "_int2" + "name": "int2" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "conpfeqop", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -6986,20 +6986,20 @@ "type": { "catalog": "", "schema": "", - "name": "_oid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "conppeqop", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -7012,20 +7012,20 @@ "type": { "catalog": "", "schema": "", - "name": "_oid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "conffeqop", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -7038,20 +7038,20 @@ "type": { "catalog": "", "schema": "", - "name": "_oid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "confdelsetcols", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 2, "is_named_param": false, "is_func_call": false, "scope": "", @@ -7064,20 +7064,20 @@ "type": { "catalog": "", "schema": "", - "name": "_int2" + "name": "int2" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "conexclop", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -7090,13 +7090,13 @@ "type": { "catalog": "", "schema": "", - "name": "_oid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "conbin", @@ -8251,7 +8251,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 16, "is_named_param": false, "is_func_call": false, "scope": "", @@ -8264,13 +8264,13 @@ "type": { "catalog": "", "schema": "", - "name": "_aclitem" + "name": "aclitem" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -8508,13 +8508,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -8791,7 +8791,7 @@ "not_null": true, "is_array": true, "comment": "", - "length": -1, + "length": 16, "is_named_param": false, "is_func_call": false, "scope": "", @@ -8804,13 +8804,13 @@ "type": { "catalog": "", "schema": "", - "name": "_aclitem" + "name": "aclitem" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -10040,13 +10040,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -10375,7 +10375,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -10388,13 +10388,13 @@ "type": { "catalog": "", "schema": "", - "name": "_oid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "extcondition", @@ -10414,13 +10414,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -10915,7 +10915,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 16, "is_named_param": false, "is_func_call": false, "scope": "", @@ -10928,13 +10928,13 @@ "type": { "catalog": "", "schema": "", - "name": "_aclitem" + "name": "aclitem" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "fdwoptions", @@ -10954,13 +10954,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -11289,7 +11289,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 16, "is_named_param": false, "is_func_call": false, "scope": "", @@ -11302,13 +11302,13 @@ "type": { "catalog": "", "schema": "", - "name": "_aclitem" + "name": "aclitem" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "srvoptions", @@ -11328,13 +11328,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -11572,13 +11572,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -11647,7 +11647,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -11660,13 +11660,13 @@ "type": { "catalog": "", "schema": "", - "name": "_oid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -11800,13 +11800,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "user_name", @@ -11826,13 +11826,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "address", @@ -11930,13 +11930,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "error", @@ -12715,7 +12715,7 @@ { "name": "indkey", "not_null": true, - "is_array": true, + "is_array": false, "comment": "", "length": -1, "is_named_param": false, @@ -12741,7 +12741,7 @@ { "name": "indcollation", "not_null": true, - "is_array": true, + "is_array": false, "comment": "", "length": -1, "is_named_param": false, @@ -12767,7 +12767,7 @@ { "name": "indclass", "not_null": true, - "is_array": true, + "is_array": false, "comment": "", "length": -1, "is_named_param": false, @@ -12793,7 +12793,7 @@ { "name": "indoption", "not_null": true, - "is_array": true, + "is_array": false, "comment": "", "length": -1, "is_named_param": false, @@ -13553,7 +13553,7 @@ "not_null": true, "is_array": true, "comment": "", - "length": -1, + "length": 16, "is_named_param": false, "is_func_call": false, "scope": "", @@ -13566,13 +13566,13 @@ "type": { "catalog": "", "schema": "", - "name": "_aclitem" + "name": "aclitem" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -13953,7 +13953,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 16, "is_named_param": false, "is_func_call": false, "scope": "", @@ -13966,13 +13966,13 @@ "type": { "catalog": "", "schema": "", - "name": "_aclitem" + "name": "aclitem" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -14441,7 +14441,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 16, "is_named_param": false, "is_func_call": false, "scope": "", @@ -14454,13 +14454,13 @@ "type": { "catalog": "", "schema": "", - "name": "_aclitem" + "name": "aclitem" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -15329,7 +15329,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 16, "is_named_param": false, "is_func_call": false, "scope": "", @@ -15342,13 +15342,13 @@ "type": { "catalog": "", "schema": "", - "name": "_aclitem" + "name": "aclitem" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -16825,7 +16825,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 16, "is_named_param": false, "is_func_call": false, "scope": "", @@ -16838,13 +16838,13 @@ "type": { "catalog": "", "schema": "", - "name": "_aclitem" + "name": "aclitem" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -17119,7 +17119,7 @@ { "name": "partattrs", "not_null": true, - "is_array": true, + "is_array": false, "comment": "", "length": -1, "is_named_param": false, @@ -17145,7 +17145,7 @@ { "name": "partclass", "not_null": true, - "is_array": true, + "is_array": false, "comment": "", "length": -1, "is_named_param": false, @@ -17171,7 +17171,7 @@ { "name": "partcollation", "not_null": true, - "is_array": true, + "is_array": false, "comment": "", "length": -1, "is_named_param": false, @@ -17339,7 +17339,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 64, "is_named_param": false, "is_func_call": false, "scope": "", @@ -17352,13 +17352,13 @@ "type": { "catalog": "", "schema": "", - "name": "_name" + "name": "name" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "cmd", @@ -17739,7 +17739,7 @@ "not_null": true, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -17752,13 +17752,13 @@ "type": { "catalog": "", "schema": "", - "name": "_oid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "polqual", @@ -17905,7 +17905,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -17918,20 +17918,20 @@ "type": { "catalog": "", "schema": "", - "name": "_regtype" + "name": "regtype" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "result_types", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -17944,13 +17944,13 @@ "type": { "catalog": "", "schema": "", - "name": "_regtype" + "name": "regtype" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "from_sql", @@ -18833,7 +18833,7 @@ { "name": "proargtypes", "not_null": true, - "is_array": true, + "is_array": false, "comment": "", "length": -1, "is_named_param": false, @@ -18861,7 +18861,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -18874,20 +18874,20 @@ "type": { "catalog": "", "schema": "", - "name": "_oid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "proargmodes", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", @@ -18900,13 +18900,13 @@ "type": { "catalog": "", "schema": "", - "name": "_char" + "name": "char" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "proargnames", @@ -18926,13 +18926,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "proargdefaults", @@ -18965,7 +18965,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -18978,13 +18978,13 @@ "type": { "catalog": "", "schema": "", - "name": "_oid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "prosrc", @@ -19082,20 +19082,20 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "proacl", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 16, "is_named_param": false, "is_func_call": false, "scope": "", @@ -19108,13 +19108,13 @@ "type": { "catalog": "", "schema": "", - "name": "_aclitem" + "name": "aclitem" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -20033,7 +20033,7 @@ { "name": "prattrs", "not_null": false, - "is_array": true, + "is_array": false, "comment": "", "length": -1, "is_named_param": false, @@ -20149,7 +20149,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 64, "is_named_param": false, "is_func_call": false, "scope": "", @@ -20162,13 +20162,13 @@ "type": { "catalog": "", "schema": "", - "name": "_name" + "name": "name" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "rowfilter", @@ -21990,13 +21990,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "oid", @@ -23636,13 +23636,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "boot_val", @@ -24010,13 +24010,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -38715,7 +38715,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -38728,20 +38728,20 @@ "type": { "catalog": "", "schema": "", - "name": "_float4" + "name": "float4" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "stanumbers2", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -38754,20 +38754,20 @@ "type": { "catalog": "", "schema": "", - "name": "_float4" + "name": "float4" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "stanumbers3", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -38780,20 +38780,20 @@ "type": { "catalog": "", "schema": "", - "name": "_float4" + "name": "float4" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "stanumbers4", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -38806,20 +38806,20 @@ "type": { "catalog": "", "schema": "", - "name": "_float4" + "name": "float4" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "stanumbers5", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -38832,13 +38832,13 @@ "type": { "catalog": "", "schema": "", - "name": "_float4" + "name": "float4" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "stavalues1", @@ -39295,7 +39295,7 @@ { "name": "stxkeys", "not_null": true, - "is_array": true, + "is_array": false, "comment": "", "length": -1, "is_named_param": false, @@ -39323,7 +39323,7 @@ "not_null": true, "is_array": true, "comment": "", - "length": -1, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", @@ -39336,13 +39336,13 @@ "type": { "catalog": "", "schema": "", - "name": "_char" + "name": "char" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "stxexprs", @@ -39684,13 +39684,13 @@ "type": { "catalog": "", "schema": "", - "name": "_pg_statistic" + "name": "pg_statistic" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -39915,7 +39915,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -39928,13 +39928,13 @@ "type": { "catalog": "", "schema": "", - "name": "_float4" + "name": "float4" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "histogram_bounds", @@ -40019,7 +40019,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -40032,20 +40032,20 @@ "type": { "catalog": "", "schema": "", - "name": "_float4" + "name": "float4" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "elem_count_histogram", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -40058,13 +40058,13 @@ "type": { "catalog": "", "schema": "", - "name": "_float4" + "name": "float4" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -40211,7 +40211,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 64, "is_named_param": false, "is_func_call": false, "scope": "", @@ -40224,13 +40224,13 @@ "type": { "catalog": "", "schema": "", - "name": "_name" + "name": "name" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "exprs", @@ -40250,20 +40250,20 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "kinds", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", @@ -40276,13 +40276,13 @@ "type": { "catalog": "", "schema": "", - "name": "_char" + "name": "char" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "inherited", @@ -40380,20 +40380,20 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "most_common_val_nulls", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", @@ -40406,20 +40406,20 @@ "type": { "catalog": "", "schema": "", - "name": "_bool" + "name": "bool" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "most_common_freqs", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 8, "is_named_param": false, "is_func_call": false, "scope": "", @@ -40432,20 +40432,20 @@ "type": { "catalog": "", "schema": "", - "name": "_float8" + "name": "float8" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "most_common_base_freqs", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 8, "is_named_param": false, "is_func_call": false, "scope": "", @@ -40458,13 +40458,13 @@ "type": { "catalog": "", "schema": "", - "name": "_float8" + "name": "float8" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -40767,7 +40767,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -40780,13 +40780,13 @@ "type": { "catalog": "", "schema": "", - "name": "_float4" + "name": "float4" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "histogram_bounds", @@ -40871,7 +40871,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -40884,20 +40884,20 @@ "type": { "catalog": "", "schema": "", - "name": "_float4" + "name": "float4" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "elem_count_histogram", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -40910,13 +40910,13 @@ "type": { "catalog": "", "schema": "", - "name": "_float4" + "name": "float4" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -41492,13 +41492,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "suborigin", @@ -42263,7 +42263,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 16, "is_named_param": false, "is_func_call": false, "scope": "", @@ -42276,13 +42276,13 @@ "type": { "catalog": "", "schema": "", - "name": "_aclitem" + "name": "aclitem" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "spcoptions", @@ -42302,13 +42302,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -43341,7 +43341,7 @@ { "name": "tgattr", "not_null": true, - "is_array": true, + "is_array": false, "comment": "", "length": -1, "is_named_param": false, @@ -46003,7 +46003,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 16, "is_named_param": false, "is_func_call": false, "scope": "", @@ -46016,13 +46016,13 @@ "type": { "catalog": "", "schema": "", - "name": "_aclitem" + "name": "aclitem" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -46260,13 +46260,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -46530,13 +46530,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -46696,13 +46696,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -46906,13 +46906,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "foreign_data_wrapper_catalog", @@ -47072,13 +47072,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "foreign_server_catalog", @@ -47368,13 +47368,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -47482,13 +47482,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "foreign_server_catalog", @@ -47622,13 +47622,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "umuser", diff --git a/internal/endtoend/testdata/process_plugin_sqlc_gen_json/gen/codegen.json b/internal/endtoend/testdata/process_plugin_sqlc_gen_json/gen/codegen.json index c4556eebee..4a85e7bd7e 100644 --- a/internal/endtoend/testdata/process_plugin_sqlc_gen_json/gen/codegen.json +++ b/internal/endtoend/testdata/process_plugin_sqlc_gen_json/gen/codegen.json @@ -2871,7 +2871,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 16, "is_named_param": false, "is_func_call": false, "scope": "", @@ -2884,13 +2884,13 @@ "type": { "catalog": "", "schema": "", - "name": "_aclitem" + "name": "aclitem" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "attoptions", @@ -2910,13 +2910,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "attfdwoptions", @@ -2936,13 +2936,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "attmissingval", @@ -3993,7 +3993,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 64, "is_named_param": false, "is_func_call": false, "scope": "", @@ -4006,13 +4006,13 @@ "type": { "catalog": "", "schema": "", - "name": "_name" + "name": "name" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "comment", @@ -5671,7 +5671,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 16, "is_named_param": false, "is_func_call": false, "scope": "", @@ -5684,13 +5684,13 @@ "type": { "catalog": "", "schema": "", - "name": "_aclitem" + "name": "aclitem" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "reloptions", @@ -5710,13 +5710,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "relpartbound", @@ -6923,7 +6923,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 2, "is_named_param": false, "is_func_call": false, "scope": "", @@ -6936,20 +6936,20 @@ "type": { "catalog": "", "schema": "", - "name": "_int2" + "name": "int2" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "confkey", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 2, "is_named_param": false, "is_func_call": false, "scope": "", @@ -6962,20 +6962,20 @@ "type": { "catalog": "", "schema": "", - "name": "_int2" + "name": "int2" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "conpfeqop", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -6988,20 +6988,20 @@ "type": { "catalog": "", "schema": "", - "name": "_oid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "conppeqop", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -7014,20 +7014,20 @@ "type": { "catalog": "", "schema": "", - "name": "_oid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "conffeqop", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -7040,20 +7040,20 @@ "type": { "catalog": "", "schema": "", - "name": "_oid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "confdelsetcols", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 2, "is_named_param": false, "is_func_call": false, "scope": "", @@ -7066,20 +7066,20 @@ "type": { "catalog": "", "schema": "", - "name": "_int2" + "name": "int2" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "conexclop", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -7092,13 +7092,13 @@ "type": { "catalog": "", "schema": "", - "name": "_oid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "conbin", @@ -8253,7 +8253,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 16, "is_named_param": false, "is_func_call": false, "scope": "", @@ -8266,13 +8266,13 @@ "type": { "catalog": "", "schema": "", - "name": "_aclitem" + "name": "aclitem" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -8510,13 +8510,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -8793,7 +8793,7 @@ "not_null": true, "is_array": true, "comment": "", - "length": -1, + "length": 16, "is_named_param": false, "is_func_call": false, "scope": "", @@ -8806,13 +8806,13 @@ "type": { "catalog": "", "schema": "", - "name": "_aclitem" + "name": "aclitem" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -10042,13 +10042,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -10377,7 +10377,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -10390,13 +10390,13 @@ "type": { "catalog": "", "schema": "", - "name": "_oid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "extcondition", @@ -10416,13 +10416,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -10917,7 +10917,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 16, "is_named_param": false, "is_func_call": false, "scope": "", @@ -10930,13 +10930,13 @@ "type": { "catalog": "", "schema": "", - "name": "_aclitem" + "name": "aclitem" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "fdwoptions", @@ -10956,13 +10956,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -11291,7 +11291,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 16, "is_named_param": false, "is_func_call": false, "scope": "", @@ -11304,13 +11304,13 @@ "type": { "catalog": "", "schema": "", - "name": "_aclitem" + "name": "aclitem" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "srvoptions", @@ -11330,13 +11330,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -11574,13 +11574,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -11649,7 +11649,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -11662,13 +11662,13 @@ "type": { "catalog": "", "schema": "", - "name": "_oid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -11802,13 +11802,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "user_name", @@ -11828,13 +11828,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "address", @@ -11932,13 +11932,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "error", @@ -12717,7 +12717,7 @@ { "name": "indkey", "not_null": true, - "is_array": true, + "is_array": false, "comment": "", "length": -1, "is_named_param": false, @@ -12743,7 +12743,7 @@ { "name": "indcollation", "not_null": true, - "is_array": true, + "is_array": false, "comment": "", "length": -1, "is_named_param": false, @@ -12769,7 +12769,7 @@ { "name": "indclass", "not_null": true, - "is_array": true, + "is_array": false, "comment": "", "length": -1, "is_named_param": false, @@ -12795,7 +12795,7 @@ { "name": "indoption", "not_null": true, - "is_array": true, + "is_array": false, "comment": "", "length": -1, "is_named_param": false, @@ -13555,7 +13555,7 @@ "not_null": true, "is_array": true, "comment": "", - "length": -1, + "length": 16, "is_named_param": false, "is_func_call": false, "scope": "", @@ -13568,13 +13568,13 @@ "type": { "catalog": "", "schema": "", - "name": "_aclitem" + "name": "aclitem" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -13955,7 +13955,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 16, "is_named_param": false, "is_func_call": false, "scope": "", @@ -13968,13 +13968,13 @@ "type": { "catalog": "", "schema": "", - "name": "_aclitem" + "name": "aclitem" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -14443,7 +14443,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 16, "is_named_param": false, "is_func_call": false, "scope": "", @@ -14456,13 +14456,13 @@ "type": { "catalog": "", "schema": "", - "name": "_aclitem" + "name": "aclitem" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -15331,7 +15331,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 16, "is_named_param": false, "is_func_call": false, "scope": "", @@ -15344,13 +15344,13 @@ "type": { "catalog": "", "schema": "", - "name": "_aclitem" + "name": "aclitem" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -16827,7 +16827,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 16, "is_named_param": false, "is_func_call": false, "scope": "", @@ -16840,13 +16840,13 @@ "type": { "catalog": "", "schema": "", - "name": "_aclitem" + "name": "aclitem" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -17121,7 +17121,7 @@ { "name": "partattrs", "not_null": true, - "is_array": true, + "is_array": false, "comment": "", "length": -1, "is_named_param": false, @@ -17147,7 +17147,7 @@ { "name": "partclass", "not_null": true, - "is_array": true, + "is_array": false, "comment": "", "length": -1, "is_named_param": false, @@ -17173,7 +17173,7 @@ { "name": "partcollation", "not_null": true, - "is_array": true, + "is_array": false, "comment": "", "length": -1, "is_named_param": false, @@ -17341,7 +17341,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 64, "is_named_param": false, "is_func_call": false, "scope": "", @@ -17354,13 +17354,13 @@ "type": { "catalog": "", "schema": "", - "name": "_name" + "name": "name" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "cmd", @@ -17741,7 +17741,7 @@ "not_null": true, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -17754,13 +17754,13 @@ "type": { "catalog": "", "schema": "", - "name": "_oid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "polqual", @@ -17907,7 +17907,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -17920,20 +17920,20 @@ "type": { "catalog": "", "schema": "", - "name": "_regtype" + "name": "regtype" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "result_types", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -17946,13 +17946,13 @@ "type": { "catalog": "", "schema": "", - "name": "_regtype" + "name": "regtype" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "from_sql", @@ -18835,7 +18835,7 @@ { "name": "proargtypes", "not_null": true, - "is_array": true, + "is_array": false, "comment": "", "length": -1, "is_named_param": false, @@ -18863,7 +18863,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -18876,20 +18876,20 @@ "type": { "catalog": "", "schema": "", - "name": "_oid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "proargmodes", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", @@ -18902,13 +18902,13 @@ "type": { "catalog": "", "schema": "", - "name": "_char" + "name": "char" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "proargnames", @@ -18928,13 +18928,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "proargdefaults", @@ -18967,7 +18967,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -18980,13 +18980,13 @@ "type": { "catalog": "", "schema": "", - "name": "_oid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "prosrc", @@ -19084,20 +19084,20 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "proacl", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 16, "is_named_param": false, "is_func_call": false, "scope": "", @@ -19110,13 +19110,13 @@ "type": { "catalog": "", "schema": "", - "name": "_aclitem" + "name": "aclitem" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -20035,7 +20035,7 @@ { "name": "prattrs", "not_null": false, - "is_array": true, + "is_array": false, "comment": "", "length": -1, "is_named_param": false, @@ -20151,7 +20151,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 64, "is_named_param": false, "is_func_call": false, "scope": "", @@ -20164,13 +20164,13 @@ "type": { "catalog": "", "schema": "", - "name": "_name" + "name": "name" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "rowfilter", @@ -21992,13 +21992,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "oid", @@ -23638,13 +23638,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "boot_val", @@ -24012,13 +24012,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -38717,7 +38717,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -38730,20 +38730,20 @@ "type": { "catalog": "", "schema": "", - "name": "_float4" + "name": "float4" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "stanumbers2", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -38756,20 +38756,20 @@ "type": { "catalog": "", "schema": "", - "name": "_float4" + "name": "float4" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "stanumbers3", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -38782,20 +38782,20 @@ "type": { "catalog": "", "schema": "", - "name": "_float4" + "name": "float4" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "stanumbers4", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -38808,20 +38808,20 @@ "type": { "catalog": "", "schema": "", - "name": "_float4" + "name": "float4" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "stanumbers5", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -38834,13 +38834,13 @@ "type": { "catalog": "", "schema": "", - "name": "_float4" + "name": "float4" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "stavalues1", @@ -39297,7 +39297,7 @@ { "name": "stxkeys", "not_null": true, - "is_array": true, + "is_array": false, "comment": "", "length": -1, "is_named_param": false, @@ -39325,7 +39325,7 @@ "not_null": true, "is_array": true, "comment": "", - "length": -1, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", @@ -39338,13 +39338,13 @@ "type": { "catalog": "", "schema": "", - "name": "_char" + "name": "char" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "stxexprs", @@ -39686,13 +39686,13 @@ "type": { "catalog": "", "schema": "", - "name": "_pg_statistic" + "name": "pg_statistic" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -39917,7 +39917,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -39930,13 +39930,13 @@ "type": { "catalog": "", "schema": "", - "name": "_float4" + "name": "float4" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "histogram_bounds", @@ -40021,7 +40021,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -40034,20 +40034,20 @@ "type": { "catalog": "", "schema": "", - "name": "_float4" + "name": "float4" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "elem_count_histogram", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -40060,13 +40060,13 @@ "type": { "catalog": "", "schema": "", - "name": "_float4" + "name": "float4" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -40213,7 +40213,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 64, "is_named_param": false, "is_func_call": false, "scope": "", @@ -40226,13 +40226,13 @@ "type": { "catalog": "", "schema": "", - "name": "_name" + "name": "name" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "exprs", @@ -40252,20 +40252,20 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "kinds", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", @@ -40278,13 +40278,13 @@ "type": { "catalog": "", "schema": "", - "name": "_char" + "name": "char" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "inherited", @@ -40382,20 +40382,20 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "most_common_val_nulls", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", @@ -40408,20 +40408,20 @@ "type": { "catalog": "", "schema": "", - "name": "_bool" + "name": "bool" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "most_common_freqs", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 8, "is_named_param": false, "is_func_call": false, "scope": "", @@ -40434,20 +40434,20 @@ "type": { "catalog": "", "schema": "", - "name": "_float8" + "name": "float8" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "most_common_base_freqs", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 8, "is_named_param": false, "is_func_call": false, "scope": "", @@ -40460,13 +40460,13 @@ "type": { "catalog": "", "schema": "", - "name": "_float8" + "name": "float8" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -40769,7 +40769,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -40782,13 +40782,13 @@ "type": { "catalog": "", "schema": "", - "name": "_float4" + "name": "float4" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "histogram_bounds", @@ -40873,7 +40873,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -40886,20 +40886,20 @@ "type": { "catalog": "", "schema": "", - "name": "_float4" + "name": "float4" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "elem_count_histogram", "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -40912,13 +40912,13 @@ "type": { "catalog": "", "schema": "", - "name": "_float4" + "name": "float4" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -41494,13 +41494,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "suborigin", @@ -42265,7 +42265,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 16, "is_named_param": false, "is_func_call": false, "scope": "", @@ -42278,13 +42278,13 @@ "type": { "catalog": "", "schema": "", - "name": "_aclitem" + "name": "aclitem" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "spcoptions", @@ -42304,13 +42304,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -43343,7 +43343,7 @@ { "name": "tgattr", "not_null": true, - "is_array": true, + "is_array": false, "comment": "", "length": -1, "is_named_param": false, @@ -46005,7 +46005,7 @@ "not_null": false, "is_array": true, "comment": "", - "length": -1, + "length": 16, "is_named_param": false, "is_func_call": false, "scope": "", @@ -46018,13 +46018,13 @@ "type": { "catalog": "", "schema": "", - "name": "_aclitem" + "name": "aclitem" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -46262,13 +46262,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -46532,13 +46532,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -46698,13 +46698,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -46908,13 +46908,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "foreign_data_wrapper_catalog", @@ -47074,13 +47074,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "foreign_server_catalog", @@ -47370,13 +47370,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 } ], "comment": "" @@ -47484,13 +47484,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "foreign_server_catalog", @@ -47624,13 +47624,13 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, - "array_dims": 0 + "array_dims": 1 }, { "name": "umuser", diff --git a/internal/engine/clickhouse/convert.go b/internal/engine/clickhouse/convert.go index de2a1419bf..f1505c0687 100644 --- a/internal/engine/clickhouse/convert.go +++ b/internal/engine/clickhouse/convert.go @@ -2,6 +2,7 @@ package clickhouse import ( "fmt" + "sort" "strconv" "strings" @@ -691,15 +692,23 @@ func (c *cc) convertFunctionCall(n *chast.FunctionCall) *ast.FuncCall { func (c *cc) convertParameter(n *chast.Parameter) ast.Node { c.paramCount++ - // Use the parameter name if available - name := n.Name - if name == "" { - name = strconv.Itoa(c.paramCount) - } - return &ast.ParamRef{ + ref := &ast.ParamRef{ Number: c.paramCount, + Name: n.Name, Location: pos(n), } + // A parameter written {name:Type} declares its type, which is what a + // cast of a placeholder says. + if n.Type != nil { + spelling := renderDataType(n.Type) + base, _, _ := unwrapTypeString(spelling) + return &ast.TypeCast{ + Arg: ref, + TypeName: &ast.TypeName{Name: base, Spelling: spelling, Canonical: canonicalDataType(n.Type)}, + Location: pos(n), + } + } + return ref } func (c *cc) convertAsterisk(n *chast.Asterisk) *ast.ColumnRef { @@ -751,9 +760,11 @@ func (c *cc) convertCastExpr(n *chast.CastExpr) *ast.TypeCast { } if n.Type != nil { - tc.TypeName = &ast.TypeName{ - Name: n.Type.Name, - } + // The whole type is handed over as its spelling, arguments and + // nesting included, the way a column's is. + spelling := renderDataType(n.Type) + base, _, _ := unwrapTypeString(spelling) + tc.TypeName = &ast.TypeName{Name: base, Spelling: spelling, Canonical: canonicalDataType(n.Type)} } return tc @@ -965,8 +976,13 @@ func (c *cc) convertCreateQuery(n *chast.CreateQuery) ast.Node { stmt.Name.Schema = identifier(n.Database) } - // Convert columns + // Convert columns. A Nested column is what ClickHouse stores as + // one array column per element, named n.a, and reports as those. for _, col := range n.Columns { + if cols, ok := c.convertNestedColumn(col); ok { + stmt.Cols = append(stmt.Cols, cols...) + continue + } colDef := c.convertColumnDeclaration(col) stmt.Cols = append(stmt.Cols, colDef) } @@ -994,6 +1010,30 @@ func (c *cc) convertCreateQuery(n *chast.CreateQuery) ast.Node { return &ast.TODO{} } +// convertNestedColumn expands a column declared Nested(a T, b U) into the +// columns n.a Array(T) and n.b Array(U), which is how ClickHouse's +// system.columns lists it and what a query selects. +func (c *cc) convertNestedColumn(n *chast.ColumnDeclaration) ([]*ast.ColumnDef, bool) { + if n.Type == nil || !strings.EqualFold(n.Type.Name, "Nested") { + return nil, false + } + var cols []*ast.ColumnDef + for _, p := range n.Type.Parameters { + pair, ok := p.(*chast.NameTypePair) + if !ok { + continue + } + spelling := "Array(" + renderDataType(pair.Type) + ")" + cols = append(cols, &ast.ColumnDef{ + Colname: identifier(n.Name) + "." + identifier(pair.Name), + TypeName: &ast.TypeName{Name: "array", Spelling: spelling, Canonical: "Array(" + canonicalDataType(pair.Type) + ")"}, + IsArray: true, + IsNotNull: true, + }) + } + return cols, len(cols) > 0 +} + func (c *cc) convertColumnDeclaration(n *chast.ColumnDeclaration) *ast.ColumnDef { colDef := &ast.ColumnDef{ Colname: identifier(n.Name), @@ -1005,7 +1045,7 @@ func (c *cc) convertColumnDeclaration(n *chast.ColumnDeclaration) *ast.ColumnDef base, isArray, nullable := unwrapTypeString(spelling) // The catalog resolves the base type; the full spelling, with its // arguments and nesting, is kept for the analysis to report. - colDef.TypeName = &ast.TypeName{Name: base, Spelling: spelling} + colDef.TypeName = &ast.TypeName{Name: base, Spelling: spelling, Canonical: canonicalDataType(n.Type)} colDef.IsArray = isArray if nullable { colDef.IsNotNull = false @@ -1030,24 +1070,86 @@ func (c *cc) convertColumnDeclaration(n *chast.ColumnDeclaration) *ast.ColumnDef return colDef } +// renderDataType spells a type as the author wrote it, which the formatter +// prints back. func renderDataType(dt *chast.DataType) string { + return renderType(dt, false) +} + +// canonicalDataType spells a type the way ClickHouse stores it, which the +// analysis core reads: an Enum's members are numbered and the family +// sized by their count, a Variant's members are sorted, and a named +// element is written label first, so that Enum('a', 'b') is Enum8('a' = +// 1, 'b' = 2), Variant(String, Int64) is Variant(Int64, String) and +// Tuple(lat Float64) is Tuple(lat: Float64). +func canonicalDataType(dt *chast.DataType) string { + return renderType(dt, true) +} + +func renderType(dt *chast.DataType, canonical bool) string { if dt == nil { return "" } if len(dt.Parameters) == 0 { return dt.Name } + name := dt.Name parts := make([]string, 0, len(dt.Parameters)) - for _, p := range dt.Parameters { - parts = append(parts, renderTypeParam(p)) + switch lower := strings.ToLower(name); { + case canonical && (lower == "enum" || lower == "enum8" || lower == "enum16"): + if lower == "enum" { + name = "Enum8" + if len(dt.Parameters) > 127 { + name = "Enum16" + } + } + next := int64(1) + for _, p := range dt.Parameters { + switch v := p.(type) { + case *chast.BinaryExpr: + // 'a' = 3 numbers itself, and the next bare member follows it. + parts = append(parts, renderParam(v, canonical)) + if lit, ok := v.Right.(*chast.Literal); ok { + if n, err := strconv.ParseInt(fmt.Sprint(lit.Value), 10, 64); err == nil { + next = n + 1 + } + } + default: + parts = append(parts, renderParam(p, canonical)+" = "+strconv.FormatInt(next, 10)) + next++ + } + } + case canonical && lower == "lowcardinality" && len(dt.Parameters) == 1: + // ClickHouse spells a nullable low-cardinality column as + // LowCardinality(Nullable(T)), the only order it accepts. The + // nullability is the column's, so the canonical form is + // Nullable(LowCardinality(T)), which reads as a nullable + // LowCardinality(T). + if inner, ok := dt.Parameters[0].(*chast.DataType); ok && strings.EqualFold(inner.Name, "nullable") && len(inner.Parameters) == 1 { + return "Nullable(LowCardinality(" + renderParam(inner.Parameters[0], canonical) + "))" + } + parts = append(parts, renderParam(dt.Parameters[0], canonical)) + case canonical && lower == "variant": + for _, p := range dt.Parameters { + parts = append(parts, renderParam(p, canonical)) + } + sort.Strings(parts) + default: + for _, p := range dt.Parameters { + parts = append(parts, renderParam(p, canonical)) + } } - return dt.Name + "(" + strings.Join(parts, ", ") + ")" + return name + "(" + strings.Join(parts, ", ") + ")" } func renderTypeParam(e chast.Expression) string { + return renderParam(e, false) +} + +func renderParam(e chast.Expression, canonical bool) string { switch v := e.(type) { case *chast.DataType: - return renderDataType(v) + return renderType(v, canonical) case *chast.Literal: if v.Type == chast.LiteralString { return quoteString(fmt.Sprint(v.Value)) @@ -1059,11 +1161,15 @@ func renderTypeParam(e chast.Expression) string { case *chast.Identifier: return strings.Join(v.Parts, ".") case *chast.NameTypePair: - // A named tuple or nested element: `lat Float64`. - return v.Name + " " + renderDataType(v.Type) + // A named tuple or nested element: `lat Float64`, or `lat: Float64` + // in the canonical form. + if canonical { + return v.Name + ": " + renderType(v.Type, canonical) + } + return v.Name + " " + renderType(v.Type, canonical) case *chast.BinaryExpr: // An enum member: `'active' = 1`. - return renderTypeParam(v.Left) + " " + v.Op + " " + renderTypeParam(v.Right) + return renderParam(v.Left, canonical) + " " + v.Op + " " + renderParam(v.Right, canonical) default: return "" } @@ -1079,14 +1185,16 @@ func unwrapTypeString(s string) (name string, isArray, nullable bool) { } return strings.ToLower(base), false, true case "lowcardinality": + // LowCardinality is an encoding of the type it wraps, and a + // column of LowCardinality(Nullable(String)) holds NULLs. if len(args) == 1 { return unwrapTypeString(args[0]) } return strings.ToLower(base), false, false case "array": if len(args) == 1 { - inner, _, nul := unwrapTypeString(args[0]) - return inner, true, nul + inner, _, _ := unwrapTypeString(args[0]) + return inner, true, false } return strings.ToLower(base), true, false default: diff --git a/internal/engine/clickhouse/dialect/dialect.json b/internal/engine/clickhouse/dialect/dialect.json index fa7f2c5c73..51cb0b641a 100644 --- a/internal/engine/clickhouse/dialect/dialect.json +++ b/internal/engine/clickhouse/dialect/dialect.json @@ -1,5 +1,6 @@ { "dialect": "clickhouse", + "default_schema": "default", "const": { "integer": "Int64", "float": "Float64", @@ -14,5 +15,27 @@ "comparison": ["=", "==", "<>", "!=", "<", "<=", ">", ">="], "comparison_categories": "NBSDU", "arithmetic": ["+", "-", "*", "/", "%"], - "arithmetic_categories": "N" + "arithmetic_categories": "N", + "rewrites": [ + { + "from": "Decimal32($1)", + "to": "Decimal(9, $1)" + }, + { + "from": "Decimal64($1)", + "to": "Decimal(18, $1)" + }, + { + "from": "Decimal128($1)", + "to": "Decimal(38, $1)" + }, + { + "from": "Decimal256($1)", + "to": "Decimal(76, $1)" + } + ], + "ident_args": { + "AggregateFunction": [1], + "SimpleAggregateFunction": [1] + } } diff --git a/internal/engine/clickhouse/dialect/functions.jsonl b/internal/engine/clickhouse/dialect/functions.jsonl index 20898b8c9d..c0ca1406c1 100644 --- a/internal/engine/clickhouse/dialect/functions.jsonl +++ b/internal/engine/clickhouse/dialect/functions.jsonl @@ -352,12 +352,12 @@ {"name": "toString", "args": [{"type": "any"}], "returns": "String"} {"name": "toDateTime", "args": [{"type": "any"}, {"type": "any"}], "returns": "DateTime"} {"name": "toDate", "args": [{"type": "any"}, {"type": "any"}], "returns": "Date"} -{"name": "toDateTime64", "args": [{"type": "any"}, {"type": "any"}], "returns": "DateTime64"} -{"name": "toDateTime64", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "DateTime64"} -{"name": "toDecimal32", "args": [{"type": "any"}, {"type": "any"}], "returns": "Decimal32"} -{"name": "toDecimal64", "args": [{"type": "any"}, {"type": "any"}], "returns": "Decimal64"} -{"name": "toDecimal128", "args": [{"type": "any"}, {"type": "any"}], "returns": "Decimal128"} -{"name": "toDecimal256", "args": [{"type": "any"}, {"type": "any"}], "returns": "Decimal256"} +{"name": "toDateTime64", "args": [{"type": "any"}, {"type": "any"}], "returns": "DateTime64($2)"} +{"name": "toDateTime64", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "DateTime64($2, $3)"} +{"name": "toDecimal32", "args": [{"type": "any"}, {"type": "any"}], "returns": "Decimal(9, $2)"} +{"name": "toDecimal64", "args": [{"type": "any"}, {"type": "any"}], "returns": "Decimal(18, $2)"} +{"name": "toDecimal128", "args": [{"type": "any"}, {"type": "any"}], "returns": "Decimal(38, $2)"} +{"name": "toDecimal256", "args": [{"type": "any"}, {"type": "any"}], "returns": "Decimal(76, $2)"} {"name": "toFixedString", "args": [{"type": "any"}, {"type": "any"}], "returns": "FixedString"} {"name": "toStringCutToZero", "args": [{"type": "any"}], "returns": "String"} {"name": "reinterpretAsString", "args": [{"type": "any"}], "returns": "String"} diff --git a/internal/engine/dolphin/convert.go b/internal/engine/dolphin/convert.go index c52fb7e2ef..4a01a68de6 100644 --- a/internal/engine/dolphin/convert.go +++ b/internal/engine/dolphin/convert.go @@ -317,6 +317,24 @@ func convertColumnDef(def *pcast.ColumnDef) *ast.ColumnDef { } typeName.Typmods = &ast.List{Items: mods} } + // MySQL drops an integer's display width except the one that means + // something: tinyint(1) is what drivers and codegen read as a boolean, + // and BOOLEAN itself is spelled that way. + case mysql.TypeTiny: + if flen == 1 { + typeName.Typmods = &ast.List{Items: []ast.Node{&ast.Integer{Ival: 1}}} + } + // A bit column's width is part of its type, and is 1 when left out. + case mysql.TypeBit: + if flen >= 0 { + typeName.Typmods = &ast.List{Items: []ast.Node{&ast.Integer{Ival: int64(flen)}}} + } + // A fractional-seconds precision is part of the type; zero is the + // default and is not written. + case mysql.TypeDatetime, mysql.TypeTimestamp, mysql.TypeDuration: + if fsp := def.Tp.GetDecimal(); fsp > 0 { + typeName.Typmods = &ast.List{Items: []ast.Node{&ast.Integer{Ival: int64(fsp)}}} + } } columnDef := ast.ColumnDef{ @@ -1112,7 +1130,8 @@ func (c *cc) convertFrameClause(n *pcast.FrameClause) ast.Node { } func (c *cc) convertFuncCastExpr(n *pcast.FuncCastExpr) ast.Node { - typeName := types.TypeStr(n.Tp.GetType()) + tp := n.Tp.GetType() + typeName := types.TypeToStr(tp, n.Tp.GetCharset()) // MySQL CAST AS UNSIGNED/SIGNED uses bigint internally. // We need to preserve the signed/unsigned info for formatting. @@ -1123,10 +1142,50 @@ func (c *cc) convertFuncCastExpr(n *pcast.FuncCastExpr) ast.Node { typeName = "bigint signed" } } + // CAST(x AS CHAR) and CAST(x AS BINARY) are typed by the parser as the + // wire's var_string, which is no SQL type, or as a char or binary. + // MySQL types the result as a varchar or a varbinary — its metadata + // and a view over it both say so. + switch typeName { + case "var_string", "char": + typeName = "varchar" + if n.Tp.GetCharset() == "binary" { + typeName = "varbinary" + } + case "binary": + typeName = "varbinary" + } + + out := &ast.TypeName{Name: typeName} + flen, dec := n.Tp.GetFlen(), n.Tp.GetDecimal() + switch tp { + case mysql.TypeNewDecimal: + // A decimal's precision and scale are part of its type, and a + // scale left out is 0: CAST(x AS DECIMAL(5)) is a decimal(5,0). + if flen >= 0 && flen != types.UnspecifiedLength { + mods := []ast.Node{&ast.Integer{Ival: int64(flen)}} + if dec >= 0 && dec != types.UnspecifiedLength { + mods = append(mods, &ast.Integer{Ival: int64(dec)}) + } + out.Typmods = &ast.List{Items: mods} + } + case mysql.TypeFloat, mysql.TypeDouble: + // The parser fills in a display width for a float or double, and + // a precision written as FLOAT(p) only picks between the two; the + // result is a plain float or double. + case mysql.TypeVarchar, mysql.TypeVarString, mysql.TypeString: + if flen > 0 && flen != types.UnspecifiedLength { + out.Typmods = &ast.List{Items: []ast.Node{&ast.Integer{Ival: int64(flen)}}} + } + case mysql.TypeDatetime, mysql.TypeTimestamp, mysql.TypeDuration: + if dec > 0 && dec != types.UnspecifiedLength { + out.Typmods = &ast.List{Items: []ast.Node{&ast.Integer{Ival: int64(dec)}}} + } + } return &ast.TypeCast{ Arg: c.convert(n.Expr), - TypeName: &ast.TypeName{Name: typeName}, + TypeName: out, } } diff --git a/internal/engine/dolphin/dialect/dialect.json b/internal/engine/dolphin/dialect/dialect.json index f48ee7183d..ce503b4960 100644 --- a/internal/engine/dolphin/dialect/dialect.json +++ b/internal/engine/dolphin/dialect/dialect.json @@ -11,5 +11,40 @@ "comparison_categories": "BNSDU", "arithmetic": ["+", "-", "*", "/", "%", "DIV"], "arithmetic_categories": "N", - "cast_categories": "NSD" + "cast_categories": "NSD", + "rewrites": [ + { + "from": "boolean", + "to": "tinyint(1)" + }, + { + "from": "bool", + "to": "tinyint(1)" + }, + { + "from": "decimal", + "to": "decimal(10, 0)" + }, + { + "from": "decimal($1)", + "to": "decimal($1, 0)" + }, + { + "from": "decimal unsigned", + "to": "decimal unsigned(10, 0)" + }, + { + "from": "decimal unsigned($1)", + "to": "decimal unsigned($1, 0)" + }, + { + "from": "float($1)", + "to": "float", + "where": "$1 <= 24" + }, + { + "from": "float($1)", + "to": "double" + } + ] } diff --git a/internal/engine/dolphin/dialect/relations.jsonl b/internal/engine/dolphin/dialect/relations.jsonl index ea3c86953f..0660804f9c 100644 --- a/internal/engine/dolphin/dialect/relations.jsonl +++ b/internal/engine/dolphin/dialect/relations.jsonl @@ -1,84 +1,84 @@ -{"catalog":"def","schema":"information_schema","name":"administrable_role_authorizations","kind":"v","columns":[{"name":"user","type":"varchar"},{"name":"host","type":"varchar"},{"name":"grantee","type":"varchar"},{"name":"grantee_host","type":"varchar"},{"name":"role_name","type":"varchar"},{"name":"role_host","type":"varchar"},{"name":"is_grantable","type":"varchar","not_null":true},{"name":"is_default","type":"varchar"},{"name":"is_mandatory","type":"varchar","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"applicable_roles","kind":"v","columns":[{"name":"user","type":"varchar"},{"name":"host","type":"varchar"},{"name":"grantee","type":"varchar"},{"name":"grantee_host","type":"varchar"},{"name":"role_name","type":"varchar"},{"name":"role_host","type":"varchar"},{"name":"is_grantable","type":"varchar","not_null":true},{"name":"is_default","type":"varchar"},{"name":"is_mandatory","type":"varchar","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"character_sets","kind":"v","columns":[{"name":"character_set_name","type":"varchar","not_null":true},{"name":"default_collate_name","type":"varchar","not_null":true},{"name":"description","type":"varchar","not_null":true},{"name":"maxlen","type":"int unsigned","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"check_constraints","kind":"v","columns":[{"name":"constraint_catalog","type":"varchar","not_null":true},{"name":"constraint_schema","type":"varchar","not_null":true},{"name":"constraint_name","type":"varchar","not_null":true},{"name":"check_clause","type":"longtext","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"collations","kind":"v","columns":[{"name":"collation_name","type":"varchar","not_null":true},{"name":"character_set_name","type":"varchar","not_null":true},{"name":"id","type":"bigint unsigned","not_null":true},{"name":"is_default","type":"varchar","not_null":true},{"name":"is_compiled","type":"varchar","not_null":true},{"name":"sortlen","type":"int unsigned","not_null":true},{"name":"pad_attribute","type":"enum","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"collation_character_set_applicability","kind":"v","columns":[{"name":"collation_name","type":"varchar","not_null":true},{"name":"character_set_name","type":"varchar","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"columns","kind":"v","columns":[{"name":"table_catalog","type":"varchar","not_null":true},{"name":"table_schema","type":"varchar","not_null":true},{"name":"table_name","type":"varchar","not_null":true},{"name":"column_name","type":"varchar"},{"name":"ordinal_position","type":"int unsigned","not_null":true},{"name":"column_default","type":"text"},{"name":"is_nullable","type":"varchar","not_null":true},{"name":"data_type","type":"longtext"},{"name":"character_maximum_length","type":"bigint"},{"name":"character_octet_length","type":"bigint"},{"name":"numeric_precision","type":"bigint unsigned"},{"name":"numeric_scale","type":"bigint unsigned"},{"name":"datetime_precision","type":"int unsigned"},{"name":"character_set_name","type":"varchar"},{"name":"collation_name","type":"varchar"},{"name":"column_type","type":"mediumtext","not_null":true},{"name":"column_key","type":"enum","not_null":true},{"name":"extra","type":"varchar"},{"name":"privileges","type":"varchar"},{"name":"column_comment","type":"text","not_null":true},{"name":"generation_expression","type":"longtext","not_null":true},{"name":"srs_id","type":"int unsigned"}]} -{"catalog":"def","schema":"information_schema","name":"columns_extensions","kind":"v","columns":[{"name":"table_catalog","type":"varchar","not_null":true},{"name":"table_schema","type":"varchar","not_null":true},{"name":"table_name","type":"varchar","not_null":true},{"name":"column_name","type":"varchar"},{"name":"engine_attribute","type":"json"},{"name":"secondary_engine_attribute","type":"json"}]} -{"catalog":"def","schema":"information_schema","name":"column_privileges","kind":"v","columns":[{"name":"grantee","type":"varchar","not_null":true},{"name":"table_catalog","type":"varchar","not_null":true},{"name":"table_schema","type":"varchar","not_null":true},{"name":"table_name","type":"varchar","not_null":true},{"name":"column_name","type":"varchar","not_null":true},{"name":"privilege_type","type":"varchar","not_null":true},{"name":"is_grantable","type":"varchar","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"column_statistics","kind":"v","columns":[{"name":"schema_name","type":"varchar","not_null":true},{"name":"table_name","type":"varchar","not_null":true},{"name":"column_name","type":"varchar","not_null":true},{"name":"histogram","type":"json","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"enabled_roles","kind":"v","columns":[{"name":"role_name","type":"varchar"},{"name":"role_host","type":"varchar"},{"name":"is_default","type":"varchar"},{"name":"is_mandatory","type":"varchar","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"engines","kind":"v","columns":[{"name":"engine","type":"varchar","not_null":true},{"name":"support","type":"varchar","not_null":true},{"name":"comment","type":"varchar","not_null":true},{"name":"transactions","type":"varchar"},{"name":"xa","type":"varchar"},{"name":"savepoints","type":"varchar"}]} -{"catalog":"def","schema":"information_schema","name":"events","kind":"v","columns":[{"name":"event_catalog","type":"varchar","not_null":true},{"name":"event_schema","type":"varchar","not_null":true},{"name":"event_name","type":"varchar","not_null":true},{"name":"definer","type":"varchar","not_null":true},{"name":"time_zone","type":"varchar","not_null":true},{"name":"event_body","type":"varchar","not_null":true},{"name":"event_definition","type":"longtext","not_null":true},{"name":"event_type","type":"varchar","not_null":true},{"name":"execute_at","type":"datetime"},{"name":"interval_value","type":"varchar"},{"name":"interval_field","type":"enum"},{"name":"sql_mode","type":"set","not_null":true},{"name":"starts","type":"datetime"},{"name":"ends","type":"datetime"},{"name":"status","type":"varchar","not_null":true},{"name":"on_completion","type":"varchar","not_null":true},{"name":"created","type":"timestamp","not_null":true},{"name":"last_altered","type":"timestamp","not_null":true},{"name":"last_executed","type":"datetime"},{"name":"event_comment","type":"varchar","not_null":true},{"name":"originator","type":"int unsigned","not_null":true},{"name":"character_set_client","type":"varchar","not_null":true},{"name":"collation_connection","type":"varchar","not_null":true},{"name":"database_collation","type":"varchar","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"files","kind":"v","columns":[{"name":"file_id","type":"bigint"},{"name":"file_name","type":"text"},{"name":"file_type","type":"varchar"},{"name":"tablespace_name","type":"varchar","not_null":true},{"name":"table_catalog","type":"varchar","not_null":true},{"name":"table_schema","type":"varbinary"},{"name":"table_name","type":"varbinary"},{"name":"logfile_group_name","type":"varchar"},{"name":"logfile_group_number","type":"bigint"},{"name":"engine","type":"varchar","not_null":true},{"name":"fulltext_keys","type":"varbinary"},{"name":"deleted_rows","type":"varbinary"},{"name":"update_count","type":"varbinary"},{"name":"free_extents","type":"bigint"},{"name":"total_extents","type":"bigint"},{"name":"extent_size","type":"bigint"},{"name":"initial_size","type":"bigint"},{"name":"maximum_size","type":"bigint"},{"name":"autoextend_size","type":"bigint"},{"name":"creation_time","type":"varbinary"},{"name":"last_update_time","type":"varbinary"},{"name":"last_access_time","type":"varbinary"},{"name":"recover_time","type":"varbinary"},{"name":"transaction_counter","type":"varbinary"},{"name":"version","type":"bigint"},{"name":"row_format","type":"varchar"},{"name":"table_rows","type":"varbinary"},{"name":"avg_row_length","type":"varbinary"},{"name":"data_length","type":"varbinary"},{"name":"max_data_length","type":"varbinary"},{"name":"index_length","type":"varbinary"},{"name":"data_free","type":"bigint"},{"name":"create_time","type":"varbinary"},{"name":"update_time","type":"varbinary"},{"name":"check_time","type":"varbinary"},{"name":"checksum","type":"varbinary"},{"name":"status","type":"varchar"},{"name":"extra","type":"varchar"}]} -{"catalog":"def","schema":"information_schema","name":"innodb_buffer_page","kind":"v","columns":[{"name":"pool_id","type":"bigint unsigned","not_null":true},{"name":"block_id","type":"bigint unsigned","not_null":true},{"name":"space","type":"bigint unsigned","not_null":true},{"name":"page_number","type":"bigint unsigned","not_null":true},{"name":"page_type","type":"varchar"},{"name":"flush_type","type":"bigint unsigned","not_null":true},{"name":"fix_count","type":"bigint unsigned","not_null":true},{"name":"is_hashed","type":"varchar"},{"name":"newest_modification","type":"bigint unsigned","not_null":true},{"name":"oldest_modification","type":"bigint unsigned","not_null":true},{"name":"access_time","type":"bigint unsigned","not_null":true},{"name":"table_name","type":"varchar"},{"name":"index_name","type":"varchar"},{"name":"number_records","type":"bigint unsigned","not_null":true},{"name":"data_size","type":"bigint unsigned","not_null":true},{"name":"compressed_size","type":"bigint unsigned","not_null":true},{"name":"page_state","type":"varchar"},{"name":"io_fix","type":"varchar"},{"name":"is_old","type":"varchar"},{"name":"free_page_clock","type":"bigint unsigned","not_null":true},{"name":"is_stale","type":"varchar"}]} -{"catalog":"def","schema":"information_schema","name":"innodb_buffer_page_lru","kind":"v","columns":[{"name":"pool_id","type":"bigint unsigned","not_null":true},{"name":"lru_position","type":"bigint unsigned","not_null":true},{"name":"space","type":"bigint unsigned","not_null":true},{"name":"page_number","type":"bigint unsigned","not_null":true},{"name":"page_type","type":"varchar"},{"name":"flush_type","type":"bigint unsigned","not_null":true},{"name":"fix_count","type":"bigint unsigned","not_null":true},{"name":"is_hashed","type":"varchar"},{"name":"newest_modification","type":"bigint unsigned","not_null":true},{"name":"oldest_modification","type":"bigint unsigned","not_null":true},{"name":"access_time","type":"bigint unsigned","not_null":true},{"name":"table_name","type":"varchar"},{"name":"index_name","type":"varchar"},{"name":"number_records","type":"bigint unsigned","not_null":true},{"name":"data_size","type":"bigint unsigned","not_null":true},{"name":"compressed_size","type":"bigint unsigned","not_null":true},{"name":"compressed","type":"varchar"},{"name":"io_fix","type":"varchar"},{"name":"is_old","type":"varchar"},{"name":"free_page_clock","type":"bigint unsigned","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"innodb_buffer_pool_stats","kind":"v","columns":[{"name":"pool_id","type":"bigint unsigned","not_null":true},{"name":"pool_size","type":"bigint unsigned","not_null":true},{"name":"free_buffers","type":"bigint unsigned","not_null":true},{"name":"database_pages","type":"bigint unsigned","not_null":true},{"name":"old_database_pages","type":"bigint unsigned","not_null":true},{"name":"modified_database_pages","type":"bigint unsigned","not_null":true},{"name":"pending_decompress","type":"bigint unsigned","not_null":true},{"name":"pending_reads","type":"bigint unsigned","not_null":true},{"name":"pending_flush_lru","type":"bigint unsigned","not_null":true},{"name":"pending_flush_list","type":"bigint unsigned","not_null":true},{"name":"pages_made_young","type":"bigint unsigned","not_null":true},{"name":"pages_not_made_young","type":"bigint unsigned","not_null":true},{"name":"pages_made_young_rate","type":"float","not_null":true},{"name":"pages_made_not_young_rate","type":"float","not_null":true},{"name":"number_pages_read","type":"bigint unsigned","not_null":true},{"name":"number_pages_created","type":"bigint unsigned","not_null":true},{"name":"number_pages_written","type":"bigint unsigned","not_null":true},{"name":"pages_read_rate","type":"float","not_null":true},{"name":"pages_create_rate","type":"float","not_null":true},{"name":"pages_written_rate","type":"float","not_null":true},{"name":"number_pages_get","type":"bigint unsigned","not_null":true},{"name":"hit_rate","type":"bigint unsigned","not_null":true},{"name":"young_make_per_thousand_gets","type":"bigint unsigned","not_null":true},{"name":"not_young_make_per_thousand_gets","type":"bigint unsigned","not_null":true},{"name":"number_pages_read_ahead","type":"bigint unsigned","not_null":true},{"name":"number_read_ahead_evicted","type":"bigint unsigned","not_null":true},{"name":"read_ahead_rate","type":"float","not_null":true},{"name":"read_ahead_evicted_rate","type":"float","not_null":true},{"name":"lru_io_total","type":"bigint unsigned","not_null":true},{"name":"lru_io_current","type":"bigint unsigned","not_null":true},{"name":"uncompress_total","type":"bigint unsigned","not_null":true},{"name":"uncompress_current","type":"bigint unsigned","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"administrable_role_authorizations","kind":"v","columns":[{"name":"user","type":"varchar(97)"},{"name":"host","type":"varchar(256)"},{"name":"grantee","type":"varchar(97)"},{"name":"grantee_host","type":"varchar(256)"},{"name":"role_name","type":"varchar(255)"},{"name":"role_host","type":"varchar(256)"},{"name":"is_grantable","type":"varchar(3)","not_null":true},{"name":"is_default","type":"varchar(3)"},{"name":"is_mandatory","type":"varchar(3)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"applicable_roles","kind":"v","columns":[{"name":"user","type":"varchar(97)"},{"name":"host","type":"varchar(256)"},{"name":"grantee","type":"varchar(97)"},{"name":"grantee_host","type":"varchar(256)"},{"name":"role_name","type":"varchar(255)"},{"name":"role_host","type":"varchar(256)"},{"name":"is_grantable","type":"varchar(3)","not_null":true},{"name":"is_default","type":"varchar(3)"},{"name":"is_mandatory","type":"varchar(3)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"character_sets","kind":"v","columns":[{"name":"character_set_name","type":"varchar(64)","not_null":true},{"name":"default_collate_name","type":"varchar(64)","not_null":true},{"name":"description","type":"varchar(2048)","not_null":true},{"name":"maxlen","type":"int unsigned","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"check_constraints","kind":"v","columns":[{"name":"constraint_catalog","type":"varchar(64)","not_null":true},{"name":"constraint_schema","type":"varchar(64)","not_null":true},{"name":"constraint_name","type":"varchar(64)","not_null":true},{"name":"check_clause","type":"longtext","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"collations","kind":"v","columns":[{"name":"collation_name","type":"varchar(64)","not_null":true},{"name":"character_set_name","type":"varchar(64)","not_null":true},{"name":"id","type":"bigint unsigned","not_null":true},{"name":"is_default","type":"varchar(3)","not_null":true},{"name":"is_compiled","type":"varchar(3)","not_null":true},{"name":"sortlen","type":"int unsigned","not_null":true},{"name":"pad_attribute","type":"enum('PAD SPACE','NO PAD')","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"collation_character_set_applicability","kind":"v","columns":[{"name":"collation_name","type":"varchar(64)","not_null":true},{"name":"character_set_name","type":"varchar(64)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"columns","kind":"v","columns":[{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"column_name","type":"varchar(64)"},{"name":"ordinal_position","type":"int unsigned","not_null":true},{"name":"column_default","type":"text"},{"name":"is_nullable","type":"varchar(3)","not_null":true},{"name":"data_type","type":"longtext"},{"name":"character_maximum_length","type":"bigint"},{"name":"character_octet_length","type":"bigint"},{"name":"numeric_precision","type":"bigint unsigned"},{"name":"numeric_scale","type":"bigint unsigned"},{"name":"datetime_precision","type":"int unsigned"},{"name":"character_set_name","type":"varchar(64)"},{"name":"collation_name","type":"varchar(64)"},{"name":"column_type","type":"mediumtext","not_null":true},{"name":"column_key","type":"enum('','PRI','UNI','MUL')","not_null":true},{"name":"extra","type":"varchar(256)"},{"name":"privileges","type":"varchar(154)"},{"name":"column_comment","type":"text","not_null":true},{"name":"generation_expression","type":"longtext","not_null":true},{"name":"srs_id","type":"int unsigned"}]} +{"catalog":"def","schema":"information_schema","name":"columns_extensions","kind":"v","columns":[{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"column_name","type":"varchar(64)"},{"name":"engine_attribute","type":"json"},{"name":"secondary_engine_attribute","type":"json"}]} +{"catalog":"def","schema":"information_schema","name":"column_privileges","kind":"v","columns":[{"name":"grantee","type":"varchar(292)","not_null":true},{"name":"table_catalog","type":"varchar(512)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"column_name","type":"varchar(64)","not_null":true},{"name":"privilege_type","type":"varchar(64)","not_null":true},{"name":"is_grantable","type":"varchar(3)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"column_statistics","kind":"v","columns":[{"name":"schema_name","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"column_name","type":"varchar(64)","not_null":true},{"name":"histogram","type":"json","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"enabled_roles","kind":"v","columns":[{"name":"role_name","type":"varchar(255)"},{"name":"role_host","type":"varchar(255)"},{"name":"is_default","type":"varchar(3)"},{"name":"is_mandatory","type":"varchar(3)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"engines","kind":"v","columns":[{"name":"engine","type":"varchar(64)","not_null":true},{"name":"support","type":"varchar(8)","not_null":true},{"name":"comment","type":"varchar(80)","not_null":true},{"name":"transactions","type":"varchar(3)"},{"name":"xa","type":"varchar(3)"},{"name":"savepoints","type":"varchar(3)"}]} +{"catalog":"def","schema":"information_schema","name":"events","kind":"v","columns":[{"name":"event_catalog","type":"varchar(64)","not_null":true},{"name":"event_schema","type":"varchar(64)","not_null":true},{"name":"event_name","type":"varchar(64)","not_null":true},{"name":"definer","type":"varchar(288)","not_null":true},{"name":"time_zone","type":"varchar(64)","not_null":true},{"name":"event_body","type":"varchar(3)","not_null":true},{"name":"event_definition","type":"longtext","not_null":true},{"name":"event_type","type":"varchar(9)","not_null":true},{"name":"execute_at","type":"datetime"},{"name":"interval_value","type":"varchar(256)"},{"name":"interval_field","type":"enum('YEAR','QUARTER','MONTH','DAY','HOUR','MINUTE','WEEK','SECOND','MICROSECOND','YEAR_MONTH','DAY_HOUR','DAY_MINUTE','DAY_SECOND','HOUR_MINUTE','HOUR_SECOND','MINUTE_SECOND','DAY_MICROSECOND','HOUR_MICROSECOND','MINUTE_MICROSECOND','SECOND_MICROSECOND')"},{"name":"sql_mode","type":"set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES','IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION','NO_DIR_IN_CREATE','NOT_USED_9','NOT_USED_10','NOT_USED_11','NOT_USED_12','NOT_USED_13','NOT_USED_14','NOT_USED_15','NOT_USED_16','NOT_USED_17','NOT_USED_18','ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES','STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','ALLOW_INVALID_DATES','ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NOT_USED_29','HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LENGTH','TIME_TRUNCATE_FRACTIONAL','INTERPRET_UTF8_AS_UTF8MB4')","not_null":true},{"name":"starts","type":"datetime"},{"name":"ends","type":"datetime"},{"name":"status","type":"varchar(21)","not_null":true},{"name":"on_completion","type":"varchar(12)","not_null":true},{"name":"created","type":"timestamp","not_null":true},{"name":"last_altered","type":"timestamp","not_null":true},{"name":"last_executed","type":"datetime"},{"name":"event_comment","type":"varchar(2048)","not_null":true},{"name":"originator","type":"int unsigned","not_null":true},{"name":"character_set_client","type":"varchar(64)","not_null":true},{"name":"collation_connection","type":"varchar(64)","not_null":true},{"name":"database_collation","type":"varchar(64)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"files","kind":"v","columns":[{"name":"file_id","type":"bigint"},{"name":"file_name","type":"text"},{"name":"file_type","type":"varchar(256)"},{"name":"tablespace_name","type":"varchar(268)","not_null":true},{"name":"table_catalog","type":"varchar(0)","not_null":true},{"name":"table_schema","type":"varbinary(0)"},{"name":"table_name","type":"varbinary(0)"},{"name":"logfile_group_name","type":"varchar(256)"},{"name":"logfile_group_number","type":"bigint"},{"name":"engine","type":"varchar(64)","not_null":true},{"name":"fulltext_keys","type":"varbinary(0)"},{"name":"deleted_rows","type":"varbinary(0)"},{"name":"update_count","type":"varbinary(0)"},{"name":"free_extents","type":"bigint"},{"name":"total_extents","type":"bigint"},{"name":"extent_size","type":"bigint"},{"name":"initial_size","type":"bigint"},{"name":"maximum_size","type":"bigint"},{"name":"autoextend_size","type":"bigint"},{"name":"creation_time","type":"varbinary(0)"},{"name":"last_update_time","type":"varbinary(0)"},{"name":"last_access_time","type":"varbinary(0)"},{"name":"recover_time","type":"varbinary(0)"},{"name":"transaction_counter","type":"varbinary(0)"},{"name":"version","type":"bigint"},{"name":"row_format","type":"varchar(256)"},{"name":"table_rows","type":"varbinary(0)"},{"name":"avg_row_length","type":"varbinary(0)"},{"name":"data_length","type":"varbinary(0)"},{"name":"max_data_length","type":"varbinary(0)"},{"name":"index_length","type":"varbinary(0)"},{"name":"data_free","type":"bigint"},{"name":"create_time","type":"varbinary(0)"},{"name":"update_time","type":"varbinary(0)"},{"name":"check_time","type":"varbinary(0)"},{"name":"checksum","type":"varbinary(0)"},{"name":"status","type":"varchar(256)"},{"name":"extra","type":"varchar(256)"}]} +{"catalog":"def","schema":"information_schema","name":"innodb_buffer_page","kind":"v","columns":[{"name":"pool_id","type":"bigint unsigned","not_null":true},{"name":"block_id","type":"bigint unsigned","not_null":true},{"name":"space","type":"bigint unsigned","not_null":true},{"name":"page_number","type":"bigint unsigned","not_null":true},{"name":"page_type","type":"varchar(64)"},{"name":"flush_type","type":"bigint unsigned","not_null":true},{"name":"fix_count","type":"bigint unsigned","not_null":true},{"name":"is_hashed","type":"varchar(3)"},{"name":"newest_modification","type":"bigint unsigned","not_null":true},{"name":"oldest_modification","type":"bigint unsigned","not_null":true},{"name":"access_time","type":"bigint unsigned","not_null":true},{"name":"table_name","type":"varchar(1024)"},{"name":"index_name","type":"varchar(1024)"},{"name":"number_records","type":"bigint unsigned","not_null":true},{"name":"data_size","type":"bigint unsigned","not_null":true},{"name":"compressed_size","type":"bigint unsigned","not_null":true},{"name":"page_state","type":"varchar(64)"},{"name":"io_fix","type":"varchar(64)"},{"name":"is_old","type":"varchar(3)"},{"name":"free_page_clock","type":"bigint unsigned","not_null":true},{"name":"is_stale","type":"varchar(3)"}]} +{"catalog":"def","schema":"information_schema","name":"innodb_buffer_page_lru","kind":"v","columns":[{"name":"pool_id","type":"bigint unsigned","not_null":true},{"name":"lru_position","type":"bigint unsigned","not_null":true},{"name":"space","type":"bigint unsigned","not_null":true},{"name":"page_number","type":"bigint unsigned","not_null":true},{"name":"page_type","type":"varchar(64)"},{"name":"flush_type","type":"bigint unsigned","not_null":true},{"name":"fix_count","type":"bigint unsigned","not_null":true},{"name":"is_hashed","type":"varchar(3)"},{"name":"newest_modification","type":"bigint unsigned","not_null":true},{"name":"oldest_modification","type":"bigint unsigned","not_null":true},{"name":"access_time","type":"bigint unsigned","not_null":true},{"name":"table_name","type":"varchar(1024)"},{"name":"index_name","type":"varchar(1024)"},{"name":"number_records","type":"bigint unsigned","not_null":true},{"name":"data_size","type":"bigint unsigned","not_null":true},{"name":"compressed_size","type":"bigint unsigned","not_null":true},{"name":"compressed","type":"varchar(3)"},{"name":"io_fix","type":"varchar(64)"},{"name":"is_old","type":"varchar(3)"},{"name":"free_page_clock","type":"bigint unsigned","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_buffer_pool_stats","kind":"v","columns":[{"name":"pool_id","type":"bigint unsigned","not_null":true},{"name":"pool_size","type":"bigint unsigned","not_null":true},{"name":"free_buffers","type":"bigint unsigned","not_null":true},{"name":"database_pages","type":"bigint unsigned","not_null":true},{"name":"old_database_pages","type":"bigint unsigned","not_null":true},{"name":"modified_database_pages","type":"bigint unsigned","not_null":true},{"name":"pending_decompress","type":"bigint unsigned","not_null":true},{"name":"pending_reads","type":"bigint unsigned","not_null":true},{"name":"pending_flush_lru","type":"bigint unsigned","not_null":true},{"name":"pending_flush_list","type":"bigint unsigned","not_null":true},{"name":"pages_made_young","type":"bigint unsigned","not_null":true},{"name":"pages_not_made_young","type":"bigint unsigned","not_null":true},{"name":"pages_made_young_rate","type":"float(12,0)","not_null":true},{"name":"pages_made_not_young_rate","type":"float(12,0)","not_null":true},{"name":"number_pages_read","type":"bigint unsigned","not_null":true},{"name":"number_pages_created","type":"bigint unsigned","not_null":true},{"name":"number_pages_written","type":"bigint unsigned","not_null":true},{"name":"pages_read_rate","type":"float(12,0)","not_null":true},{"name":"pages_create_rate","type":"float(12,0)","not_null":true},{"name":"pages_written_rate","type":"float(12,0)","not_null":true},{"name":"number_pages_get","type":"bigint unsigned","not_null":true},{"name":"hit_rate","type":"bigint unsigned","not_null":true},{"name":"young_make_per_thousand_gets","type":"bigint unsigned","not_null":true},{"name":"not_young_make_per_thousand_gets","type":"bigint unsigned","not_null":true},{"name":"number_pages_read_ahead","type":"bigint unsigned","not_null":true},{"name":"number_read_ahead_evicted","type":"bigint unsigned","not_null":true},{"name":"read_ahead_rate","type":"float(12,0)","not_null":true},{"name":"read_ahead_evicted_rate","type":"float(12,0)","not_null":true},{"name":"lru_io_total","type":"bigint unsigned","not_null":true},{"name":"lru_io_current","type":"bigint unsigned","not_null":true},{"name":"uncompress_total","type":"bigint unsigned","not_null":true},{"name":"uncompress_current","type":"bigint unsigned","not_null":true}]} {"catalog":"def","schema":"information_schema","name":"innodb_cached_indexes","kind":"v","columns":[{"name":"space_id","type":"int unsigned","not_null":true},{"name":"index_id","type":"bigint unsigned","not_null":true},{"name":"n_cached_pages","type":"bigint unsigned","not_null":true}]} {"catalog":"def","schema":"information_schema","name":"innodb_cmp","kind":"v","columns":[{"name":"page_size","type":"int","not_null":true},{"name":"compress_ops","type":"int","not_null":true},{"name":"compress_ops_ok","type":"int","not_null":true},{"name":"compress_time","type":"int","not_null":true},{"name":"uncompress_ops","type":"int","not_null":true},{"name":"uncompress_time","type":"int","not_null":true}]} {"catalog":"def","schema":"information_schema","name":"innodb_cmpmem","kind":"v","columns":[{"name":"page_size","type":"int","not_null":true},{"name":"buffer_pool_instance","type":"int","not_null":true},{"name":"pages_used","type":"int","not_null":true},{"name":"pages_free","type":"int","not_null":true},{"name":"relocation_ops","type":"bigint","not_null":true},{"name":"relocation_time","type":"int","not_null":true}]} {"catalog":"def","schema":"information_schema","name":"innodb_cmpmem_reset","kind":"v","columns":[{"name":"page_size","type":"int","not_null":true},{"name":"buffer_pool_instance","type":"int","not_null":true},{"name":"pages_used","type":"int","not_null":true},{"name":"pages_free","type":"int","not_null":true},{"name":"relocation_ops","type":"bigint","not_null":true},{"name":"relocation_time","type":"int","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"innodb_cmp_per_index","kind":"v","columns":[{"name":"database_name","type":"varchar","not_null":true},{"name":"table_name","type":"varchar","not_null":true},{"name":"index_name","type":"varchar","not_null":true},{"name":"compress_ops","type":"int","not_null":true},{"name":"compress_ops_ok","type":"int","not_null":true},{"name":"compress_time","type":"int","not_null":true},{"name":"uncompress_ops","type":"int","not_null":true},{"name":"uncompress_time","type":"int","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"innodb_cmp_per_index_reset","kind":"v","columns":[{"name":"database_name","type":"varchar","not_null":true},{"name":"table_name","type":"varchar","not_null":true},{"name":"index_name","type":"varchar","not_null":true},{"name":"compress_ops","type":"int","not_null":true},{"name":"compress_ops_ok","type":"int","not_null":true},{"name":"compress_time","type":"int","not_null":true},{"name":"uncompress_ops","type":"int","not_null":true},{"name":"uncompress_time","type":"int","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_cmp_per_index","kind":"v","columns":[{"name":"database_name","type":"varchar(192)","not_null":true},{"name":"table_name","type":"varchar(192)","not_null":true},{"name":"index_name","type":"varchar(192)","not_null":true},{"name":"compress_ops","type":"int","not_null":true},{"name":"compress_ops_ok","type":"int","not_null":true},{"name":"compress_time","type":"int","not_null":true},{"name":"uncompress_ops","type":"int","not_null":true},{"name":"uncompress_time","type":"int","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_cmp_per_index_reset","kind":"v","columns":[{"name":"database_name","type":"varchar(192)","not_null":true},{"name":"table_name","type":"varchar(192)","not_null":true},{"name":"index_name","type":"varchar(192)","not_null":true},{"name":"compress_ops","type":"int","not_null":true},{"name":"compress_ops_ok","type":"int","not_null":true},{"name":"compress_time","type":"int","not_null":true},{"name":"uncompress_ops","type":"int","not_null":true},{"name":"uncompress_time","type":"int","not_null":true}]} {"catalog":"def","schema":"information_schema","name":"innodb_cmp_reset","kind":"v","columns":[{"name":"page_size","type":"int","not_null":true},{"name":"compress_ops","type":"int","not_null":true},{"name":"compress_ops_ok","type":"int","not_null":true},{"name":"compress_time","type":"int","not_null":true},{"name":"uncompress_ops","type":"int","not_null":true},{"name":"uncompress_time","type":"int","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"innodb_columns","kind":"v","columns":[{"name":"table_id","type":"bigint unsigned","not_null":true},{"name":"name","type":"varchar","not_null":true},{"name":"pos","type":"bigint unsigned","not_null":true},{"name":"mtype","type":"int","not_null":true},{"name":"prtype","type":"int","not_null":true},{"name":"len","type":"int","not_null":true},{"name":"has_default","type":"int","not_null":true},{"name":"default_value","type":"text"}]} -{"catalog":"def","schema":"information_schema","name":"innodb_datafiles","kind":"v","columns":[{"name":"space","type":"varbinary"},{"name":"path","type":"varchar","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"innodb_fields","kind":"v","columns":[{"name":"index_id","type":"varbinary"},{"name":"name","type":"varchar","not_null":true},{"name":"pos","type":"bigint unsigned","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"innodb_foreign","kind":"v","columns":[{"name":"id","type":"varchar"},{"name":"for_name","type":"varchar"},{"name":"ref_name","type":"varchar"},{"name":"n_cols","type":"bigint","not_null":true},{"name":"type","type":"bigint unsigned","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"innodb_foreign_cols","kind":"v","columns":[{"name":"id","type":"varchar"},{"name":"for_col_name","type":"varchar","not_null":true},{"name":"ref_col_name","type":"varchar","not_null":true},{"name":"pos","type":"int unsigned","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_columns","kind":"v","columns":[{"name":"table_id","type":"bigint unsigned","not_null":true},{"name":"name","type":"varchar(193)","not_null":true},{"name":"pos","type":"bigint unsigned","not_null":true},{"name":"mtype","type":"int","not_null":true},{"name":"prtype","type":"int","not_null":true},{"name":"len","type":"int","not_null":true},{"name":"has_default","type":"int","not_null":true},{"name":"default_value","type":"text"}]} +{"catalog":"def","schema":"information_schema","name":"innodb_datafiles","kind":"v","columns":[{"name":"space","type":"varbinary(256)"},{"name":"path","type":"varchar(512)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_fields","kind":"v","columns":[{"name":"index_id","type":"varbinary(256)"},{"name":"name","type":"varchar(64)","not_null":true},{"name":"pos","type":"bigint unsigned","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_foreign","kind":"v","columns":[{"name":"id","type":"varchar(129)"},{"name":"for_name","type":"varchar(129)"},{"name":"ref_name","type":"varchar(129)"},{"name":"n_cols","type":"bigint","not_null":true},{"name":"type","type":"bigint unsigned","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_foreign_cols","kind":"v","columns":[{"name":"id","type":"varchar(129)"},{"name":"for_col_name","type":"varchar(64)","not_null":true},{"name":"ref_col_name","type":"varchar(64)","not_null":true},{"name":"pos","type":"int unsigned","not_null":true}]} {"catalog":"def","schema":"information_schema","name":"innodb_ft_being_deleted","kind":"v","columns":[{"name":"doc_id","type":"bigint unsigned","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"innodb_ft_config","kind":"v","columns":[{"name":"key","type":"varchar","not_null":true},{"name":"value","type":"varchar","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"innodb_ft_default_stopword","kind":"v","columns":[{"name":"value","type":"varchar","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_ft_config","kind":"v","columns":[{"name":"key","type":"varchar(193)","not_null":true},{"name":"value","type":"varchar(193)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_ft_default_stopword","kind":"v","columns":[{"name":"value","type":"varchar(18)","not_null":true}]} {"catalog":"def","schema":"information_schema","name":"innodb_ft_deleted","kind":"v","columns":[{"name":"doc_id","type":"bigint unsigned","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"innodb_ft_index_cache","kind":"v","columns":[{"name":"word","type":"varchar","not_null":true},{"name":"first_doc_id","type":"bigint unsigned","not_null":true},{"name":"last_doc_id","type":"bigint unsigned","not_null":true},{"name":"doc_count","type":"bigint unsigned","not_null":true},{"name":"doc_id","type":"bigint unsigned","not_null":true},{"name":"position","type":"bigint unsigned","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"innodb_ft_index_table","kind":"v","columns":[{"name":"word","type":"varchar","not_null":true},{"name":"first_doc_id","type":"bigint unsigned","not_null":true},{"name":"last_doc_id","type":"bigint unsigned","not_null":true},{"name":"doc_count","type":"bigint unsigned","not_null":true},{"name":"doc_id","type":"bigint unsigned","not_null":true},{"name":"position","type":"bigint unsigned","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"innodb_indexes","kind":"v","columns":[{"name":"index_id","type":"bigint unsigned","not_null":true},{"name":"name","type":"varchar","not_null":true},{"name":"table_id","type":"bigint unsigned","not_null":true},{"name":"type","type":"int","not_null":true},{"name":"n_fields","type":"int","not_null":true},{"name":"page_no","type":"int","not_null":true},{"name":"space","type":"int","not_null":true},{"name":"merge_threshold","type":"int","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"innodb_metrics","kind":"v","columns":[{"name":"name","type":"varchar","not_null":true},{"name":"subsystem","type":"varchar","not_null":true},{"name":"count","type":"bigint","not_null":true},{"name":"max_count","type":"bigint"},{"name":"min_count","type":"bigint"},{"name":"avg_count","type":"float"},{"name":"count_reset","type":"bigint","not_null":true},{"name":"max_count_reset","type":"bigint"},{"name":"min_count_reset","type":"bigint"},{"name":"avg_count_reset","type":"float"},{"name":"time_enabled","type":"datetime"},{"name":"time_disabled","type":"datetime"},{"name":"time_elapsed","type":"bigint"},{"name":"time_reset","type":"datetime"},{"name":"status","type":"varchar","not_null":true},{"name":"type","type":"varchar","not_null":true},{"name":"comment","type":"varchar","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"innodb_session_temp_tablespaces","kind":"v","columns":[{"name":"id","type":"int unsigned","not_null":true},{"name":"space","type":"int unsigned","not_null":true},{"name":"path","type":"varchar","not_null":true},{"name":"size","type":"bigint unsigned","not_null":true},{"name":"state","type":"varchar","not_null":true},{"name":"purpose","type":"varchar","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"innodb_tables","kind":"v","columns":[{"name":"table_id","type":"bigint unsigned","not_null":true},{"name":"name","type":"varchar","not_null":true},{"name":"flag","type":"int","not_null":true},{"name":"n_cols","type":"int","not_null":true},{"name":"space","type":"bigint","not_null":true},{"name":"row_format","type":"varchar"},{"name":"zip_page_size","type":"int unsigned","not_null":true},{"name":"space_type","type":"varchar"},{"name":"instant_cols","type":"int","not_null":true},{"name":"total_row_versions","type":"int","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"innodb_tablespaces","kind":"v","columns":[{"name":"space","type":"int unsigned","not_null":true},{"name":"name","type":"varchar","not_null":true},{"name":"flag","type":"int unsigned","not_null":true},{"name":"row_format","type":"varchar"},{"name":"page_size","type":"int unsigned","not_null":true},{"name":"zip_page_size","type":"int unsigned","not_null":true},{"name":"space_type","type":"varchar"},{"name":"fs_block_size","type":"int unsigned","not_null":true},{"name":"file_size","type":"bigint unsigned","not_null":true},{"name":"allocated_size","type":"bigint unsigned","not_null":true},{"name":"autoextend_size","type":"bigint unsigned","not_null":true},{"name":"server_version","type":"varchar"},{"name":"space_version","type":"int unsigned","not_null":true},{"name":"encryption","type":"varchar"},{"name":"state","type":"varchar"}]} -{"catalog":"def","schema":"information_schema","name":"innodb_tablespaces_brief","kind":"v","columns":[{"name":"space","type":"varbinary"},{"name":"name","type":"varchar","not_null":true},{"name":"path","type":"varchar","not_null":true},{"name":"flag","type":"varbinary"},{"name":"space_type","type":"varchar","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"innodb_tablestats","kind":"v","columns":[{"name":"table_id","type":"bigint unsigned","not_null":true},{"name":"name","type":"varchar","not_null":true},{"name":"stats_initialized","type":"varchar","not_null":true},{"name":"num_rows","type":"bigint unsigned","not_null":true},{"name":"clust_index_size","type":"bigint unsigned","not_null":true},{"name":"other_index_size","type":"bigint unsigned","not_null":true},{"name":"modified_counter","type":"bigint unsigned","not_null":true},{"name":"autoinc","type":"bigint unsigned","not_null":true},{"name":"ref_count","type":"int","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"innodb_temp_table_info","kind":"v","columns":[{"name":"table_id","type":"bigint unsigned","not_null":true},{"name":"name","type":"varchar"},{"name":"n_cols","type":"int unsigned","not_null":true},{"name":"space","type":"int unsigned","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"innodb_trx","kind":"v","columns":[{"name":"trx_id","type":"bigint unsigned","not_null":true},{"name":"trx_state","type":"varchar","not_null":true},{"name":"trx_started","type":"datetime","not_null":true},{"name":"trx_requested_lock_id","type":"varchar"},{"name":"trx_wait_started","type":"datetime"},{"name":"trx_weight","type":"bigint unsigned","not_null":true},{"name":"trx_mysql_thread_id","type":"bigint unsigned","not_null":true},{"name":"trx_query","type":"varchar"},{"name":"trx_operation_state","type":"varchar"},{"name":"trx_tables_in_use","type":"bigint unsigned","not_null":true},{"name":"trx_tables_locked","type":"bigint unsigned","not_null":true},{"name":"trx_lock_structs","type":"bigint unsigned","not_null":true},{"name":"trx_lock_memory_bytes","type":"bigint unsigned","not_null":true},{"name":"trx_rows_locked","type":"bigint unsigned","not_null":true},{"name":"trx_rows_modified","type":"bigint unsigned","not_null":true},{"name":"trx_concurrency_tickets","type":"bigint unsigned","not_null":true},{"name":"trx_isolation_level","type":"varchar","not_null":true},{"name":"trx_unique_checks","type":"int","not_null":true},{"name":"trx_foreign_key_checks","type":"int","not_null":true},{"name":"trx_last_foreign_key_error","type":"varchar"},{"name":"trx_adaptive_hash_latched","type":"int","not_null":true},{"name":"trx_adaptive_hash_timeout","type":"bigint unsigned","not_null":true},{"name":"trx_is_read_only","type":"int","not_null":true},{"name":"trx_autocommit_non_locking","type":"int","not_null":true},{"name":"trx_schedule_weight","type":"bigint unsigned"}]} +{"catalog":"def","schema":"information_schema","name":"innodb_ft_index_cache","kind":"v","columns":[{"name":"word","type":"varchar(337)","not_null":true},{"name":"first_doc_id","type":"bigint unsigned","not_null":true},{"name":"last_doc_id","type":"bigint unsigned","not_null":true},{"name":"doc_count","type":"bigint unsigned","not_null":true},{"name":"doc_id","type":"bigint unsigned","not_null":true},{"name":"position","type":"bigint unsigned","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_ft_index_table","kind":"v","columns":[{"name":"word","type":"varchar(337)","not_null":true},{"name":"first_doc_id","type":"bigint unsigned","not_null":true},{"name":"last_doc_id","type":"bigint unsigned","not_null":true},{"name":"doc_count","type":"bigint unsigned","not_null":true},{"name":"doc_id","type":"bigint unsigned","not_null":true},{"name":"position","type":"bigint unsigned","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_indexes","kind":"v","columns":[{"name":"index_id","type":"bigint unsigned","not_null":true},{"name":"name","type":"varchar(193)","not_null":true},{"name":"table_id","type":"bigint unsigned","not_null":true},{"name":"type","type":"int","not_null":true},{"name":"n_fields","type":"int","not_null":true},{"name":"page_no","type":"int","not_null":true},{"name":"space","type":"int","not_null":true},{"name":"merge_threshold","type":"int","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_metrics","kind":"v","columns":[{"name":"name","type":"varchar(193)","not_null":true},{"name":"subsystem","type":"varchar(193)","not_null":true},{"name":"count","type":"bigint","not_null":true},{"name":"max_count","type":"bigint"},{"name":"min_count","type":"bigint"},{"name":"avg_count","type":"float(12,0)"},{"name":"count_reset","type":"bigint","not_null":true},{"name":"max_count_reset","type":"bigint"},{"name":"min_count_reset","type":"bigint"},{"name":"avg_count_reset","type":"float(12,0)"},{"name":"time_enabled","type":"datetime"},{"name":"time_disabled","type":"datetime"},{"name":"time_elapsed","type":"bigint"},{"name":"time_reset","type":"datetime"},{"name":"status","type":"varchar(193)","not_null":true},{"name":"type","type":"varchar(193)","not_null":true},{"name":"comment","type":"varchar(193)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_session_temp_tablespaces","kind":"v","columns":[{"name":"id","type":"int unsigned","not_null":true},{"name":"space","type":"int unsigned","not_null":true},{"name":"path","type":"varchar(4001)","not_null":true},{"name":"size","type":"bigint unsigned","not_null":true},{"name":"state","type":"varchar(192)","not_null":true},{"name":"purpose","type":"varchar(192)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_tables","kind":"v","columns":[{"name":"table_id","type":"bigint unsigned","not_null":true},{"name":"name","type":"varchar(655)","not_null":true},{"name":"flag","type":"int","not_null":true},{"name":"n_cols","type":"int","not_null":true},{"name":"space","type":"bigint","not_null":true},{"name":"row_format","type":"varchar(12)"},{"name":"zip_page_size","type":"int unsigned","not_null":true},{"name":"space_type","type":"varchar(10)"},{"name":"instant_cols","type":"int","not_null":true},{"name":"total_row_versions","type":"int","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_tablespaces","kind":"v","columns":[{"name":"space","type":"int unsigned","not_null":true},{"name":"name","type":"varchar(655)","not_null":true},{"name":"flag","type":"int unsigned","not_null":true},{"name":"row_format","type":"varchar(22)"},{"name":"page_size","type":"int unsigned","not_null":true},{"name":"zip_page_size","type":"int unsigned","not_null":true},{"name":"space_type","type":"varchar(10)"},{"name":"fs_block_size","type":"int unsigned","not_null":true},{"name":"file_size","type":"bigint unsigned","not_null":true},{"name":"allocated_size","type":"bigint unsigned","not_null":true},{"name":"autoextend_size","type":"bigint unsigned","not_null":true},{"name":"server_version","type":"varchar(10)"},{"name":"space_version","type":"int unsigned","not_null":true},{"name":"encryption","type":"varchar(1)"},{"name":"state","type":"varchar(10)"}]} +{"catalog":"def","schema":"information_schema","name":"innodb_tablespaces_brief","kind":"v","columns":[{"name":"space","type":"varbinary(256)"},{"name":"name","type":"varchar(268)","not_null":true},{"name":"path","type":"varchar(512)","not_null":true},{"name":"flag","type":"varbinary(256)"},{"name":"space_type","type":"varchar(7)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_tablestats","kind":"v","columns":[{"name":"table_id","type":"bigint unsigned","not_null":true},{"name":"name","type":"varchar(193)","not_null":true},{"name":"stats_initialized","type":"varchar(193)","not_null":true},{"name":"num_rows","type":"bigint unsigned","not_null":true},{"name":"clust_index_size","type":"bigint unsigned","not_null":true},{"name":"other_index_size","type":"bigint unsigned","not_null":true},{"name":"modified_counter","type":"bigint unsigned","not_null":true},{"name":"autoinc","type":"bigint unsigned","not_null":true},{"name":"ref_count","type":"int","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_temp_table_info","kind":"v","columns":[{"name":"table_id","type":"bigint unsigned","not_null":true},{"name":"name","type":"varchar(64)"},{"name":"n_cols","type":"int unsigned","not_null":true},{"name":"space","type":"int unsigned","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_trx","kind":"v","columns":[{"name":"trx_id","type":"bigint unsigned","not_null":true},{"name":"trx_state","type":"varchar(13)","not_null":true},{"name":"trx_started","type":"datetime","not_null":true},{"name":"trx_requested_lock_id","type":"varchar(126)"},{"name":"trx_wait_started","type":"datetime"},{"name":"trx_weight","type":"bigint unsigned","not_null":true},{"name":"trx_mysql_thread_id","type":"bigint unsigned","not_null":true},{"name":"trx_query","type":"varchar(1024)"},{"name":"trx_operation_state","type":"varchar(64)"},{"name":"trx_tables_in_use","type":"bigint unsigned","not_null":true},{"name":"trx_tables_locked","type":"bigint unsigned","not_null":true},{"name":"trx_lock_structs","type":"bigint unsigned","not_null":true},{"name":"trx_lock_memory_bytes","type":"bigint unsigned","not_null":true},{"name":"trx_rows_locked","type":"bigint unsigned","not_null":true},{"name":"trx_rows_modified","type":"bigint unsigned","not_null":true},{"name":"trx_concurrency_tickets","type":"bigint unsigned","not_null":true},{"name":"trx_isolation_level","type":"varchar(16)","not_null":true},{"name":"trx_unique_checks","type":"int","not_null":true},{"name":"trx_foreign_key_checks","type":"int","not_null":true},{"name":"trx_last_foreign_key_error","type":"varchar(256)"},{"name":"trx_adaptive_hash_latched","type":"int","not_null":true},{"name":"trx_adaptive_hash_timeout","type":"bigint unsigned","not_null":true},{"name":"trx_is_read_only","type":"int","not_null":true},{"name":"trx_autocommit_non_locking","type":"int","not_null":true},{"name":"trx_schedule_weight","type":"bigint unsigned"}]} {"catalog":"def","schema":"information_schema","name":"innodb_virtual","kind":"v","columns":[{"name":"table_id","type":"bigint unsigned","not_null":true},{"name":"pos","type":"int unsigned","not_null":true},{"name":"base_pos","type":"int unsigned","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"json_duality_views","kind":"v","columns":[{"name":"table_catalog","type":"varchar","not_null":true},{"name":"table_schema","type":"varchar","not_null":true},{"name":"table_name","type":"varchar","not_null":true},{"name":"definer","type":"varchar"},{"name":"security_type","type":"varchar"},{"name":"json_column_name","type":"varchar","not_null":true},{"name":"root_table_catalog","type":"varchar"},{"name":"root_table_schema","type":"varchar"},{"name":"root_table_name","type":"varchar"},{"name":"allow_insert","type":"varchar"},{"name":"allow_update","type":"varchar"},{"name":"allow_delete","type":"varchar"},{"name":"read_only","type":"varchar"},{"name":"status","type":"varchar","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"json_duality_view_columns","kind":"v","columns":[{"name":"table_catalog","type":"varchar","not_null":true},{"name":"table_schema","type":"varchar","not_null":true},{"name":"table_name","type":"varchar","not_null":true},{"name":"referenced_table_catalog","type":"varchar"},{"name":"referenced_table_schema","type":"varchar"},{"name":"referenced_table_name","type":"varchar"},{"name":"is_root_table","type":"tinyint"},{"name":"referenced_table_id","type":"int"},{"name":"referenced_column_name","type":"varchar"},{"name":"json_key_name","type":"varchar"},{"name":"allow_insert","type":"tinyint"},{"name":"allow_update","type":"tinyint"},{"name":"allow_delete","type":"tinyint"},{"name":"read_only","type":"tinyint"}]} -{"catalog":"def","schema":"information_schema","name":"json_duality_view_links","kind":"v","columns":[{"name":"table_catalog","type":"varchar","not_null":true},{"name":"table_schema","type":"varchar","not_null":true},{"name":"table_name","type":"varchar","not_null":true},{"name":"parent_table_catalog","type":"varchar"},{"name":"parent_table_schema","type":"varchar"},{"name":"parent_table_name","type":"varchar"},{"name":"child_table_catalog","type":"varchar"},{"name":"child_table_schema","type":"varchar"},{"name":"child_table_name","type":"varchar"},{"name":"parent_column_name","type":"varchar"},{"name":"child_column_name","type":"varchar"},{"name":"join_type","type":"varchar"},{"name":"json_key_name","type":"varchar"}]} -{"catalog":"def","schema":"information_schema","name":"json_duality_view_tables","kind":"v","columns":[{"name":"table_catalog","type":"varchar","not_null":true},{"name":"table_schema","type":"varchar","not_null":true},{"name":"table_name","type":"varchar","not_null":true},{"name":"referenced_table_catalog","type":"varchar"},{"name":"referenced_table_schema","type":"varchar"},{"name":"referenced_table_name","type":"varchar"},{"name":"where_clause","type":"varchar"},{"name":"allow_insert","type":"tinyint"},{"name":"allow_update","type":"tinyint"},{"name":"allow_delete","type":"tinyint"},{"name":"read_only","type":"tinyint"},{"name":"is_root_table","type":"tinyint"},{"name":"referenced_table_id","type":"int"},{"name":"referenced_table_parent_id","type":"int"},{"name":"referenced_table_parent_relationship","type":"varchar"}]} -{"catalog":"def","schema":"information_schema","name":"keywords","kind":"v","columns":[{"name":"word","type":"varchar"},{"name":"reserved","type":"int"}]} -{"catalog":"def","schema":"information_schema","name":"key_column_usage","kind":"v","columns":[{"name":"constraint_catalog","type":"varchar","not_null":true},{"name":"constraint_schema","type":"varchar","not_null":true},{"name":"constraint_name","type":"varchar"},{"name":"table_catalog","type":"varchar","not_null":true},{"name":"table_schema","type":"varchar","not_null":true},{"name":"table_name","type":"varchar","not_null":true},{"name":"column_name","type":"varchar"},{"name":"ordinal_position","type":"int unsigned","not_null":true},{"name":"position_in_unique_constraint","type":"int unsigned"},{"name":"referenced_table_schema","type":"varchar"},{"name":"referenced_table_name","type":"varchar"},{"name":"referenced_column_name","type":"varchar"}]} -{"catalog":"def","schema":"information_schema","name":"libraries","kind":"v","columns":[{"name":"library_catalog","type":"varchar","not_null":true},{"name":"library_schema","type":"varchar","not_null":true},{"name":"library_name","type":"varchar","not_null":true},{"name":"library_definition","type":"longtext"},{"name":"language","type":"varchar","not_null":true},{"name":"created","type":"timestamp","not_null":true},{"name":"last_altered","type":"timestamp","not_null":true},{"name":"sql_mode","type":"set","not_null":true},{"name":"library_comment","type":"text","not_null":true},{"name":"creator","type":"varchar","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"optimizer_trace","kind":"v","columns":[{"name":"query","type":"varchar","not_null":true},{"name":"trace","type":"varchar","not_null":true},{"name":"missing_bytes_beyond_max_mem_size","type":"int","not_null":true},{"name":"insufficient_privileges","type":"tinyint","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"parameters","kind":"v","columns":[{"name":"specific_catalog","type":"varchar","not_null":true},{"name":"specific_schema","type":"varchar","not_null":true},{"name":"specific_name","type":"varchar","not_null":true},{"name":"ordinal_position","type":"bigint unsigned","not_null":true},{"name":"parameter_mode","type":"varchar"},{"name":"parameter_name","type":"varchar"},{"name":"data_type","type":"longtext"},{"name":"character_maximum_length","type":"bigint"},{"name":"character_octet_length","type":"bigint"},{"name":"numeric_precision","type":"int unsigned"},{"name":"numeric_scale","type":"bigint"},{"name":"datetime_precision","type":"int unsigned"},{"name":"character_set_name","type":"varchar"},{"name":"collation_name","type":"varchar"},{"name":"dtd_identifier","type":"mediumtext","not_null":true},{"name":"routine_type","type":"enum","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"partitions","kind":"v","columns":[{"name":"table_catalog","type":"varchar","not_null":true},{"name":"table_schema","type":"varchar","not_null":true},{"name":"table_name","type":"varchar","not_null":true},{"name":"partition_name","type":"varchar"},{"name":"subpartition_name","type":"varchar"},{"name":"partition_ordinal_position","type":"int unsigned"},{"name":"subpartition_ordinal_position","type":"int unsigned"},{"name":"secondary_load","type":"varchar"},{"name":"partition_method","type":"varchar"},{"name":"subpartition_method","type":"varchar"},{"name":"partition_expression","type":"varchar"},{"name":"subpartition_expression","type":"varchar"},{"name":"partition_description","type":"text"},{"name":"table_rows","type":"bigint unsigned"},{"name":"avg_row_length","type":"bigint unsigned"},{"name":"data_length","type":"bigint unsigned"},{"name":"max_data_length","type":"bigint unsigned"},{"name":"index_length","type":"bigint unsigned"},{"name":"data_free","type":"bigint unsigned"},{"name":"create_time","type":"timestamp","not_null":true},{"name":"update_time","type":"datetime"},{"name":"check_time","type":"datetime"},{"name":"checksum","type":"bigint"},{"name":"partition_comment","type":"text","not_null":true},{"name":"nodegroup","type":"varchar"},{"name":"tablespace_name","type":"varchar"}]} -{"catalog":"def","schema":"information_schema","name":"plugins","kind":"v","columns":[{"name":"plugin_name","type":"varchar","not_null":true},{"name":"plugin_version","type":"varchar","not_null":true},{"name":"plugin_status","type":"varchar","not_null":true},{"name":"plugin_type","type":"varchar","not_null":true},{"name":"plugin_type_version","type":"varchar","not_null":true},{"name":"plugin_library","type":"varchar"},{"name":"plugin_library_version","type":"varchar"},{"name":"plugin_author","type":"varchar"},{"name":"plugin_description","type":"varchar"},{"name":"plugin_license","type":"varchar"},{"name":"load_option","type":"varchar","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"processlist","kind":"v","columns":[{"name":"id","type":"bigint unsigned","not_null":true},{"name":"user","type":"varchar","not_null":true},{"name":"host","type":"varchar","not_null":true},{"name":"db","type":"varchar"},{"name":"command","type":"varchar","not_null":true},{"name":"time","type":"int","not_null":true},{"name":"state","type":"varchar"},{"name":"info","type":"varchar"}]} -{"catalog":"def","schema":"information_schema","name":"profiling","kind":"v","columns":[{"name":"query_id","type":"int","not_null":true},{"name":"seq","type":"int","not_null":true},{"name":"state","type":"varchar","not_null":true},{"name":"duration","type":"decimal","not_null":true},{"name":"cpu_user","type":"decimal"},{"name":"cpu_system","type":"decimal"},{"name":"context_voluntary","type":"int"},{"name":"context_involuntary","type":"int"},{"name":"block_ops_in","type":"int"},{"name":"block_ops_out","type":"int"},{"name":"messages_sent","type":"int"},{"name":"messages_received","type":"int"},{"name":"page_faults_major","type":"int"},{"name":"page_faults_minor","type":"int"},{"name":"swaps","type":"int"},{"name":"source_function","type":"varchar"},{"name":"source_file","type":"varchar"},{"name":"source_line","type":"int"}]} -{"catalog":"def","schema":"information_schema","name":"referential_constraints","kind":"v","columns":[{"name":"constraint_catalog","type":"varchar","not_null":true},{"name":"constraint_schema","type":"varchar","not_null":true},{"name":"constraint_name","type":"varchar"},{"name":"unique_constraint_catalog","type":"varchar","not_null":true},{"name":"unique_constraint_schema","type":"varchar","not_null":true},{"name":"unique_constraint_name","type":"varchar"},{"name":"match_option","type":"enum","not_null":true},{"name":"update_rule","type":"enum","not_null":true},{"name":"delete_rule","type":"enum","not_null":true},{"name":"table_name","type":"varchar","not_null":true},{"name":"referenced_table_name","type":"varchar","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"resource_groups","kind":"v","columns":[{"name":"resource_group_name","type":"varchar","not_null":true},{"name":"resource_group_type","type":"enum","not_null":true},{"name":"resource_group_enabled","type":"tinyint","not_null":true},{"name":"vcpu_ids","type":"blob"},{"name":"thread_priority","type":"int","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"role_column_grants","kind":"v","columns":[{"name":"grantor","type":"varchar"},{"name":"grantor_host","type":"varchar"},{"name":"grantee","type":"char","not_null":true},{"name":"grantee_host","type":"char","not_null":true},{"name":"table_catalog","type":"varchar","not_null":true},{"name":"table_schema","type":"char","not_null":true},{"name":"table_name","type":"char","not_null":true},{"name":"column_name","type":"char","not_null":true},{"name":"privilege_type","type":"set","not_null":true},{"name":"is_grantable","type":"varchar","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"role_routine_grants","kind":"v","columns":[{"name":"grantor","type":"varchar"},{"name":"grantor_host","type":"varchar"},{"name":"grantee","type":"char","not_null":true},{"name":"grantee_host","type":"char","not_null":true},{"name":"specific_catalog","type":"varchar","not_null":true},{"name":"specific_schema","type":"char","not_null":true},{"name":"specific_name","type":"char","not_null":true},{"name":"routine_catalog","type":"varchar","not_null":true},{"name":"routine_schema","type":"char","not_null":true},{"name":"routine_name","type":"char","not_null":true},{"name":"privilege_type","type":"set","not_null":true},{"name":"is_grantable","type":"varchar","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"role_table_grants","kind":"v","columns":[{"name":"grantor","type":"varchar"},{"name":"grantor_host","type":"varchar"},{"name":"grantee","type":"char","not_null":true},{"name":"grantee_host","type":"char","not_null":true},{"name":"table_catalog","type":"varchar","not_null":true},{"name":"table_schema","type":"char","not_null":true},{"name":"table_name","type":"char","not_null":true},{"name":"privilege_type","type":"set","not_null":true},{"name":"is_grantable","type":"varchar","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"routines","kind":"v","columns":[{"name":"specific_name","type":"varchar","not_null":true},{"name":"routine_catalog","type":"varchar","not_null":true},{"name":"routine_schema","type":"varchar","not_null":true},{"name":"routine_name","type":"varchar","not_null":true},{"name":"routine_type","type":"enum","not_null":true},{"name":"data_type","type":"longtext"},{"name":"character_maximum_length","type":"bigint"},{"name":"character_octet_length","type":"bigint"},{"name":"numeric_precision","type":"int unsigned"},{"name":"numeric_scale","type":"int unsigned"},{"name":"datetime_precision","type":"int unsigned"},{"name":"character_set_name","type":"varchar"},{"name":"collation_name","type":"varchar"},{"name":"dtd_identifier","type":"longtext"},{"name":"routine_body","type":"varchar","not_null":true},{"name":"routine_definition","type":"longtext"},{"name":"external_name","type":"varbinary"},{"name":"external_language","type":"varchar","not_null":true},{"name":"parameter_style","type":"varchar","not_null":true},{"name":"is_deterministic","type":"varchar","not_null":true},{"name":"sql_data_access","type":"enum","not_null":true},{"name":"sql_path","type":"varbinary"},{"name":"security_type","type":"enum","not_null":true},{"name":"created","type":"timestamp","not_null":true},{"name":"last_altered","type":"timestamp","not_null":true},{"name":"sql_mode","type":"set","not_null":true},{"name":"routine_comment","type":"text","not_null":true},{"name":"definer","type":"varchar","not_null":true},{"name":"character_set_client","type":"varchar","not_null":true},{"name":"collation_connection","type":"varchar","not_null":true},{"name":"database_collation","type":"varchar","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"routine_libraries","kind":"v","columns":[{"name":"routine_catalog","type":"varchar","not_null":true},{"name":"routine_schema","type":"varchar","not_null":true},{"name":"routine_name","type":"varchar","not_null":true},{"name":"routine_type","type":"enum","not_null":true},{"name":"library_catalog","type":"varchar"},{"name":"library_schema","type":"varchar"},{"name":"library_name","type":"varchar"},{"name":"library_version","type":"varchar"}]} -{"catalog":"def","schema":"information_schema","name":"schemata","kind":"v","columns":[{"name":"catalog_name","type":"varchar","not_null":true},{"name":"schema_name","type":"varchar","not_null":true},{"name":"default_character_set_name","type":"varchar","not_null":true},{"name":"default_collation_name","type":"varchar","not_null":true},{"name":"sql_path","type":"varbinary"},{"name":"default_encryption","type":"enum","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"schemata_extensions","kind":"v","columns":[{"name":"catalog_name","type":"varchar","not_null":true},{"name":"schema_name","type":"varchar","not_null":true},{"name":"options","type":"varchar"}]} -{"catalog":"def","schema":"information_schema","name":"schema_privileges","kind":"v","columns":[{"name":"grantee","type":"varchar","not_null":true},{"name":"table_catalog","type":"varchar","not_null":true},{"name":"table_schema","type":"varchar","not_null":true},{"name":"privilege_type","type":"varchar","not_null":true},{"name":"is_grantable","type":"varchar","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"statistics","kind":"v","columns":[{"name":"table_catalog","type":"varchar","not_null":true},{"name":"table_schema","type":"varchar","not_null":true},{"name":"table_name","type":"varchar","not_null":true},{"name":"non_unique","type":"int","not_null":true},{"name":"index_schema","type":"varchar","not_null":true},{"name":"index_name","type":"varchar"},{"name":"seq_in_index","type":"int unsigned","not_null":true},{"name":"column_name","type":"varchar"},{"name":"collation","type":"varchar"},{"name":"cardinality","type":"bigint"},{"name":"sub_part","type":"bigint"},{"name":"packed","type":"varbinary"},{"name":"nullable","type":"varchar","not_null":true},{"name":"index_type","type":"varchar","not_null":true},{"name":"comment","type":"varchar","not_null":true},{"name":"index_comment","type":"varchar","not_null":true},{"name":"is_visible","type":"varchar","not_null":true},{"name":"expression","type":"longtext"}]} -{"catalog":"def","schema":"information_schema","name":"st_geometry_columns","kind":"v","columns":[{"name":"table_catalog","type":"varchar","not_null":true},{"name":"table_schema","type":"varchar","not_null":true},{"name":"table_name","type":"varchar","not_null":true},{"name":"column_name","type":"varchar"},{"name":"srs_name","type":"varchar"},{"name":"srs_id","type":"int unsigned"},{"name":"geometry_type_name","type":"longtext"}]} -{"catalog":"def","schema":"information_schema","name":"st_spatial_reference_systems","kind":"v","columns":[{"name":"srs_name","type":"varchar","not_null":true},{"name":"srs_id","type":"int unsigned","not_null":true},{"name":"organization","type":"varchar"},{"name":"organization_coordsys_id","type":"int unsigned"},{"name":"definition","type":"varchar","not_null":true},{"name":"description","type":"varchar"}]} -{"catalog":"def","schema":"information_schema","name":"st_units_of_measure","kind":"v","columns":[{"name":"unit_name","type":"varchar"},{"name":"unit_type","type":"varchar"},{"name":"conversion_factor","type":"double"},{"name":"description","type":"varchar"}]} -{"catalog":"def","schema":"information_schema","name":"tables","kind":"v","columns":[{"name":"table_catalog","type":"varchar","not_null":true},{"name":"table_schema","type":"varchar","not_null":true},{"name":"table_name","type":"varchar","not_null":true},{"name":"table_type","type":"enum","not_null":true},{"name":"engine","type":"varchar"},{"name":"version","type":"int"},{"name":"row_format","type":"enum"},{"name":"table_rows","type":"bigint unsigned"},{"name":"avg_row_length","type":"bigint unsigned"},{"name":"data_length","type":"bigint unsigned"},{"name":"max_data_length","type":"bigint unsigned"},{"name":"index_length","type":"bigint unsigned"},{"name":"data_free","type":"bigint unsigned"},{"name":"auto_increment","type":"bigint unsigned"},{"name":"create_time","type":"timestamp","not_null":true},{"name":"update_time","type":"datetime"},{"name":"check_time","type":"datetime"},{"name":"table_collation","type":"varchar"},{"name":"checksum","type":"bigint"},{"name":"create_options","type":"varchar"},{"name":"table_comment","type":"text"}]} -{"catalog":"def","schema":"information_schema","name":"tablespaces_extensions","kind":"v","columns":[{"name":"tablespace_name","type":"varchar","not_null":true},{"name":"engine_attribute","type":"json"}]} -{"catalog":"def","schema":"information_schema","name":"tables_extensions","kind":"v","columns":[{"name":"table_catalog","type":"varchar","not_null":true},{"name":"table_schema","type":"varchar","not_null":true},{"name":"table_name","type":"varchar","not_null":true},{"name":"engine_attribute","type":"json"},{"name":"secondary_engine_attribute","type":"json"}]} -{"catalog":"def","schema":"information_schema","name":"table_constraints","kind":"v","columns":[{"name":"constraint_catalog","type":"varchar","not_null":true},{"name":"constraint_schema","type":"varchar","not_null":true},{"name":"constraint_name","type":"varchar"},{"name":"table_schema","type":"varchar","not_null":true},{"name":"table_name","type":"varchar","not_null":true},{"name":"constraint_type","type":"varchar","not_null":true},{"name":"enforced","type":"varchar","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"table_constraints_extensions","kind":"v","columns":[{"name":"constraint_catalog","type":"varchar","not_null":true},{"name":"constraint_schema","type":"varchar","not_null":true},{"name":"constraint_name","type":"varchar","not_null":true},{"name":"table_name","type":"varchar","not_null":true},{"name":"engine_attribute","type":"json"},{"name":"secondary_engine_attribute","type":"json"}]} -{"catalog":"def","schema":"information_schema","name":"table_privileges","kind":"v","columns":[{"name":"grantee","type":"varchar","not_null":true},{"name":"table_catalog","type":"varchar","not_null":true},{"name":"table_schema","type":"varchar","not_null":true},{"name":"table_name","type":"varchar","not_null":true},{"name":"privilege_type","type":"varchar","not_null":true},{"name":"is_grantable","type":"varchar","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"triggers","kind":"v","columns":[{"name":"trigger_catalog","type":"varchar","not_null":true},{"name":"trigger_schema","type":"varchar","not_null":true},{"name":"trigger_name","type":"varchar","not_null":true},{"name":"event_manipulation","type":"enum","not_null":true},{"name":"event_object_catalog","type":"varchar","not_null":true},{"name":"event_object_schema","type":"varchar","not_null":true},{"name":"event_object_table","type":"varchar","not_null":true},{"name":"action_order","type":"int unsigned","not_null":true},{"name":"action_condition","type":"varbinary"},{"name":"action_statement","type":"longtext","not_null":true},{"name":"action_orientation","type":"varchar","not_null":true},{"name":"action_timing","type":"enum","not_null":true},{"name":"action_reference_old_table","type":"varbinary"},{"name":"action_reference_new_table","type":"varbinary"},{"name":"action_reference_old_row","type":"varchar","not_null":true},{"name":"action_reference_new_row","type":"varchar","not_null":true},{"name":"created","type":"timestamp","not_null":true},{"name":"sql_mode","type":"set","not_null":true},{"name":"definer","type":"varchar","not_null":true},{"name":"character_set_client","type":"varchar","not_null":true},{"name":"collation_connection","type":"varchar","not_null":true},{"name":"database_collation","type":"varchar","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"user_attributes","kind":"v","columns":[{"name":"user","type":"char","not_null":true},{"name":"host","type":"char","not_null":true},{"name":"attribute","type":"longtext"}]} -{"catalog":"def","schema":"information_schema","name":"user_privileges","kind":"v","columns":[{"name":"grantee","type":"varchar","not_null":true},{"name":"table_catalog","type":"varchar","not_null":true},{"name":"privilege_type","type":"varchar","not_null":true},{"name":"is_grantable","type":"varchar","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"views","kind":"v","columns":[{"name":"table_catalog","type":"varchar","not_null":true},{"name":"table_schema","type":"varchar","not_null":true},{"name":"table_name","type":"varchar","not_null":true},{"name":"view_definition","type":"longtext"},{"name":"check_option","type":"enum"},{"name":"is_updatable","type":"enum"},{"name":"definer","type":"varchar"},{"name":"security_type","type":"varchar"},{"name":"character_set_client","type":"varchar","not_null":true},{"name":"collation_connection","type":"varchar","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"view_routine_usage","kind":"v","columns":[{"name":"table_catalog","type":"varchar","not_null":true},{"name":"table_schema","type":"varchar","not_null":true},{"name":"table_name","type":"varchar","not_null":true},{"name":"specific_catalog","type":"varchar","not_null":true},{"name":"specific_schema","type":"varchar","not_null":true},{"name":"specific_name","type":"varchar","not_null":true}]} -{"catalog":"def","schema":"information_schema","name":"view_table_usage","kind":"v","columns":[{"name":"view_catalog","type":"varchar","not_null":true},{"name":"view_schema","type":"varchar","not_null":true},{"name":"view_name","type":"varchar","not_null":true},{"name":"table_catalog","type":"varchar","not_null":true},{"name":"table_schema","type":"varchar","not_null":true},{"name":"table_name","type":"varchar","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"json_duality_views","kind":"v","columns":[{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"definer","type":"varchar(288)"},{"name":"security_type","type":"varchar(7)"},{"name":"json_column_name","type":"varchar(64)","not_null":true},{"name":"root_table_catalog","type":"varchar(64)"},{"name":"root_table_schema","type":"varchar(64)"},{"name":"root_table_name","type":"varchar(64)"},{"name":"allow_insert","type":"varchar(4)"},{"name":"allow_update","type":"varchar(4)"},{"name":"allow_delete","type":"varchar(4)"},{"name":"read_only","type":"varchar(4)"},{"name":"status","type":"varchar(7)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"json_duality_view_columns","kind":"v","columns":[{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"referenced_table_catalog","type":"varchar(64)"},{"name":"referenced_table_schema","type":"varchar(64)"},{"name":"referenced_table_name","type":"varchar(64)"},{"name":"is_root_table","type":"tinyint"},{"name":"referenced_table_id","type":"int"},{"name":"referenced_column_name","type":"varchar(64)"},{"name":"json_key_name","type":"varchar(64)"},{"name":"allow_insert","type":"tinyint"},{"name":"allow_update","type":"tinyint"},{"name":"allow_delete","type":"tinyint"},{"name":"read_only","type":"tinyint"}]} +{"catalog":"def","schema":"information_schema","name":"json_duality_view_links","kind":"v","columns":[{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"parent_table_catalog","type":"varchar(64)"},{"name":"parent_table_schema","type":"varchar(64)"},{"name":"parent_table_name","type":"varchar(64)"},{"name":"child_table_catalog","type":"varchar(64)"},{"name":"child_table_schema","type":"varchar(64)"},{"name":"child_table_name","type":"varchar(64)"},{"name":"parent_column_name","type":"varchar(64)"},{"name":"child_column_name","type":"varchar(64)"},{"name":"join_type","type":"varchar(64)"},{"name":"json_key_name","type":"varchar(64)"}]} +{"catalog":"def","schema":"information_schema","name":"json_duality_view_tables","kind":"v","columns":[{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"referenced_table_catalog","type":"varchar(64)"},{"name":"referenced_table_schema","type":"varchar(64)"},{"name":"referenced_table_name","type":"varchar(64)"},{"name":"where_clause","type":"varchar(64)"},{"name":"allow_insert","type":"tinyint"},{"name":"allow_update","type":"tinyint"},{"name":"allow_delete","type":"tinyint"},{"name":"read_only","type":"tinyint"},{"name":"is_root_table","type":"tinyint"},{"name":"referenced_table_id","type":"int"},{"name":"referenced_table_parent_id","type":"int"},{"name":"referenced_table_parent_relationship","type":"varchar(64)"}]} +{"catalog":"def","schema":"information_schema","name":"keywords","kind":"v","columns":[{"name":"word","type":"varchar(128)"},{"name":"reserved","type":"int"}]} +{"catalog":"def","schema":"information_schema","name":"key_column_usage","kind":"v","columns":[{"name":"constraint_catalog","type":"varchar(64)","not_null":true},{"name":"constraint_schema","type":"varchar(64)","not_null":true},{"name":"constraint_name","type":"varchar(64)"},{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"column_name","type":"varchar(64)"},{"name":"ordinal_position","type":"int unsigned","not_null":true},{"name":"position_in_unique_constraint","type":"int unsigned"},{"name":"referenced_table_schema","type":"varchar(64)"},{"name":"referenced_table_name","type":"varchar(64)"},{"name":"referenced_column_name","type":"varchar(64)"}]} +{"catalog":"def","schema":"information_schema","name":"libraries","kind":"v","columns":[{"name":"library_catalog","type":"varchar(64)","not_null":true},{"name":"library_schema","type":"varchar(64)","not_null":true},{"name":"library_name","type":"varchar(64)","not_null":true},{"name":"library_definition","type":"longtext"},{"name":"language","type":"varchar(64)","not_null":true},{"name":"created","type":"timestamp","not_null":true},{"name":"last_altered","type":"timestamp","not_null":true},{"name":"sql_mode","type":"set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES','IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION','NO_DIR_IN_CREATE','NOT_USED_9','NOT_USED_10','NOT_USED_11','NOT_USED_12','NOT_USED_13','NOT_USED_14','NOT_USED_15','NOT_USED_16','NOT_USED_17','NOT_USED_18','ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES','STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','ALLOW_INVALID_DATES','ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NOT_USED_29','HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LENGTH','TIME_TRUNCATE_FRACTIONAL','INTERPRET_UTF8_AS_UTF8MB4')","not_null":true},{"name":"library_comment","type":"text","not_null":true},{"name":"creator","type":"varchar(288)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"optimizer_trace","kind":"v","columns":[{"name":"query","type":"varchar(65535)","not_null":true},{"name":"trace","type":"varchar(65535)","not_null":true},{"name":"missing_bytes_beyond_max_mem_size","type":"int","not_null":true},{"name":"insufficient_privileges","type":"tinyint(1)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"parameters","kind":"v","columns":[{"name":"specific_catalog","type":"varchar(64)","not_null":true},{"name":"specific_schema","type":"varchar(64)","not_null":true},{"name":"specific_name","type":"varchar(64)","not_null":true},{"name":"ordinal_position","type":"bigint unsigned","not_null":true},{"name":"parameter_mode","type":"varchar(5)"},{"name":"parameter_name","type":"varchar(64)"},{"name":"data_type","type":"longtext"},{"name":"character_maximum_length","type":"bigint"},{"name":"character_octet_length","type":"bigint"},{"name":"numeric_precision","type":"int unsigned"},{"name":"numeric_scale","type":"bigint"},{"name":"datetime_precision","type":"int unsigned"},{"name":"character_set_name","type":"varchar(64)"},{"name":"collation_name","type":"varchar(64)"},{"name":"dtd_identifier","type":"mediumtext","not_null":true},{"name":"routine_type","type":"enum('FUNCTION','PROCEDURE','LIBRARY')","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"partitions","kind":"v","columns":[{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"partition_name","type":"varchar(64)"},{"name":"subpartition_name","type":"varchar(64)"},{"name":"partition_ordinal_position","type":"int unsigned"},{"name":"subpartition_ordinal_position","type":"int unsigned"},{"name":"secondary_load","type":"varchar(1)"},{"name":"partition_method","type":"varchar(13)"},{"name":"subpartition_method","type":"varchar(13)"},{"name":"partition_expression","type":"varchar(2048)"},{"name":"subpartition_expression","type":"varchar(2048)"},{"name":"partition_description","type":"text"},{"name":"table_rows","type":"bigint unsigned"},{"name":"avg_row_length","type":"bigint unsigned"},{"name":"data_length","type":"bigint unsigned"},{"name":"max_data_length","type":"bigint unsigned"},{"name":"index_length","type":"bigint unsigned"},{"name":"data_free","type":"bigint unsigned"},{"name":"create_time","type":"timestamp","not_null":true},{"name":"update_time","type":"datetime"},{"name":"check_time","type":"datetime"},{"name":"checksum","type":"bigint"},{"name":"partition_comment","type":"text","not_null":true},{"name":"nodegroup","type":"varchar(256)"},{"name":"tablespace_name","type":"varchar(268)"}]} +{"catalog":"def","schema":"information_schema","name":"plugins","kind":"v","columns":[{"name":"plugin_name","type":"varchar(64)","not_null":true},{"name":"plugin_version","type":"varchar(20)","not_null":true},{"name":"plugin_status","type":"varchar(10)","not_null":true},{"name":"plugin_type","type":"varchar(80)","not_null":true},{"name":"plugin_type_version","type":"varchar(20)","not_null":true},{"name":"plugin_library","type":"varchar(64)"},{"name":"plugin_library_version","type":"varchar(20)"},{"name":"plugin_author","type":"varchar(64)"},{"name":"plugin_description","type":"varchar(65535)"},{"name":"plugin_license","type":"varchar(80)"},{"name":"load_option","type":"varchar(64)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"processlist","kind":"v","columns":[{"name":"id","type":"bigint unsigned","not_null":true},{"name":"user","type":"varchar(32)","not_null":true},{"name":"host","type":"varchar(261)","not_null":true},{"name":"db","type":"varchar(64)"},{"name":"command","type":"varchar(16)","not_null":true},{"name":"time","type":"int","not_null":true},{"name":"state","type":"varchar(64)"},{"name":"info","type":"varchar(65535)"}]} +{"catalog":"def","schema":"information_schema","name":"profiling","kind":"v","columns":[{"name":"query_id","type":"int","not_null":true},{"name":"seq","type":"int","not_null":true},{"name":"state","type":"varchar(30)","not_null":true},{"name":"duration","type":"decimal(905,0)","not_null":true},{"name":"cpu_user","type":"decimal(905,0)"},{"name":"cpu_system","type":"decimal(905,0)"},{"name":"context_voluntary","type":"int"},{"name":"context_involuntary","type":"int"},{"name":"block_ops_in","type":"int"},{"name":"block_ops_out","type":"int"},{"name":"messages_sent","type":"int"},{"name":"messages_received","type":"int"},{"name":"page_faults_major","type":"int"},{"name":"page_faults_minor","type":"int"},{"name":"swaps","type":"int"},{"name":"source_function","type":"varchar(30)"},{"name":"source_file","type":"varchar(20)"},{"name":"source_line","type":"int"}]} +{"catalog":"def","schema":"information_schema","name":"referential_constraints","kind":"v","columns":[{"name":"constraint_catalog","type":"varchar(64)","not_null":true},{"name":"constraint_schema","type":"varchar(64)","not_null":true},{"name":"constraint_name","type":"varchar(64)"},{"name":"unique_constraint_catalog","type":"varchar(64)","not_null":true},{"name":"unique_constraint_schema","type":"varchar(64)","not_null":true},{"name":"unique_constraint_name","type":"varchar(64)"},{"name":"match_option","type":"enum('NONE','PARTIAL','FULL')","not_null":true},{"name":"update_rule","type":"enum('NO ACTION','RESTRICT','CASCADE','SET NULL','SET DEFAULT')","not_null":true},{"name":"delete_rule","type":"enum('NO ACTION','RESTRICT','CASCADE','SET NULL','SET DEFAULT')","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"referenced_table_name","type":"varchar(64)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"resource_groups","kind":"v","columns":[{"name":"resource_group_name","type":"varchar(64)","not_null":true},{"name":"resource_group_type","type":"enum('SYSTEM','USER')","not_null":true},{"name":"resource_group_enabled","type":"tinyint(1)","not_null":true},{"name":"vcpu_ids","type":"blob"},{"name":"thread_priority","type":"int","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"role_column_grants","kind":"v","columns":[{"name":"grantor","type":"varchar(97)"},{"name":"grantor_host","type":"varchar(256)"},{"name":"grantee","type":"char(32)","not_null":true},{"name":"grantee_host","type":"char(255)","not_null":true},{"name":"table_catalog","type":"varchar(3)","not_null":true},{"name":"table_schema","type":"char(64)","not_null":true},{"name":"table_name","type":"char(64)","not_null":true},{"name":"column_name","type":"char(64)","not_null":true},{"name":"privilege_type","type":"set('Select','Insert','Update','References')","not_null":true},{"name":"is_grantable","type":"varchar(3)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"role_routine_grants","kind":"v","columns":[{"name":"grantor","type":"varchar(97)"},{"name":"grantor_host","type":"varchar(256)"},{"name":"grantee","type":"char(32)","not_null":true},{"name":"grantee_host","type":"char(255)","not_null":true},{"name":"specific_catalog","type":"varchar(3)","not_null":true},{"name":"specific_schema","type":"char(64)","not_null":true},{"name":"specific_name","type":"char(64)","not_null":true},{"name":"routine_catalog","type":"varchar(3)","not_null":true},{"name":"routine_schema","type":"char(64)","not_null":true},{"name":"routine_name","type":"char(64)","not_null":true},{"name":"privilege_type","type":"set('Execute','Alter Routine','Grant')","not_null":true},{"name":"is_grantable","type":"varchar(3)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"role_table_grants","kind":"v","columns":[{"name":"grantor","type":"varchar(97)"},{"name":"grantor_host","type":"varchar(256)"},{"name":"grantee","type":"char(32)","not_null":true},{"name":"grantee_host","type":"char(255)","not_null":true},{"name":"table_catalog","type":"varchar(3)","not_null":true},{"name":"table_schema","type":"char(64)","not_null":true},{"name":"table_name","type":"char(64)","not_null":true},{"name":"privilege_type","type":"set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view','Trigger')","not_null":true},{"name":"is_grantable","type":"varchar(3)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"routines","kind":"v","columns":[{"name":"specific_name","type":"varchar(64)","not_null":true},{"name":"routine_catalog","type":"varchar(64)","not_null":true},{"name":"routine_schema","type":"varchar(64)","not_null":true},{"name":"routine_name","type":"varchar(64)","not_null":true},{"name":"routine_type","type":"enum('FUNCTION','PROCEDURE','LIBRARY')","not_null":true},{"name":"data_type","type":"longtext"},{"name":"character_maximum_length","type":"bigint"},{"name":"character_octet_length","type":"bigint"},{"name":"numeric_precision","type":"int unsigned"},{"name":"numeric_scale","type":"int unsigned"},{"name":"datetime_precision","type":"int unsigned"},{"name":"character_set_name","type":"varchar(64)"},{"name":"collation_name","type":"varchar(64)"},{"name":"dtd_identifier","type":"longtext"},{"name":"routine_body","type":"varchar(8)","not_null":true},{"name":"routine_definition","type":"longtext"},{"name":"external_name","type":"varbinary(0)"},{"name":"external_language","type":"varchar(64)","not_null":true},{"name":"parameter_style","type":"varchar(3)","not_null":true},{"name":"is_deterministic","type":"varchar(3)","not_null":true},{"name":"sql_data_access","type":"enum('CONTAINS SQL','NO SQL','READS SQL DATA','MODIFIES SQL DATA')","not_null":true},{"name":"sql_path","type":"varbinary(0)"},{"name":"security_type","type":"enum('DEFAULT','INVOKER','DEFINER')","not_null":true},{"name":"created","type":"timestamp","not_null":true},{"name":"last_altered","type":"timestamp","not_null":true},{"name":"sql_mode","type":"set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES','IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION','NO_DIR_IN_CREATE','NOT_USED_9','NOT_USED_10','NOT_USED_11','NOT_USED_12','NOT_USED_13','NOT_USED_14','NOT_USED_15','NOT_USED_16','NOT_USED_17','NOT_USED_18','ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES','STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','ALLOW_INVALID_DATES','ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NOT_USED_29','HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LENGTH','TIME_TRUNCATE_FRACTIONAL','INTERPRET_UTF8_AS_UTF8MB4')","not_null":true},{"name":"routine_comment","type":"text","not_null":true},{"name":"definer","type":"varchar(288)","not_null":true},{"name":"character_set_client","type":"varchar(64)","not_null":true},{"name":"collation_connection","type":"varchar(64)","not_null":true},{"name":"database_collation","type":"varchar(64)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"routine_libraries","kind":"v","columns":[{"name":"routine_catalog","type":"varchar(64)","not_null":true},{"name":"routine_schema","type":"varchar(64)","not_null":true},{"name":"routine_name","type":"varchar(64)","not_null":true},{"name":"routine_type","type":"enum('FUNCTION','PROCEDURE','LIBRARY')","not_null":true},{"name":"library_catalog","type":"varchar(64)"},{"name":"library_schema","type":"varchar(100)"},{"name":"library_name","type":"varchar(100)"},{"name":"library_version","type":"varchar(100)"}]} +{"catalog":"def","schema":"information_schema","name":"schemata","kind":"v","columns":[{"name":"catalog_name","type":"varchar(64)","not_null":true},{"name":"schema_name","type":"varchar(64)","not_null":true},{"name":"default_character_set_name","type":"varchar(64)","not_null":true},{"name":"default_collation_name","type":"varchar(64)","not_null":true},{"name":"sql_path","type":"varbinary(0)"},{"name":"default_encryption","type":"enum('NO','YES')","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"schemata_extensions","kind":"v","columns":[{"name":"catalog_name","type":"varchar(64)","not_null":true},{"name":"schema_name","type":"varchar(64)","not_null":true},{"name":"options","type":"varchar(256)"}]} +{"catalog":"def","schema":"information_schema","name":"schema_privileges","kind":"v","columns":[{"name":"grantee","type":"varchar(292)","not_null":true},{"name":"table_catalog","type":"varchar(512)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"privilege_type","type":"varchar(64)","not_null":true},{"name":"is_grantable","type":"varchar(3)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"statistics","kind":"v","columns":[{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"non_unique","type":"int","not_null":true},{"name":"index_schema","type":"varchar(64)","not_null":true},{"name":"index_name","type":"varchar(64)"},{"name":"seq_in_index","type":"int unsigned","not_null":true},{"name":"column_name","type":"varchar(64)"},{"name":"collation","type":"varchar(1)"},{"name":"cardinality","type":"bigint"},{"name":"sub_part","type":"bigint"},{"name":"packed","type":"varbinary(0)"},{"name":"nullable","type":"varchar(3)","not_null":true},{"name":"index_type","type":"varchar(11)","not_null":true},{"name":"comment","type":"varchar(8)","not_null":true},{"name":"index_comment","type":"varchar(2048)","not_null":true},{"name":"is_visible","type":"varchar(3)","not_null":true},{"name":"expression","type":"longtext"}]} +{"catalog":"def","schema":"information_schema","name":"st_geometry_columns","kind":"v","columns":[{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"column_name","type":"varchar(64)"},{"name":"srs_name","type":"varchar(80)"},{"name":"srs_id","type":"int unsigned"},{"name":"geometry_type_name","type":"longtext"}]} +{"catalog":"def","schema":"information_schema","name":"st_spatial_reference_systems","kind":"v","columns":[{"name":"srs_name","type":"varchar(80)","not_null":true},{"name":"srs_id","type":"int unsigned","not_null":true},{"name":"organization","type":"varchar(256)"},{"name":"organization_coordsys_id","type":"int unsigned"},{"name":"definition","type":"varchar(4096)","not_null":true},{"name":"description","type":"varchar(2048)"}]} +{"catalog":"def","schema":"information_schema","name":"st_units_of_measure","kind":"v","columns":[{"name":"unit_name","type":"varchar(255)"},{"name":"unit_type","type":"varchar(7)"},{"name":"conversion_factor","type":"double"},{"name":"description","type":"varchar(255)"}]} +{"catalog":"def","schema":"information_schema","name":"tables","kind":"v","columns":[{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"table_type","type":"enum('BASE TABLE','VIEW','SYSTEM VIEW')","not_null":true},{"name":"engine","type":"varchar(64)"},{"name":"version","type":"int"},{"name":"row_format","type":"enum('Fixed','Dynamic','Compressed','Redundant','Compact','Paged')"},{"name":"table_rows","type":"bigint unsigned"},{"name":"avg_row_length","type":"bigint unsigned"},{"name":"data_length","type":"bigint unsigned"},{"name":"max_data_length","type":"bigint unsigned"},{"name":"index_length","type":"bigint unsigned"},{"name":"data_free","type":"bigint unsigned"},{"name":"auto_increment","type":"bigint unsigned"},{"name":"create_time","type":"timestamp","not_null":true},{"name":"update_time","type":"datetime"},{"name":"check_time","type":"datetime"},{"name":"table_collation","type":"varchar(64)"},{"name":"checksum","type":"bigint"},{"name":"create_options","type":"varchar(256)"},{"name":"table_comment","type":"text"}]} +{"catalog":"def","schema":"information_schema","name":"tablespaces_extensions","kind":"v","columns":[{"name":"tablespace_name","type":"varchar(268)","not_null":true},{"name":"engine_attribute","type":"json"}]} +{"catalog":"def","schema":"information_schema","name":"tables_extensions","kind":"v","columns":[{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"engine_attribute","type":"json"},{"name":"secondary_engine_attribute","type":"json"}]} +{"catalog":"def","schema":"information_schema","name":"table_constraints","kind":"v","columns":[{"name":"constraint_catalog","type":"varchar(64)","not_null":true},{"name":"constraint_schema","type":"varchar(64)","not_null":true},{"name":"constraint_name","type":"varchar(64)"},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"constraint_type","type":"varchar(11)","not_null":true},{"name":"enforced","type":"varchar(3)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"table_constraints_extensions","kind":"v","columns":[{"name":"constraint_catalog","type":"varchar(64)","not_null":true},{"name":"constraint_schema","type":"varchar(64)","not_null":true},{"name":"constraint_name","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"engine_attribute","type":"json"},{"name":"secondary_engine_attribute","type":"json"}]} +{"catalog":"def","schema":"information_schema","name":"table_privileges","kind":"v","columns":[{"name":"grantee","type":"varchar(292)","not_null":true},{"name":"table_catalog","type":"varchar(512)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"privilege_type","type":"varchar(64)","not_null":true},{"name":"is_grantable","type":"varchar(3)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"triggers","kind":"v","columns":[{"name":"trigger_catalog","type":"varchar(64)","not_null":true},{"name":"trigger_schema","type":"varchar(64)","not_null":true},{"name":"trigger_name","type":"varchar(64)","not_null":true},{"name":"event_manipulation","type":"enum('INSERT','UPDATE','DELETE')","not_null":true},{"name":"event_object_catalog","type":"varchar(64)","not_null":true},{"name":"event_object_schema","type":"varchar(64)","not_null":true},{"name":"event_object_table","type":"varchar(64)","not_null":true},{"name":"action_order","type":"int unsigned","not_null":true},{"name":"action_condition","type":"varbinary(0)"},{"name":"action_statement","type":"longtext","not_null":true},{"name":"action_orientation","type":"varchar(3)","not_null":true},{"name":"action_timing","type":"enum('BEFORE','AFTER')","not_null":true},{"name":"action_reference_old_table","type":"varbinary(0)"},{"name":"action_reference_new_table","type":"varbinary(0)"},{"name":"action_reference_old_row","type":"varchar(3)","not_null":true},{"name":"action_reference_new_row","type":"varchar(3)","not_null":true},{"name":"created","type":"timestamp(2)","not_null":true},{"name":"sql_mode","type":"set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES','IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION','NO_DIR_IN_CREATE','NOT_USED_9','NOT_USED_10','NOT_USED_11','NOT_USED_12','NOT_USED_13','NOT_USED_14','NOT_USED_15','NOT_USED_16','NOT_USED_17','NOT_USED_18','ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES','STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','ALLOW_INVALID_DATES','ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NOT_USED_29','HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LENGTH','TIME_TRUNCATE_FRACTIONAL','INTERPRET_UTF8_AS_UTF8MB4')","not_null":true},{"name":"definer","type":"varchar(288)","not_null":true},{"name":"character_set_client","type":"varchar(64)","not_null":true},{"name":"collation_connection","type":"varchar(64)","not_null":true},{"name":"database_collation","type":"varchar(64)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"user_attributes","kind":"v","columns":[{"name":"user","type":"char(32)","not_null":true},{"name":"host","type":"char(255)","not_null":true},{"name":"attribute","type":"longtext"}]} +{"catalog":"def","schema":"information_schema","name":"user_privileges","kind":"v","columns":[{"name":"grantee","type":"varchar(292)","not_null":true},{"name":"table_catalog","type":"varchar(512)","not_null":true},{"name":"privilege_type","type":"varchar(64)","not_null":true},{"name":"is_grantable","type":"varchar(3)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"views","kind":"v","columns":[{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"view_definition","type":"longtext"},{"name":"check_option","type":"enum('NONE','LOCAL','CASCADED')"},{"name":"is_updatable","type":"enum('NO','YES')"},{"name":"definer","type":"varchar(288)"},{"name":"security_type","type":"varchar(7)"},{"name":"character_set_client","type":"varchar(64)","not_null":true},{"name":"collation_connection","type":"varchar(64)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"view_routine_usage","kind":"v","columns":[{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"specific_catalog","type":"varchar(64)","not_null":true},{"name":"specific_schema","type":"varchar(64)","not_null":true},{"name":"specific_name","type":"varchar(64)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"view_table_usage","kind":"v","columns":[{"name":"view_catalog","type":"varchar(64)","not_null":true},{"name":"view_schema","type":"varchar(64)","not_null":true},{"name":"view_name","type":"varchar(64)","not_null":true},{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true}]} diff --git a/internal/engine/dolphin/dialect/types.jsonl b/internal/engine/dolphin/dialect/types.jsonl index 9b0d0c7192..c76d29d28a 100644 --- a/internal/engine/dolphin/dialect/types.jsonl +++ b/internal/engine/dolphin/dialect/types.jsonl @@ -1,12 +1,20 @@ {"name": "bool", "category": "B", "aliases": ["boolean"]} -{"name": "tinyint", "category": "N", "aliases": ["tinyint unsigned"]} -{"name": "smallint", "category": "N", "aliases": ["smallint unsigned"]} -{"name": "mediumint", "category": "N", "aliases": ["mediumint unsigned"]} -{"name": "int", "category": "N", "aliases": ["integer", "int unsigned"]} -{"name": "bigint", "category": "N", "aliases": ["signed", "unsigned", "bigint unsigned"]} -{"name": "float", "category": "N", "aliases": ["float unsigned"]} -{"name": "double", "category": "N", "aliases": ["double precision", "real", "double unsigned"]} -{"name": "decimal", "category": "N", "aliases": ["numeric", "dec", "fixed", "decimal unsigned"]} +{"name": "tinyint", "category": "N"} +{"name": "tinyint unsigned", "category": "N", "base": "tinyint"} +{"name": "smallint", "category": "N"} +{"name": "smallint unsigned", "category": "N", "base": "smallint"} +{"name": "mediumint", "category": "N"} +{"name": "mediumint unsigned", "category": "N", "base": "mediumint"} +{"name": "int", "category": "N", "aliases": ["integer"]} +{"name": "int unsigned", "category": "N", "base": "int", "aliases": ["integer unsigned"]} +{"name": "bigint", "category": "N", "aliases": ["signed", "bigint signed"]} +{"name": "bigint unsigned", "category": "N", "base": "bigint", "aliases": ["unsigned"]} +{"name": "float", "category": "N"} +{"name": "float unsigned", "category": "N", "base": "float"} +{"name": "double", "category": "N", "aliases": ["double precision", "real"]} +{"name": "double unsigned", "category": "N", "base": "double", "aliases": ["double precision unsigned", "real unsigned"]} +{"name": "decimal", "category": "N", "aliases": ["numeric", "dec", "fixed"]} +{"name": "decimal unsigned", "category": "N", "base": "decimal", "aliases": ["numeric unsigned", "dec unsigned", "fixed unsigned"]} {"name": "bit", "category": "N"} {"name": "char", "category": "S"} {"name": "varchar", "category": "S"} diff --git a/internal/engine/duckdb/convert.go b/internal/engine/duckdb/convert.go index 03b4b01390..29721bb60d 100644 --- a/internal/engine/duckdb/convert.go +++ b/internal/engine/duckdb/convert.go @@ -812,15 +812,24 @@ func (c *cc) convertWindow(e *dw.WindowExpression) ast.Node { } // convertTypeExpression maps an unbound DuckDB type to a sqlc type name and -// the number of list/array dimensions wrapped around it. +// the number of list/array dimensions wrapped around it, which is what the +// legacy catalog reads. The whole type — its arguments, a struct's fields, +// a map's key and value, the nesting of a list of lists — goes along as +// its spelling, which is what the analysis core reads. func (c *cc) convertTypeExpression(t *dw.TypeExpression) (*ast.TypeName, int) { + typeName, dims := c.elementTypeName(t) + typeName.Canonical = renderTypeExpression(t) + return typeName, dims +} + +func (c *cc) elementTypeName(t *dw.TypeExpression) (*ast.TypeName, int) { name := identifier(t.TypeName) switch name { case "list", "array": // int[] is LIST(INTEGER); int[3] is ARRAY(INTEGER, 3). if len(t.Args) > 0 { if elem, ok := t.Args[0].(*dw.TypeExpression); ok { - typeName, dims := c.convertTypeExpression(elem) + typeName, dims := c.elementTypeName(elem) return typeName, dims + 1 } } @@ -831,6 +840,45 @@ func (c *cc) convertTypeExpression(t *dw.TypeExpression) (*ast.TypeName, int) { }, 0 } +// renderTypeExpression spells a type as a call expression the core reads: +// a list is array applied to its element, a fixed-size array carries its +// size, a struct's or union's fields are labelled, and a constant argument +// is written as it was. +func renderTypeExpression(t *dw.TypeExpression) string { + name := identifier(t.TypeName) + if schema := schemaName(t.Schema); schema != "" { + name = schema + "." + name + } + if name == "list" { + name = "array" + } + if len(t.Args) == 0 { + return name + } + parts := make([]string, 0, len(t.Args)) + for _, arg := range t.Args { + var part string + switch a := arg.(type) { + case *dw.TypeExpression: + part = renderTypeExpression(a) + if a.Alias != "" { + part = identifier(a.Alias) + ": " + part + } + case *dw.ConstantExpression: + switch { + case a.Value.Str != "": + part = "'" + strings.ReplaceAll(a.Value.Str, "'", "''") + "'" + default: + part = strconv.FormatInt(a.Value.Int64, 10) + } + default: + continue + } + parts = append(parts, part) + } + return name + "(" + strings.Join(parts, ", ") + ")" +} + func (c *cc) convertReturning(returning []dw.Expr) *ast.List { if len(returning) == 0 { return nil diff --git a/internal/engine/duckdb/dialect/dialect.json b/internal/engine/duckdb/dialect/dialect.json index e7dbb91524..061007b611 100644 --- a/internal/engine/duckdb/dialect/dialect.json +++ b/internal/engine/duckdb/dialect/dialect.json @@ -1,5 +1,6 @@ { "dialect": "duckdb", + "default_schema": "main", "const": { "integer": "integer", "float": "double", @@ -11,5 +12,15 @@ "comparison_categories": "BNSDU", "arithmetic": ["+", "-", "*", "/", "//", "%", "**", "^"], "arithmetic_categories": "N", - "cast_categories": "NSD" + "cast_categories": "NSD", + "rewrites": [ + { + "from": "varchar($1)", + "to": "varchar" + }, + { + "from": "decimal", + "to": "decimal(18, 3)" + } + ] } diff --git a/internal/engine/googlesql/convert.go b/internal/engine/googlesql/convert.go index e94304096f..cedfe7f090 100644 --- a/internal/engine/googlesql/convert.go +++ b/internal/engine/googlesql/convert.go @@ -452,7 +452,7 @@ func (c *cc) convertExpr(node zjast.Node) ast.Node { case *zjast.CastExpression: return &ast.TypeCast{ Arg: c.convertExpr(n.Expr), - TypeName: &ast.TypeName{Name: typeName(n.Type)}, + TypeName: spelledTypeName(typeName(n.Type)), Location: n.Pos(), } case *zjast.ExpressionSubquery: @@ -918,7 +918,7 @@ func (c *cc) convertCreateTableStatement(n *zjast.CreateTableStatement) ast.Node func (c *cc) convertColumnDefinition(n *zjast.ColumnDefinition) *ast.ColumnDef { col := &ast.ColumnDef{ Location: n.Pos(), - TypeName: &ast.TypeName{Name: columnSchemaTypeName(n.Schema)}, + TypeName: spelledTypeName(columnSchemaTypeName(n.Schema)), } if n.Name != nil { col.Colname = identifier(n.Name.Name) @@ -936,13 +936,6 @@ func (c *cc) convertColumnDefinition(n *zjast.ColumnDefinition) *ast.ColumnDef { } if simple, ok := n.Schema.(*zjast.SimpleColumnSchema); ok { - // Type parameters, e.g. STRING(10) or NUMERIC(10, 2). - if simple.TypeParameters != nil { - col.TypeName.Typmods = &ast.List{} - for _, param := range simple.TypeParameters.Parameters { - col.TypeName.Typmods.Items = append(col.TypeName.Typmods.Items, c.convertExpr(param)) - } - } if simple.DefaultExpression != nil { col.RawDefault = c.convertExpr(simple.DefaultExpression) } @@ -971,3 +964,14 @@ func (c *cc) convertTruncateStatement(n *zjast.TruncateStatement) ast.Node { Relations: &ast.List{Items: []ast.Node{parseRangeVar(n.Target)}}, } } + +// spelledTypeName is a type name the core reads from its spelling, whose +// name is the family the spelling applies: string for string(10), array +// for array(int64). +func spelledTypeName(spelling string) *ast.TypeName { + name := spelling + if i := strings.IndexByte(name, '('); i >= 0 { + name = name[:i] + } + return &ast.TypeName{Name: name, Canonical: spelling} +} diff --git a/internal/engine/googlesql/dialect/dialect.json b/internal/engine/googlesql/dialect/dialect.json index 9fa041c005..728546d80b 100644 --- a/internal/engine/googlesql/dialect/dialect.json +++ b/internal/engine/googlesql/dialect/dialect.json @@ -10,5 +10,6 @@ "comparison": ["=", "<>", "!=", "<", "<=", ">", ">="], "comparison_categories": "BNSDTU", "arithmetic": ["+", "-", "*", "/"], - "arithmetic_categories": "N" + "arithmetic_categories": "N", + "idents": ["max"] } diff --git a/internal/engine/googlesql/dialect/types.jsonl b/internal/engine/googlesql/dialect/types.jsonl index 08fc476b5e..c6d189461e 100644 --- a/internal/engine/googlesql/dialect/types.jsonl +++ b/internal/engine/googlesql/dialect/types.jsonl @@ -18,3 +18,5 @@ {"name": "enum", "category": "U"} {"name": "tokenlist", "category": "U"} {"name": "array", "category": "A"} +{"name": "range", "category": "U"} +{"name": "map", "category": "U"} diff --git a/internal/engine/googlesql/utils.go b/internal/engine/googlesql/utils.go index 002f217c37..0ee4c585d2 100644 --- a/internal/engine/googlesql/utils.go +++ b/internal/engine/googlesql/utils.go @@ -182,33 +182,78 @@ func decodeEscapes(s string) string { // typeName renders a zetajones type node (used by CAST) as a lowercased type // name. Nested types degrade to a readable representation. +// typeName spells a type the way the analysis core reads one: a family +// applied to its arguments, with an array's element, a struct's labelled +// fields, a range's subtype and a map's key and value nested, and a +// parameter list's integers and MAX written as they were. func typeName(node zjast.Node) string { switch t := node.(type) { case *zjast.SimpleType: - return strings.ToLower(strings.Join(pathParts(t.Name), ".")) + return strings.ToLower(strings.Join(pathParts(t.Name), ".")) + typeParameters(t.TypeParameters) case *zjast.ArrayType: - return "array<" + typeName(t.ElementType) + ">" + return "array(" + typeName(t.ElementType) + ")" case *zjast.StructType: - return "struct" + fields := make([]string, 0, len(t.Fields)) + for _, f := range t.Fields { + field := typeName(f.Type) + if f.Name != nil { + field = identifier(f.Name.Name) + ": " + field + } + fields = append(fields, field) + } + return "struct(" + strings.Join(fields, ", ") + ")" case *zjast.RangeType: - return "range<" + typeName(t.ElementType) + ">" + return "range(" + typeName(t.ElementType) + ")" case *zjast.MapType: - return "map" + return "map(" + typeName(t.KeyType) + ", " + typeName(t.ValueType) + ")" default: return "" } } +// typeParameters spells a parameter list, STRING(10) or BYTES(MAX), as the +// arguments of a call. +func typeParameters(params *zjast.TypeParameterList) string { + if params == nil || len(params.Parameters) == 0 { + return "" + } + parts := make([]string, 0, len(params.Parameters)) + for _, p := range params.Parameters { + switch v := p.(type) { + case *zjast.IntLiteral: + parts = append(parts, v.Image) + case *zjast.MaxLiteral: + parts = append(parts, "max") + default: + continue + } + } + if len(parts) == 0 { + return "" + } + return "(" + strings.Join(parts, ", ") + ")" +} + // columnSchemaTypeName renders a CREATE TABLE column schema as a lowercased // type name. Nested types degrade to a readable representation. +// columnSchemaTypeName spells a column's type the way typeName spells a +// type. func columnSchemaTypeName(node zjast.Node) string { switch t := node.(type) { case *zjast.SimpleColumnSchema: - return strings.ToLower(strings.Join(pathParts(t.Type), ".")) + return strings.ToLower(strings.Join(pathParts(t.Type), ".")) + typeParameters(t.TypeParameters) case *zjast.ArrayColumnSchema: - return "array<" + columnSchemaTypeName(t.ElementSchema) + ">" + return "array(" + columnSchemaTypeName(t.ElementSchema) + ")" case *zjast.StructColumnSchema: - return "struct" + fields := make([]string, 0, len(t.Fields)) + for _, f := range t.Fields { + field := columnSchemaTypeName(f.Schema) + if f.Name != nil { + field = identifier(f.Name.Name) + ": " + field + } + fields = append(fields, field) + } + return "struct(" + strings.Join(fields, ", ") + ")" default: return "" } diff --git a/internal/engine/mssql/convert.go b/internal/engine/mssql/convert.go index 6401b7bb88..45b3c8a498 100644 --- a/internal/engine/mssql/convert.go +++ b/internal/engine/mssql/convert.go @@ -63,11 +63,34 @@ func (c *cc) convert(node tsql.Node) ast.Node { return c.convertAlterTableAddTableElementStatement(n) case *tsql.AlterTableDropTableElementStatement: return c.convertAlterTableDropTableElementStatement(n) + case *tsql.CreateTypeUddtStatement: + return c.convertCreateTypeUddtStatement(n) default: return todo(n) } } +// convertCreateTypeUddtStatement reports CREATE TYPE name FROM base [NOT +// NULL] as the domain it is: a type standing on its base that may forbid +// NULL. +func (c *cc) convertCreateTypeUddtStatement(n *tsql.CreateTypeUddtStatement) ast.Node { + if n.Name == nil || n.Name.BaseIdentifier == nil || n.DataType == nil { + return todo(n) + } + stmt := &ast.CreateDomainStmt{ + Domainname: &ast.List{}, + TypeName: dataTypeName(n.DataType), + } + if n.Name.SchemaIdentifier != nil { + stmt.Domainname.Items = append(stmt.Domainname.Items, NewIdentifier(identifierValue(n.Name.SchemaIdentifier))) + } + stmt.Domainname.Items = append(stmt.Domainname.Items, NewIdentifier(identifierValue(n.Name.BaseIdentifier))) + if n.NullableConstraint != nil && !n.NullableConstraint.Nullable { + stmt.Constraints = &ast.List{Items: []ast.Node{&ast.Constraint{Contype: ast.ConstrTypeNotNull}}} + } + return stmt +} + func (c *cc) convertSelectStatement(n *tsql.SelectStatement) ast.Node { stmt := c.convertQueryExpression(n.QueryExpression) sel, ok := stmt.(*ast.SelectStmt) @@ -528,25 +551,25 @@ func (c *cc) convertScalarExpression(expr tsql.ScalarExpression) ast.Node { case *tsql.CastCall: return &ast.TypeCast{ Arg: c.convertScalarExpression(e.Parameter), - TypeName: &ast.TypeName{Name: dataTypeName(e.DataType)}, + TypeName: dataTypeName(e.DataType), Location: c.loc(e), } case *tsql.TryCastCall: return &ast.TypeCast{ Arg: c.convertScalarExpression(e.Parameter), - TypeName: &ast.TypeName{Name: dataTypeName(e.DataType)}, + TypeName: dataTypeName(e.DataType), Location: c.loc(e), } case *tsql.ConvertCall: return &ast.TypeCast{ Arg: c.convertScalarExpression(e.Parameter), - TypeName: &ast.TypeName{Name: dataTypeName(e.DataType)}, + TypeName: dataTypeName(e.DataType), Location: c.loc(e), } case *tsql.TryConvertCall: return &ast.TypeCast{ Arg: c.convertScalarExpression(e.Parameter), - TypeName: &ast.TypeName{Name: dataTypeName(e.DataType)}, + TypeName: dataTypeName(e.DataType), Location: c.loc(e), } case *tsql.CoalesceExpression: @@ -1037,7 +1060,7 @@ func (c *cc) convertColumnDefinition(n *tsql.ColumnDefinition, tablePrimaryKey m name := identifierValue(n.ColumnIdentifier) colDef := &ast.ColumnDef{ Colname: name, - TypeName: &ast.TypeName{Name: dataTypeName(n.DataType)}, + TypeName: dataTypeName(n.DataType), Location: c.loc(n), } @@ -1071,21 +1094,46 @@ func (c *cc) convertColumnDefinition(n *tsql.ColumnDefinition, tablePrimaryKey m // dataTypeName returns the lowercased base name of a column's declared type, // e.g. "nvarchar" for NVARCHAR(100). Length and precision arguments do not // name distinct types. -func dataTypeName(ref tsql.DataTypeReference) string { +// dataTypeName is a type as the core reads it: its name, qualified by its +// schema for a user-defined type, with its parameters as type modifiers, +// MAX among them as the word it is. +func dataTypeName(ref tsql.DataTypeReference) *ast.TypeName { switch t := ref.(type) { case *tsql.SqlDataTypeReference: + out := &ast.TypeName{Name: identifier(t.SqlDataTypeOption)} if t.Name != nil && t.Name.BaseIdentifier != nil { - return identifierValue(t.Name.BaseIdentifier) + out.Name = identifierValue(t.Name.BaseIdentifier) + } + for _, p := range t.Parameters { + switch v := p.(type) { + case *tsql.IntegerLiteral: + n, _ := strconv.ParseInt(v.Value, 10, 64) + out.Typmods = appendTypmod(out.Typmods, &ast.A_Const{Val: &ast.Integer{Ival: n}}) + case *tsql.MaxLiteral: + out.Typmods = appendTypmod(out.Typmods, &ast.String{Str: "max"}) + } } - return identifier(t.SqlDataTypeOption) + return out case *tsql.XmlDataTypeReference: - return "xml" + return &ast.TypeName{Name: "xml"} case *tsql.UserDataTypeReference: if t.Name != nil && t.Name.BaseIdentifier != nil { - return identifierValue(t.Name.BaseIdentifier) + name := identifierValue(t.Name.BaseIdentifier) + if t.Name.SchemaIdentifier != nil { + name = identifierValue(t.Name.SchemaIdentifier) + "." + name + } + return &ast.TypeName{Name: name} } } - return "" + return &ast.TypeName{} +} + +func appendTypmod(l *ast.List, n ast.Node) *ast.List { + if l == nil { + l = &ast.List{} + } + l.Items = append(l.Items, n) + return l } func (c *cc) convertDropTableStatement(n *tsql.DropTableStatement) ast.Node { diff --git a/internal/engine/mssql/dialect/dialect.json b/internal/engine/mssql/dialect/dialect.json index 88d4088df1..30ea408744 100644 --- a/internal/engine/mssql/dialect/dialect.json +++ b/internal/engine/mssql/dialect/dialect.json @@ -1,5 +1,6 @@ { "dialect": "mssql", + "default_schema": "dbo", "const": { "integer": "int", "float": "float", @@ -11,5 +12,73 @@ "comparison_categories": "NBSD", "arithmetic": ["+", "-", "*", "/", "%"], "arithmetic_categories": "N", - "cast_categories": "NSD" + "cast_categories": "NSD", + "idents": ["max"], + "rewrites": [ + { + "from": "sysname", + "to": "nvarchar(128)" + }, + { + "from": "float($1)", + "to": "real", + "where": "$1 <= 24" + }, + { + "from": "float($1)", + "to": "float" + }, + { + "from": "char", + "to": "char(1)" + }, + { + "from": "varchar", + "to": "varchar(1)" + }, + { + "from": "nchar", + "to": "nchar(1)" + }, + { + "from": "nvarchar", + "to": "nvarchar(1)" + }, + { + "from": "binary", + "to": "binary(1)" + }, + { + "from": "varbinary", + "to": "varbinary(1)" + }, + { + "from": "decimal", + "to": "decimal(18, 0)" + }, + { + "from": "decimal($1)", + "to": "decimal($1, 0)" + }, + { + "from": "numeric", + "to": "numeric(18, 0)" + }, + { + "from": "numeric($1)", + "to": "numeric($1, 0)" + }, + { + "from": "datetime2", + "to": "datetime2(7)" + }, + { + "from": "time", + "to": "time(7)" + }, + { + "from": "datetimeoffset", + "to": "datetimeoffset(7)" + } + ] } diff --git a/internal/engine/postgresql/convert.go b/internal/engine/postgresql/convert.go index 6600ce2151..586ebd7291 100644 --- a/internal/engine/postgresql/convert.go +++ b/internal/engine/postgresql/convert.go @@ -2811,7 +2811,7 @@ func convertTypeName(n *pg.TypeName) *ast.TypeName { if n == nil { return nil } - return &ast.TypeName{ + out := &ast.TypeName{ Names: convertSlice(n.Names), TypeOid: ast.Oid(n.TypeOid), Setof: n.Setof, @@ -2821,6 +2821,43 @@ func convertTypeName(n *pg.TypeName) *ast.TypeName { ArrayBounds: convertSlice(n.ArrayBounds), Location: int(n.Location), } + decodeIntervalTypmods(out) + return out +} + +// decodeIntervalTypmods turns the field mask an interval's first type +// modifier carries — what the parser reports for CAST(x AS interval day to +// second) — into the words format_type prints, as a column definition's +// type does; the full range is dropped. +func decodeIntervalTypmods(tn *ast.TypeName) { + if tn.Typmods == nil || len(tn.Typmods.Items) == 0 || len(tn.Names.Items) == 0 { + return + } + last, ok := tn.Names.Items[len(tn.Names.Items)-1].(*ast.String) + if !ok || last.Str != "interval" { + return + } + c, ok := tn.Typmods.Items[0].(*ast.A_Const) + if !ok { + return + } + mask, ok := c.Val.(*ast.Integer) + if !ok { + return + } + fields, ok := intervalFields[int32(mask.Ival)] + if !ok { + return + } + rest := tn.Typmods.Items[1:] + if fields != "" { + rest = append([]ast.Node{&ast.String{Str: fields}}, rest...) + } + if len(rest) == 0 { + tn.Typmods = nil + return + } + tn.Typmods = &ast.List{Items: rest} } func convertUnlistenStmt(n *pg.UnlistenStmt) *ast.UnlistenStmt { diff --git a/internal/engine/postgresql/dialect/dialect.json b/internal/engine/postgresql/dialect/dialect.json index 2e64c9c571..d8ae14185a 100644 --- a/internal/engine/postgresql/dialect/dialect.json +++ b/internal/engine/postgresql/dialect/dialect.json @@ -1,12 +1,12 @@ { "dialect": "postgresql", "const": { - "integer": "int4", + "integer": "integer", "float": "numeric", "string": "text", - "bool": "bool" + "bool": "boolean" }, - "bool": "bool", + "bool": "boolean", "comparison": ["=", "<>", "!=", "<", "<=", ">", ">=", "IS DISTINCT FROM", "IS NOT DISTINCT FROM"], "comparison_categories": "BNSDTU", "arithmetic": ["+", "-", "*", "/", "%"], diff --git a/internal/engine/postgresql/dialect/relations.jsonl b/internal/engine/postgresql/dialect/relations.jsonl index 3e2127e8a9..b93fada4ac 100644 --- a/internal/engine/postgresql/dialect/relations.jsonl +++ b/internal/engine/postgresql/dialect/relations.jsonl @@ -3,71 +3,71 @@ {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_amop","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"amopfamily","type":"oid","not_null":true,"length":4},{"name":"amoplefttype","type":"oid","not_null":true,"length":4},{"name":"amoprighttype","type":"oid","not_null":true,"length":4},{"name":"amopstrategy","type":"int2","not_null":true,"length":2},{"name":"amoppurpose","type":"char","not_null":true,"length":1},{"name":"amopopr","type":"oid","not_null":true,"length":4},{"name":"amopmethod","type":"oid","not_null":true,"length":4},{"name":"amopsortfamily","type":"oid","not_null":true,"length":4}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_amproc","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"amprocfamily","type":"oid","not_null":true,"length":4},{"name":"amproclefttype","type":"oid","not_null":true,"length":4},{"name":"amprocrighttype","type":"oid","not_null":true,"length":4},{"name":"amprocnum","type":"int2","not_null":true,"length":2},{"name":"amproc","type":"regproc","not_null":true,"length":4}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_attrdef","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"adrelid","type":"oid","not_null":true,"length":4},{"name":"adnum","type":"int2","not_null":true,"length":2},{"name":"adbin","type":"pg_node_tree","not_null":true}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_attribute","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"attrelid","type":"oid","not_null":true,"length":4},{"name":"attname","type":"name","not_null":true,"length":64},{"name":"atttypid","type":"oid","not_null":true,"length":4},{"name":"attlen","type":"int2","not_null":true,"length":2},{"name":"attnum","type":"int2","not_null":true,"length":2},{"name":"attcacheoff","type":"int4","not_null":true,"length":4},{"name":"atttypmod","type":"int4","not_null":true,"length":4},{"name":"attndims","type":"int2","not_null":true,"length":2},{"name":"attbyval","type":"bool","not_null":true,"length":1},{"name":"attalign","type":"char","not_null":true,"length":1},{"name":"attstorage","type":"char","not_null":true,"length":1},{"name":"attcompression","type":"char","not_null":true,"length":1},{"name":"attnotnull","type":"bool","not_null":true,"length":1},{"name":"atthasdef","type":"bool","not_null":true,"length":1},{"name":"atthasmissing","type":"bool","not_null":true,"length":1},{"name":"attidentity","type":"char","not_null":true,"length":1},{"name":"attgenerated","type":"char","not_null":true,"length":1},{"name":"attisdropped","type":"bool","not_null":true,"length":1},{"name":"attislocal","type":"bool","not_null":true,"length":1},{"name":"attinhcount","type":"int2","not_null":true,"length":2},{"name":"attstattarget","type":"int2","not_null":true,"length":2},{"name":"attcollation","type":"oid","not_null":true,"length":4},{"name":"attacl","type":"_aclitem","array":true},{"name":"attoptions","type":"_text","array":true},{"name":"attfdwoptions","type":"_text","array":true},{"name":"attmissingval","type":"anyarray"}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_attribute","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"attrelid","type":"oid","not_null":true,"length":4},{"name":"attname","type":"name","not_null":true,"length":64},{"name":"atttypid","type":"oid","not_null":true,"length":4},{"name":"attlen","type":"int2","not_null":true,"length":2},{"name":"attnum","type":"int2","not_null":true,"length":2},{"name":"attcacheoff","type":"int4","not_null":true,"length":4},{"name":"atttypmod","type":"int4","not_null":true,"length":4},{"name":"attndims","type":"int2","not_null":true,"length":2},{"name":"attbyval","type":"bool","not_null":true,"length":1},{"name":"attalign","type":"char","not_null":true,"length":1},{"name":"attstorage","type":"char","not_null":true,"length":1},{"name":"attcompression","type":"char","not_null":true,"length":1},{"name":"attnotnull","type":"bool","not_null":true,"length":1},{"name":"atthasdef","type":"bool","not_null":true,"length":1},{"name":"atthasmissing","type":"bool","not_null":true,"length":1},{"name":"attidentity","type":"char","not_null":true,"length":1},{"name":"attgenerated","type":"char","not_null":true,"length":1},{"name":"attisdropped","type":"bool","not_null":true,"length":1},{"name":"attislocal","type":"bool","not_null":true,"length":1},{"name":"attinhcount","type":"int2","not_null":true,"length":2},{"name":"attstattarget","type":"int2","not_null":true,"length":2},{"name":"attcollation","type":"oid","not_null":true,"length":4},{"name":"attacl","type":"aclitem","array":true,"length":16},{"name":"attoptions","type":"text","array":true},{"name":"attfdwoptions","type":"text","array":true},{"name":"attmissingval","type":"anyarray"}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_auth_members","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"roleid","type":"oid","not_null":true,"length":4},{"name":"member","type":"oid","not_null":true,"length":4},{"name":"grantor","type":"oid","not_null":true,"length":4},{"name":"admin_option","type":"bool","not_null":true,"length":1},{"name":"inherit_option","type":"bool","not_null":true,"length":1},{"name":"set_option","type":"bool","not_null":true,"length":1}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_authid","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"rolname","type":"name","not_null":true,"length":64},{"name":"rolsuper","type":"bool","not_null":true,"length":1},{"name":"rolinherit","type":"bool","not_null":true,"length":1},{"name":"rolcreaterole","type":"bool","not_null":true,"length":1},{"name":"rolcreatedb","type":"bool","not_null":true,"length":1},{"name":"rolcanlogin","type":"bool","not_null":true,"length":1},{"name":"rolreplication","type":"bool","not_null":true,"length":1},{"name":"rolbypassrls","type":"bool","not_null":true,"length":1},{"name":"rolconnlimit","type":"int4","not_null":true,"length":4},{"name":"rolpassword","type":"text"},{"name":"rolvaliduntil","type":"timestamptz","length":8}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_available_extension_versions","columns":[{"name":"name","type":"name","length":64},{"name":"version","type":"text"},{"name":"installed","type":"bool","length":1},{"name":"superuser","type":"bool","length":1},{"name":"trusted","type":"bool","length":1},{"name":"relocatable","type":"bool","length":1},{"name":"schema","type":"name","length":64},{"name":"requires","type":"_name","array":true},{"name":"comment","type":"text"}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_available_extension_versions","columns":[{"name":"name","type":"name","length":64},{"name":"version","type":"text"},{"name":"installed","type":"bool","length":1},{"name":"superuser","type":"bool","length":1},{"name":"trusted","type":"bool","length":1},{"name":"relocatable","type":"bool","length":1},{"name":"schema","type":"name","length":64},{"name":"requires","type":"name","array":true,"length":64},{"name":"comment","type":"text"}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_available_extensions","columns":[{"name":"name","type":"name","length":64},{"name":"default_version","type":"text"},{"name":"installed_version","type":"text"},{"name":"comment","type":"text"}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_backend_memory_contexts","columns":[{"name":"name","type":"text"},{"name":"ident","type":"text"},{"name":"parent","type":"text"},{"name":"level","type":"int4","length":4},{"name":"total_bytes","type":"int8","length":8},{"name":"total_nblocks","type":"int8","length":8},{"name":"free_bytes","type":"int8","length":8},{"name":"free_chunks","type":"int8","length":8},{"name":"used_bytes","type":"int8","length":8}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_cast","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"castsource","type":"oid","not_null":true,"length":4},{"name":"casttarget","type":"oid","not_null":true,"length":4},{"name":"castfunc","type":"oid","not_null":true,"length":4},{"name":"castcontext","type":"char","not_null":true,"length":1},{"name":"castmethod","type":"char","not_null":true,"length":1}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_class","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"relname","type":"name","not_null":true,"length":64},{"name":"relnamespace","type":"oid","not_null":true,"length":4},{"name":"reltype","type":"oid","not_null":true,"length":4},{"name":"reloftype","type":"oid","not_null":true,"length":4},{"name":"relowner","type":"oid","not_null":true,"length":4},{"name":"relam","type":"oid","not_null":true,"length":4},{"name":"relfilenode","type":"oid","not_null":true,"length":4},{"name":"reltablespace","type":"oid","not_null":true,"length":4},{"name":"relpages","type":"int4","not_null":true,"length":4},{"name":"reltuples","type":"float4","not_null":true,"length":4},{"name":"relallvisible","type":"int4","not_null":true,"length":4},{"name":"reltoastrelid","type":"oid","not_null":true,"length":4},{"name":"relhasindex","type":"bool","not_null":true,"length":1},{"name":"relisshared","type":"bool","not_null":true,"length":1},{"name":"relpersistence","type":"char","not_null":true,"length":1},{"name":"relkind","type":"char","not_null":true,"length":1},{"name":"relnatts","type":"int2","not_null":true,"length":2},{"name":"relchecks","type":"int2","not_null":true,"length":2},{"name":"relhasrules","type":"bool","not_null":true,"length":1},{"name":"relhastriggers","type":"bool","not_null":true,"length":1},{"name":"relhassubclass","type":"bool","not_null":true,"length":1},{"name":"relrowsecurity","type":"bool","not_null":true,"length":1},{"name":"relforcerowsecurity","type":"bool","not_null":true,"length":1},{"name":"relispopulated","type":"bool","not_null":true,"length":1},{"name":"relreplident","type":"char","not_null":true,"length":1},{"name":"relispartition","type":"bool","not_null":true,"length":1},{"name":"relrewrite","type":"oid","not_null":true,"length":4},{"name":"relfrozenxid","type":"xid","not_null":true,"length":4},{"name":"relminmxid","type":"xid","not_null":true,"length":4},{"name":"relacl","type":"_aclitem","array":true},{"name":"reloptions","type":"_text","array":true},{"name":"relpartbound","type":"pg_node_tree"}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_class","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"relname","type":"name","not_null":true,"length":64},{"name":"relnamespace","type":"oid","not_null":true,"length":4},{"name":"reltype","type":"oid","not_null":true,"length":4},{"name":"reloftype","type":"oid","not_null":true,"length":4},{"name":"relowner","type":"oid","not_null":true,"length":4},{"name":"relam","type":"oid","not_null":true,"length":4},{"name":"relfilenode","type":"oid","not_null":true,"length":4},{"name":"reltablespace","type":"oid","not_null":true,"length":4},{"name":"relpages","type":"int4","not_null":true,"length":4},{"name":"reltuples","type":"float4","not_null":true,"length":4},{"name":"relallvisible","type":"int4","not_null":true,"length":4},{"name":"reltoastrelid","type":"oid","not_null":true,"length":4},{"name":"relhasindex","type":"bool","not_null":true,"length":1},{"name":"relisshared","type":"bool","not_null":true,"length":1},{"name":"relpersistence","type":"char","not_null":true,"length":1},{"name":"relkind","type":"char","not_null":true,"length":1},{"name":"relnatts","type":"int2","not_null":true,"length":2},{"name":"relchecks","type":"int2","not_null":true,"length":2},{"name":"relhasrules","type":"bool","not_null":true,"length":1},{"name":"relhastriggers","type":"bool","not_null":true,"length":1},{"name":"relhassubclass","type":"bool","not_null":true,"length":1},{"name":"relrowsecurity","type":"bool","not_null":true,"length":1},{"name":"relforcerowsecurity","type":"bool","not_null":true,"length":1},{"name":"relispopulated","type":"bool","not_null":true,"length":1},{"name":"relreplident","type":"char","not_null":true,"length":1},{"name":"relispartition","type":"bool","not_null":true,"length":1},{"name":"relrewrite","type":"oid","not_null":true,"length":4},{"name":"relfrozenxid","type":"xid","not_null":true,"length":4},{"name":"relminmxid","type":"xid","not_null":true,"length":4},{"name":"relacl","type":"aclitem","array":true,"length":16},{"name":"reloptions","type":"text","array":true},{"name":"relpartbound","type":"pg_node_tree"}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_collation","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"collname","type":"name","not_null":true,"length":64},{"name":"collnamespace","type":"oid","not_null":true,"length":4},{"name":"collowner","type":"oid","not_null":true,"length":4},{"name":"collprovider","type":"char","not_null":true,"length":1},{"name":"collisdeterministic","type":"bool","not_null":true,"length":1},{"name":"collencoding","type":"int4","not_null":true,"length":4},{"name":"collcollate","type":"text"},{"name":"collctype","type":"text"},{"name":"colliculocale","type":"text"},{"name":"collicurules","type":"text"},{"name":"collversion","type":"text"}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_config","columns":[{"name":"name","type":"text"},{"name":"setting","type":"text"}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_constraint","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"conname","type":"name","not_null":true,"length":64},{"name":"connamespace","type":"oid","not_null":true,"length":4},{"name":"contype","type":"char","not_null":true,"length":1},{"name":"condeferrable","type":"bool","not_null":true,"length":1},{"name":"condeferred","type":"bool","not_null":true,"length":1},{"name":"convalidated","type":"bool","not_null":true,"length":1},{"name":"conrelid","type":"oid","not_null":true,"length":4},{"name":"contypid","type":"oid","not_null":true,"length":4},{"name":"conindid","type":"oid","not_null":true,"length":4},{"name":"conparentid","type":"oid","not_null":true,"length":4},{"name":"confrelid","type":"oid","not_null":true,"length":4},{"name":"confupdtype","type":"char","not_null":true,"length":1},{"name":"confdeltype","type":"char","not_null":true,"length":1},{"name":"confmatchtype","type":"char","not_null":true,"length":1},{"name":"conislocal","type":"bool","not_null":true,"length":1},{"name":"coninhcount","type":"int2","not_null":true,"length":2},{"name":"connoinherit","type":"bool","not_null":true,"length":1},{"name":"conkey","type":"_int2","array":true},{"name":"confkey","type":"_int2","array":true},{"name":"conpfeqop","type":"_oid","array":true},{"name":"conppeqop","type":"_oid","array":true},{"name":"conffeqop","type":"_oid","array":true},{"name":"confdelsetcols","type":"_int2","array":true},{"name":"conexclop","type":"_oid","array":true},{"name":"conbin","type":"pg_node_tree"}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_constraint","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"conname","type":"name","not_null":true,"length":64},{"name":"connamespace","type":"oid","not_null":true,"length":4},{"name":"contype","type":"char","not_null":true,"length":1},{"name":"condeferrable","type":"bool","not_null":true,"length":1},{"name":"condeferred","type":"bool","not_null":true,"length":1},{"name":"convalidated","type":"bool","not_null":true,"length":1},{"name":"conrelid","type":"oid","not_null":true,"length":4},{"name":"contypid","type":"oid","not_null":true,"length":4},{"name":"conindid","type":"oid","not_null":true,"length":4},{"name":"conparentid","type":"oid","not_null":true,"length":4},{"name":"confrelid","type":"oid","not_null":true,"length":4},{"name":"confupdtype","type":"char","not_null":true,"length":1},{"name":"confdeltype","type":"char","not_null":true,"length":1},{"name":"confmatchtype","type":"char","not_null":true,"length":1},{"name":"conislocal","type":"bool","not_null":true,"length":1},{"name":"coninhcount","type":"int2","not_null":true,"length":2},{"name":"connoinherit","type":"bool","not_null":true,"length":1},{"name":"conkey","type":"int2","array":true,"length":2},{"name":"confkey","type":"int2","array":true,"length":2},{"name":"conpfeqop","type":"oid","array":true,"length":4},{"name":"conppeqop","type":"oid","array":true,"length":4},{"name":"conffeqop","type":"oid","array":true,"length":4},{"name":"confdelsetcols","type":"int2","array":true,"length":2},{"name":"conexclop","type":"oid","array":true,"length":4},{"name":"conbin","type":"pg_node_tree"}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_conversion","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"conname","type":"name","not_null":true,"length":64},{"name":"connamespace","type":"oid","not_null":true,"length":4},{"name":"conowner","type":"oid","not_null":true,"length":4},{"name":"conforencoding","type":"int4","not_null":true,"length":4},{"name":"contoencoding","type":"int4","not_null":true,"length":4},{"name":"conproc","type":"regproc","not_null":true,"length":4},{"name":"condefault","type":"bool","not_null":true,"length":1}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_cursors","columns":[{"name":"name","type":"text"},{"name":"statement","type":"text"},{"name":"is_holdable","type":"bool","length":1},{"name":"is_binary","type":"bool","length":1},{"name":"is_scrollable","type":"bool","length":1},{"name":"creation_time","type":"timestamptz","length":8}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_database","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"datname","type":"name","not_null":true,"length":64},{"name":"datdba","type":"oid","not_null":true,"length":4},{"name":"encoding","type":"int4","not_null":true,"length":4},{"name":"datlocprovider","type":"char","not_null":true,"length":1},{"name":"datistemplate","type":"bool","not_null":true,"length":1},{"name":"datallowconn","type":"bool","not_null":true,"length":1},{"name":"datconnlimit","type":"int4","not_null":true,"length":4},{"name":"datfrozenxid","type":"xid","not_null":true,"length":4},{"name":"datminmxid","type":"xid","not_null":true,"length":4},{"name":"dattablespace","type":"oid","not_null":true,"length":4},{"name":"datcollate","type":"text","not_null":true},{"name":"datctype","type":"text","not_null":true},{"name":"daticulocale","type":"text"},{"name":"daticurules","type":"text"},{"name":"datcollversion","type":"text"},{"name":"datacl","type":"_aclitem","array":true}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_db_role_setting","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"setdatabase","type":"oid","not_null":true,"length":4},{"name":"setrole","type":"oid","not_null":true,"length":4},{"name":"setconfig","type":"_text","array":true}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_default_acl","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"defaclrole","type":"oid","not_null":true,"length":4},{"name":"defaclnamespace","type":"oid","not_null":true,"length":4},{"name":"defaclobjtype","type":"char","not_null":true,"length":1},{"name":"defaclacl","type":"_aclitem","not_null":true,"array":true}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_database","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"datname","type":"name","not_null":true,"length":64},{"name":"datdba","type":"oid","not_null":true,"length":4},{"name":"encoding","type":"int4","not_null":true,"length":4},{"name":"datlocprovider","type":"char","not_null":true,"length":1},{"name":"datistemplate","type":"bool","not_null":true,"length":1},{"name":"datallowconn","type":"bool","not_null":true,"length":1},{"name":"datconnlimit","type":"int4","not_null":true,"length":4},{"name":"datfrozenxid","type":"xid","not_null":true,"length":4},{"name":"datminmxid","type":"xid","not_null":true,"length":4},{"name":"dattablespace","type":"oid","not_null":true,"length":4},{"name":"datcollate","type":"text","not_null":true},{"name":"datctype","type":"text","not_null":true},{"name":"daticulocale","type":"text"},{"name":"daticurules","type":"text"},{"name":"datcollversion","type":"text"},{"name":"datacl","type":"aclitem","array":true,"length":16}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_db_role_setting","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"setdatabase","type":"oid","not_null":true,"length":4},{"name":"setrole","type":"oid","not_null":true,"length":4},{"name":"setconfig","type":"text","array":true}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_default_acl","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"defaclrole","type":"oid","not_null":true,"length":4},{"name":"defaclnamespace","type":"oid","not_null":true,"length":4},{"name":"defaclobjtype","type":"char","not_null":true,"length":1},{"name":"defaclacl","type":"aclitem","not_null":true,"array":true,"length":16}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_depend","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"classid","type":"oid","not_null":true,"length":4},{"name":"objid","type":"oid","not_null":true,"length":4},{"name":"objsubid","type":"int4","not_null":true,"length":4},{"name":"refclassid","type":"oid","not_null":true,"length":4},{"name":"refobjid","type":"oid","not_null":true,"length":4},{"name":"refobjsubid","type":"int4","not_null":true,"length":4},{"name":"deptype","type":"char","not_null":true,"length":1}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_description","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"objoid","type":"oid","not_null":true,"length":4},{"name":"classoid","type":"oid","not_null":true,"length":4},{"name":"objsubid","type":"int4","not_null":true,"length":4},{"name":"description","type":"text","not_null":true}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_enum","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"enumtypid","type":"oid","not_null":true,"length":4},{"name":"enumsortorder","type":"float4","not_null":true,"length":4},{"name":"enumlabel","type":"name","not_null":true,"length":64}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_event_trigger","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"evtname","type":"name","not_null":true,"length":64},{"name":"evtevent","type":"name","not_null":true,"length":64},{"name":"evtowner","type":"oid","not_null":true,"length":4},{"name":"evtfoid","type":"oid","not_null":true,"length":4},{"name":"evtenabled","type":"char","not_null":true,"length":1},{"name":"evttags","type":"_text","array":true}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_extension","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"extname","type":"name","not_null":true,"length":64},{"name":"extowner","type":"oid","not_null":true,"length":4},{"name":"extnamespace","type":"oid","not_null":true,"length":4},{"name":"extrelocatable","type":"bool","not_null":true,"length":1},{"name":"extversion","type":"text","not_null":true},{"name":"extconfig","type":"_oid","array":true},{"name":"extcondition","type":"_text","array":true}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_event_trigger","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"evtname","type":"name","not_null":true,"length":64},{"name":"evtevent","type":"name","not_null":true,"length":64},{"name":"evtowner","type":"oid","not_null":true,"length":4},{"name":"evtfoid","type":"oid","not_null":true,"length":4},{"name":"evtenabled","type":"char","not_null":true,"length":1},{"name":"evttags","type":"text","array":true}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_extension","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"extname","type":"name","not_null":true,"length":64},{"name":"extowner","type":"oid","not_null":true,"length":4},{"name":"extnamespace","type":"oid","not_null":true,"length":4},{"name":"extrelocatable","type":"bool","not_null":true,"length":1},{"name":"extversion","type":"text","not_null":true},{"name":"extconfig","type":"oid","array":true,"length":4},{"name":"extcondition","type":"text","array":true}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_file_settings","columns":[{"name":"sourcefile","type":"text"},{"name":"sourceline","type":"int4","length":4},{"name":"seqno","type":"int4","length":4},{"name":"name","type":"text"},{"name":"setting","type":"text"},{"name":"applied","type":"bool","length":1},{"name":"error","type":"text"}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_foreign_data_wrapper","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"fdwname","type":"name","not_null":true,"length":64},{"name":"fdwowner","type":"oid","not_null":true,"length":4},{"name":"fdwhandler","type":"oid","not_null":true,"length":4},{"name":"fdwvalidator","type":"oid","not_null":true,"length":4},{"name":"fdwacl","type":"_aclitem","array":true},{"name":"fdwoptions","type":"_text","array":true}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_foreign_server","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"srvname","type":"name","not_null":true,"length":64},{"name":"srvowner","type":"oid","not_null":true,"length":4},{"name":"srvfdw","type":"oid","not_null":true,"length":4},{"name":"srvtype","type":"text"},{"name":"srvversion","type":"text"},{"name":"srvacl","type":"_aclitem","array":true},{"name":"srvoptions","type":"_text","array":true}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_foreign_table","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"ftrelid","type":"oid","not_null":true,"length":4},{"name":"ftserver","type":"oid","not_null":true,"length":4},{"name":"ftoptions","type":"_text","array":true}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_group","columns":[{"name":"groname","type":"name","length":64},{"name":"grosysid","type":"oid","length":4},{"name":"grolist","type":"_oid","array":true}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_hba_file_rules","columns":[{"name":"rule_number","type":"int4","length":4},{"name":"file_name","type":"text"},{"name":"line_number","type":"int4","length":4},{"name":"type","type":"text"},{"name":"database","type":"_text","array":true},{"name":"user_name","type":"_text","array":true},{"name":"address","type":"text"},{"name":"netmask","type":"text"},{"name":"auth_method","type":"text"},{"name":"options","type":"_text","array":true},{"name":"error","type":"text"}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_foreign_data_wrapper","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"fdwname","type":"name","not_null":true,"length":64},{"name":"fdwowner","type":"oid","not_null":true,"length":4},{"name":"fdwhandler","type":"oid","not_null":true,"length":4},{"name":"fdwvalidator","type":"oid","not_null":true,"length":4},{"name":"fdwacl","type":"aclitem","array":true,"length":16},{"name":"fdwoptions","type":"text","array":true}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_foreign_server","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"srvname","type":"name","not_null":true,"length":64},{"name":"srvowner","type":"oid","not_null":true,"length":4},{"name":"srvfdw","type":"oid","not_null":true,"length":4},{"name":"srvtype","type":"text"},{"name":"srvversion","type":"text"},{"name":"srvacl","type":"aclitem","array":true,"length":16},{"name":"srvoptions","type":"text","array":true}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_foreign_table","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"ftrelid","type":"oid","not_null":true,"length":4},{"name":"ftserver","type":"oid","not_null":true,"length":4},{"name":"ftoptions","type":"text","array":true}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_group","columns":[{"name":"groname","type":"name","length":64},{"name":"grosysid","type":"oid","length":4},{"name":"grolist","type":"oid","array":true,"length":4}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_hba_file_rules","columns":[{"name":"rule_number","type":"int4","length":4},{"name":"file_name","type":"text"},{"name":"line_number","type":"int4","length":4},{"name":"type","type":"text"},{"name":"database","type":"text","array":true},{"name":"user_name","type":"text","array":true},{"name":"address","type":"text"},{"name":"netmask","type":"text"},{"name":"auth_method","type":"text"},{"name":"options","type":"text","array":true},{"name":"error","type":"text"}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_ident_file_mappings","columns":[{"name":"map_number","type":"int4","length":4},{"name":"file_name","type":"text"},{"name":"line_number","type":"int4","length":4},{"name":"map_name","type":"text"},{"name":"sys_name","type":"text"},{"name":"pg_username","type":"text"},{"name":"error","type":"text"}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_index","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"indexrelid","type":"oid","not_null":true,"length":4},{"name":"indrelid","type":"oid","not_null":true,"length":4},{"name":"indnatts","type":"int2","not_null":true,"length":2},{"name":"indnkeyatts","type":"int2","not_null":true,"length":2},{"name":"indisunique","type":"bool","not_null":true,"length":1},{"name":"indnullsnotdistinct","type":"bool","not_null":true,"length":1},{"name":"indisprimary","type":"bool","not_null":true,"length":1},{"name":"indisexclusion","type":"bool","not_null":true,"length":1},{"name":"indimmediate","type":"bool","not_null":true,"length":1},{"name":"indisclustered","type":"bool","not_null":true,"length":1},{"name":"indisvalid","type":"bool","not_null":true,"length":1},{"name":"indcheckxmin","type":"bool","not_null":true,"length":1},{"name":"indisready","type":"bool","not_null":true,"length":1},{"name":"indislive","type":"bool","not_null":true,"length":1},{"name":"indisreplident","type":"bool","not_null":true,"length":1},{"name":"indkey","type":"int2vector","not_null":true,"array":true},{"name":"indcollation","type":"oidvector","not_null":true,"array":true},{"name":"indclass","type":"oidvector","not_null":true,"array":true},{"name":"indoption","type":"int2vector","not_null":true,"array":true},{"name":"indexprs","type":"pg_node_tree"},{"name":"indpred","type":"pg_node_tree"}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_index","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"indexrelid","type":"oid","not_null":true,"length":4},{"name":"indrelid","type":"oid","not_null":true,"length":4},{"name":"indnatts","type":"int2","not_null":true,"length":2},{"name":"indnkeyatts","type":"int2","not_null":true,"length":2},{"name":"indisunique","type":"bool","not_null":true,"length":1},{"name":"indnullsnotdistinct","type":"bool","not_null":true,"length":1},{"name":"indisprimary","type":"bool","not_null":true,"length":1},{"name":"indisexclusion","type":"bool","not_null":true,"length":1},{"name":"indimmediate","type":"bool","not_null":true,"length":1},{"name":"indisclustered","type":"bool","not_null":true,"length":1},{"name":"indisvalid","type":"bool","not_null":true,"length":1},{"name":"indcheckxmin","type":"bool","not_null":true,"length":1},{"name":"indisready","type":"bool","not_null":true,"length":1},{"name":"indislive","type":"bool","not_null":true,"length":1},{"name":"indisreplident","type":"bool","not_null":true,"length":1},{"name":"indkey","type":"int2vector","not_null":true},{"name":"indcollation","type":"oidvector","not_null":true},{"name":"indclass","type":"oidvector","not_null":true},{"name":"indoption","type":"int2vector","not_null":true},{"name":"indexprs","type":"pg_node_tree"},{"name":"indpred","type":"pg_node_tree"}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_indexes","columns":[{"name":"schemaname","type":"name","length":64},{"name":"tablename","type":"name","length":64},{"name":"indexname","type":"name","length":64},{"name":"tablespace","type":"name","length":64},{"name":"indexdef","type":"text"}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_inherits","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"inhrelid","type":"oid","not_null":true,"length":4},{"name":"inhparent","type":"oid","not_null":true,"length":4},{"name":"inhseqno","type":"int4","not_null":true,"length":4},{"name":"inhdetachpending","type":"bool","not_null":true,"length":1}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_init_privs","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"objoid","type":"oid","not_null":true,"length":4},{"name":"classoid","type":"oid","not_null":true,"length":4},{"name":"objsubid","type":"int4","not_null":true,"length":4},{"name":"privtype","type":"char","not_null":true,"length":1},{"name":"initprivs","type":"_aclitem","not_null":true,"array":true}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_language","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"lanname","type":"name","not_null":true,"length":64},{"name":"lanowner","type":"oid","not_null":true,"length":4},{"name":"lanispl","type":"bool","not_null":true,"length":1},{"name":"lanpltrusted","type":"bool","not_null":true,"length":1},{"name":"lanplcallfoid","type":"oid","not_null":true,"length":4},{"name":"laninline","type":"oid","not_null":true,"length":4},{"name":"lanvalidator","type":"oid","not_null":true,"length":4},{"name":"lanacl","type":"_aclitem","array":true}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_init_privs","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"objoid","type":"oid","not_null":true,"length":4},{"name":"classoid","type":"oid","not_null":true,"length":4},{"name":"objsubid","type":"int4","not_null":true,"length":4},{"name":"privtype","type":"char","not_null":true,"length":1},{"name":"initprivs","type":"aclitem","not_null":true,"array":true,"length":16}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_language","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"lanname","type":"name","not_null":true,"length":64},{"name":"lanowner","type":"oid","not_null":true,"length":4},{"name":"lanispl","type":"bool","not_null":true,"length":1},{"name":"lanpltrusted","type":"bool","not_null":true,"length":1},{"name":"lanplcallfoid","type":"oid","not_null":true,"length":4},{"name":"laninline","type":"oid","not_null":true,"length":4},{"name":"lanvalidator","type":"oid","not_null":true,"length":4},{"name":"lanacl","type":"aclitem","array":true,"length":16}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_largeobject","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"loid","type":"oid","not_null":true,"length":4},{"name":"pageno","type":"int4","not_null":true,"length":4},{"name":"data","type":"bytea","not_null":true}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_largeobject_metadata","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"lomowner","type":"oid","not_null":true,"length":4},{"name":"lomacl","type":"_aclitem","array":true}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_largeobject_metadata","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"lomowner","type":"oid","not_null":true,"length":4},{"name":"lomacl","type":"aclitem","array":true,"length":16}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_locks","columns":[{"name":"locktype","type":"text"},{"name":"database","type":"oid","length":4},{"name":"relation","type":"oid","length":4},{"name":"page","type":"int4","length":4},{"name":"tuple","type":"int2","length":2},{"name":"virtualxid","type":"text"},{"name":"transactionid","type":"xid","length":4},{"name":"classid","type":"oid","length":4},{"name":"objid","type":"oid","length":4},{"name":"objsubid","type":"int2","length":2},{"name":"virtualtransaction","type":"text"},{"name":"pid","type":"int4","length":4},{"name":"mode","type":"text"},{"name":"granted","type":"bool","length":1},{"name":"fastpath","type":"bool","length":1},{"name":"waitstart","type":"timestamptz","length":8}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_matviews","columns":[{"name":"schemaname","type":"name","length":64},{"name":"matviewname","type":"name","length":64},{"name":"matviewowner","type":"name","length":64},{"name":"tablespace","type":"name","length":64},{"name":"hasindexes","type":"bool","length":1},{"name":"ispopulated","type":"bool","length":1},{"name":"definition","type":"text"}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_namespace","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"nspname","type":"name","not_null":true,"length":64},{"name":"nspowner","type":"oid","not_null":true,"length":4},{"name":"nspacl","type":"_aclitem","array":true}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_namespace","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"nspname","type":"name","not_null":true,"length":64},{"name":"nspowner","type":"oid","not_null":true,"length":4},{"name":"nspacl","type":"aclitem","array":true,"length":16}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_opclass","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"opcmethod","type":"oid","not_null":true,"length":4},{"name":"opcname","type":"name","not_null":true,"length":64},{"name":"opcnamespace","type":"oid","not_null":true,"length":4},{"name":"opcowner","type":"oid","not_null":true,"length":4},{"name":"opcfamily","type":"oid","not_null":true,"length":4},{"name":"opcintype","type":"oid","not_null":true,"length":4},{"name":"opcdefault","type":"bool","not_null":true,"length":1},{"name":"opckeytype","type":"oid","not_null":true,"length":4}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_operator","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"oprname","type":"name","not_null":true,"length":64},{"name":"oprnamespace","type":"oid","not_null":true,"length":4},{"name":"oprowner","type":"oid","not_null":true,"length":4},{"name":"oprkind","type":"char","not_null":true,"length":1},{"name":"oprcanmerge","type":"bool","not_null":true,"length":1},{"name":"oprcanhash","type":"bool","not_null":true,"length":1},{"name":"oprleft","type":"oid","not_null":true,"length":4},{"name":"oprright","type":"oid","not_null":true,"length":4},{"name":"oprresult","type":"oid","not_null":true,"length":4},{"name":"oprcom","type":"oid","not_null":true,"length":4},{"name":"oprnegate","type":"oid","not_null":true,"length":4},{"name":"oprcode","type":"regproc","not_null":true,"length":4},{"name":"oprrest","type":"regproc","not_null":true,"length":4},{"name":"oprjoin","type":"regproc","not_null":true,"length":4}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_opfamily","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"opfmethod","type":"oid","not_null":true,"length":4},{"name":"opfname","type":"name","not_null":true,"length":64},{"name":"opfnamespace","type":"oid","not_null":true,"length":4},{"name":"opfowner","type":"oid","not_null":true,"length":4}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_parameter_acl","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"parname","type":"text","not_null":true},{"name":"paracl","type":"_aclitem","array":true}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_partitioned_table","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"partrelid","type":"oid","not_null":true,"length":4},{"name":"partstrat","type":"char","not_null":true,"length":1},{"name":"partnatts","type":"int2","not_null":true,"length":2},{"name":"partdefid","type":"oid","not_null":true,"length":4},{"name":"partattrs","type":"int2vector","not_null":true,"array":true},{"name":"partclass","type":"oidvector","not_null":true,"array":true},{"name":"partcollation","type":"oidvector","not_null":true,"array":true},{"name":"partexprs","type":"pg_node_tree"}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_policies","columns":[{"name":"schemaname","type":"name","length":64},{"name":"tablename","type":"name","length":64},{"name":"policyname","type":"name","length":64},{"name":"permissive","type":"text"},{"name":"roles","type":"_name","array":true},{"name":"cmd","type":"text"},{"name":"qual","type":"text"},{"name":"with_check","type":"text"}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_policy","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"polname","type":"name","not_null":true,"length":64},{"name":"polrelid","type":"oid","not_null":true,"length":4},{"name":"polcmd","type":"char","not_null":true,"length":1},{"name":"polpermissive","type":"bool","not_null":true,"length":1},{"name":"polroles","type":"_oid","not_null":true,"array":true},{"name":"polqual","type":"pg_node_tree"},{"name":"polwithcheck","type":"pg_node_tree"}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_prepared_statements","columns":[{"name":"name","type":"text"},{"name":"statement","type":"text"},{"name":"prepare_time","type":"timestamptz","length":8},{"name":"parameter_types","type":"_regtype","array":true},{"name":"result_types","type":"_regtype","array":true},{"name":"from_sql","type":"bool","length":1},{"name":"generic_plans","type":"int8","length":8},{"name":"custom_plans","type":"int8","length":8}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_parameter_acl","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"parname","type":"text","not_null":true},{"name":"paracl","type":"aclitem","array":true,"length":16}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_partitioned_table","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"partrelid","type":"oid","not_null":true,"length":4},{"name":"partstrat","type":"char","not_null":true,"length":1},{"name":"partnatts","type":"int2","not_null":true,"length":2},{"name":"partdefid","type":"oid","not_null":true,"length":4},{"name":"partattrs","type":"int2vector","not_null":true},{"name":"partclass","type":"oidvector","not_null":true},{"name":"partcollation","type":"oidvector","not_null":true},{"name":"partexprs","type":"pg_node_tree"}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_policies","columns":[{"name":"schemaname","type":"name","length":64},{"name":"tablename","type":"name","length":64},{"name":"policyname","type":"name","length":64},{"name":"permissive","type":"text"},{"name":"roles","type":"name","array":true,"length":64},{"name":"cmd","type":"text"},{"name":"qual","type":"text"},{"name":"with_check","type":"text"}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_policy","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"polname","type":"name","not_null":true,"length":64},{"name":"polrelid","type":"oid","not_null":true,"length":4},{"name":"polcmd","type":"char","not_null":true,"length":1},{"name":"polpermissive","type":"bool","not_null":true,"length":1},{"name":"polroles","type":"oid","not_null":true,"array":true,"length":4},{"name":"polqual","type":"pg_node_tree"},{"name":"polwithcheck","type":"pg_node_tree"}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_prepared_statements","columns":[{"name":"name","type":"text"},{"name":"statement","type":"text"},{"name":"prepare_time","type":"timestamptz","length":8},{"name":"parameter_types","type":"regtype","array":true,"length":4},{"name":"result_types","type":"regtype","array":true,"length":4},{"name":"from_sql","type":"bool","length":1},{"name":"generic_plans","type":"int8","length":8},{"name":"custom_plans","type":"int8","length":8}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_prepared_xacts","columns":[{"name":"transaction","type":"xid","length":4},{"name":"gid","type":"text"},{"name":"prepared","type":"timestamptz","length":8},{"name":"owner","type":"name","length":64},{"name":"database","type":"name","length":64}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_proc","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"proname","type":"name","not_null":true,"length":64},{"name":"pronamespace","type":"oid","not_null":true,"length":4},{"name":"proowner","type":"oid","not_null":true,"length":4},{"name":"prolang","type":"oid","not_null":true,"length":4},{"name":"procost","type":"float4","not_null":true,"length":4},{"name":"prorows","type":"float4","not_null":true,"length":4},{"name":"provariadic","type":"oid","not_null":true,"length":4},{"name":"prosupport","type":"regproc","not_null":true,"length":4},{"name":"prokind","type":"char","not_null":true,"length":1},{"name":"prosecdef","type":"bool","not_null":true,"length":1},{"name":"proleakproof","type":"bool","not_null":true,"length":1},{"name":"proisstrict","type":"bool","not_null":true,"length":1},{"name":"proretset","type":"bool","not_null":true,"length":1},{"name":"provolatile","type":"char","not_null":true,"length":1},{"name":"proparallel","type":"char","not_null":true,"length":1},{"name":"pronargs","type":"int2","not_null":true,"length":2},{"name":"pronargdefaults","type":"int2","not_null":true,"length":2},{"name":"prorettype","type":"oid","not_null":true,"length":4},{"name":"proargtypes","type":"oidvector","not_null":true,"array":true},{"name":"proallargtypes","type":"_oid","array":true},{"name":"proargmodes","type":"_char","array":true},{"name":"proargnames","type":"_text","array":true},{"name":"proargdefaults","type":"pg_node_tree"},{"name":"protrftypes","type":"_oid","array":true},{"name":"prosrc","type":"text","not_null":true},{"name":"probin","type":"text"},{"name":"prosqlbody","type":"pg_node_tree"},{"name":"proconfig","type":"_text","array":true},{"name":"proacl","type":"_aclitem","array":true}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_proc","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"proname","type":"name","not_null":true,"length":64},{"name":"pronamespace","type":"oid","not_null":true,"length":4},{"name":"proowner","type":"oid","not_null":true,"length":4},{"name":"prolang","type":"oid","not_null":true,"length":4},{"name":"procost","type":"float4","not_null":true,"length":4},{"name":"prorows","type":"float4","not_null":true,"length":4},{"name":"provariadic","type":"oid","not_null":true,"length":4},{"name":"prosupport","type":"regproc","not_null":true,"length":4},{"name":"prokind","type":"char","not_null":true,"length":1},{"name":"prosecdef","type":"bool","not_null":true,"length":1},{"name":"proleakproof","type":"bool","not_null":true,"length":1},{"name":"proisstrict","type":"bool","not_null":true,"length":1},{"name":"proretset","type":"bool","not_null":true,"length":1},{"name":"provolatile","type":"char","not_null":true,"length":1},{"name":"proparallel","type":"char","not_null":true,"length":1},{"name":"pronargs","type":"int2","not_null":true,"length":2},{"name":"pronargdefaults","type":"int2","not_null":true,"length":2},{"name":"prorettype","type":"oid","not_null":true,"length":4},{"name":"proargtypes","type":"oidvector","not_null":true},{"name":"proallargtypes","type":"oid","array":true,"length":4},{"name":"proargmodes","type":"char","array":true,"length":1},{"name":"proargnames","type":"text","array":true},{"name":"proargdefaults","type":"pg_node_tree"},{"name":"protrftypes","type":"oid","array":true,"length":4},{"name":"prosrc","type":"text","not_null":true},{"name":"probin","type":"text"},{"name":"prosqlbody","type":"pg_node_tree"},{"name":"proconfig","type":"text","array":true},{"name":"proacl","type":"aclitem","array":true,"length":16}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_publication","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"pubname","type":"name","not_null":true,"length":64},{"name":"pubowner","type":"oid","not_null":true,"length":4},{"name":"puballtables","type":"bool","not_null":true,"length":1},{"name":"pubinsert","type":"bool","not_null":true,"length":1},{"name":"pubupdate","type":"bool","not_null":true,"length":1},{"name":"pubdelete","type":"bool","not_null":true,"length":1},{"name":"pubtruncate","type":"bool","not_null":true,"length":1},{"name":"pubviaroot","type":"bool","not_null":true,"length":1}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_publication_namespace","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"pnpubid","type":"oid","not_null":true,"length":4},{"name":"pnnspid","type":"oid","not_null":true,"length":4}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_publication_rel","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"prpubid","type":"oid","not_null":true,"length":4},{"name":"prrelid","type":"oid","not_null":true,"length":4},{"name":"prqual","type":"pg_node_tree"},{"name":"prattrs","type":"int2vector","array":true}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_publication_tables","columns":[{"name":"pubname","type":"name","length":64},{"name":"schemaname","type":"name","length":64},{"name":"tablename","type":"name","length":64},{"name":"attnames","type":"_name","array":true},{"name":"rowfilter","type":"text"}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_publication_rel","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"prpubid","type":"oid","not_null":true,"length":4},{"name":"prrelid","type":"oid","not_null":true,"length":4},{"name":"prqual","type":"pg_node_tree"},{"name":"prattrs","type":"int2vector"}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_publication_tables","columns":[{"name":"pubname","type":"name","length":64},{"name":"schemaname","type":"name","length":64},{"name":"tablename","type":"name","length":64},{"name":"attnames","type":"name","array":true,"length":64},{"name":"rowfilter","type":"text"}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_range","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"rngtypid","type":"oid","not_null":true,"length":4},{"name":"rngsubtype","type":"oid","not_null":true,"length":4},{"name":"rngmultitypid","type":"oid","not_null":true,"length":4},{"name":"rngcollation","type":"oid","not_null":true,"length":4},{"name":"rngsubopc","type":"oid","not_null":true,"length":4},{"name":"rngcanonical","type":"regproc","not_null":true,"length":4},{"name":"rngsubdiff","type":"regproc","not_null":true,"length":4}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_replication_origin","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"roident","type":"oid","not_null":true,"length":4},{"name":"roname","type":"text","not_null":true}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_replication_origin_status","columns":[{"name":"local_id","type":"oid","length":4},{"name":"external_id","type":"text"},{"name":"remote_lsn","type":"pg_lsn","length":8},{"name":"local_lsn","type":"pg_lsn","length":8}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_replication_slots","columns":[{"name":"slot_name","type":"name","length":64},{"name":"plugin","type":"name","length":64},{"name":"slot_type","type":"text"},{"name":"datoid","type":"oid","length":4},{"name":"database","type":"name","length":64},{"name":"temporary","type":"bool","length":1},{"name":"active","type":"bool","length":1},{"name":"active_pid","type":"int4","length":4},{"name":"xmin","type":"xid","length":4},{"name":"catalog_xmin","type":"xid","length":4},{"name":"restart_lsn","type":"pg_lsn","length":8},{"name":"confirmed_flush_lsn","type":"pg_lsn","length":8},{"name":"wal_status","type":"text"},{"name":"safe_wal_size","type":"int8","length":8},{"name":"two_phase","type":"bool","length":1},{"name":"conflicting","type":"bool","length":1}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_rewrite","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"rulename","type":"name","not_null":true,"length":64},{"name":"ev_class","type":"oid","not_null":true,"length":4},{"name":"ev_type","type":"char","not_null":true,"length":1},{"name":"ev_enabled","type":"char","not_null":true,"length":1},{"name":"is_instead","type":"bool","not_null":true,"length":1},{"name":"ev_qual","type":"pg_node_tree","not_null":true},{"name":"ev_action","type":"pg_node_tree","not_null":true}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_roles","columns":[{"name":"rolname","type":"name","length":64},{"name":"rolsuper","type":"bool","length":1},{"name":"rolinherit","type":"bool","length":1},{"name":"rolcreaterole","type":"bool","length":1},{"name":"rolcreatedb","type":"bool","length":1},{"name":"rolcanlogin","type":"bool","length":1},{"name":"rolreplication","type":"bool","length":1},{"name":"rolconnlimit","type":"int4","length":4},{"name":"rolpassword","type":"text"},{"name":"rolvaliduntil","type":"timestamptz","length":8},{"name":"rolbypassrls","type":"bool","length":1},{"name":"rolconfig","type":"_text","array":true},{"name":"oid","type":"oid","length":4}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_roles","columns":[{"name":"rolname","type":"name","length":64},{"name":"rolsuper","type":"bool","length":1},{"name":"rolinherit","type":"bool","length":1},{"name":"rolcreaterole","type":"bool","length":1},{"name":"rolcreatedb","type":"bool","length":1},{"name":"rolcanlogin","type":"bool","length":1},{"name":"rolreplication","type":"bool","length":1},{"name":"rolconnlimit","type":"int4","length":4},{"name":"rolpassword","type":"text"},{"name":"rolvaliduntil","type":"timestamptz","length":8},{"name":"rolbypassrls","type":"bool","length":1},{"name":"rolconfig","type":"text","array":true},{"name":"oid","type":"oid","length":4}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_rules","columns":[{"name":"schemaname","type":"name","length":64},{"name":"tablename","type":"name","length":64},{"name":"rulename","type":"name","length":64},{"name":"definition","type":"text"}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_seclabel","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"objoid","type":"oid","not_null":true,"length":4},{"name":"classoid","type":"oid","not_null":true,"length":4},{"name":"objsubid","type":"int4","not_null":true,"length":4},{"name":"provider","type":"text","not_null":true},{"name":"label","type":"text","not_null":true}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_seclabels","columns":[{"name":"objoid","type":"oid","length":4},{"name":"classoid","type":"oid","length":4},{"name":"objsubid","type":"int4","length":4},{"name":"objtype","type":"text"},{"name":"objnamespace","type":"oid","length":4},{"name":"objname","type":"text"},{"name":"provider","type":"text"},{"name":"label","type":"text"}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_sequence","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"seqrelid","type":"oid","not_null":true,"length":4},{"name":"seqtypid","type":"oid","not_null":true,"length":4},{"name":"seqstart","type":"int8","not_null":true,"length":8},{"name":"seqincrement","type":"int8","not_null":true,"length":8},{"name":"seqmax","type":"int8","not_null":true,"length":8},{"name":"seqmin","type":"int8","not_null":true,"length":8},{"name":"seqcache","type":"int8","not_null":true,"length":8},{"name":"seqcycle","type":"bool","not_null":true,"length":1}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_sequences","columns":[{"name":"schemaname","type":"name","length":64},{"name":"sequencename","type":"name","length":64},{"name":"sequenceowner","type":"name","length":64},{"name":"data_type","type":"regtype","length":4},{"name":"start_value","type":"int8","length":8},{"name":"min_value","type":"int8","length":8},{"name":"max_value","type":"int8","length":8},{"name":"increment_by","type":"int8","length":8},{"name":"cycle","type":"bool","length":1},{"name":"cache_size","type":"int8","length":8},{"name":"last_value","type":"int8","length":8}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_settings","columns":[{"name":"name","type":"text"},{"name":"setting","type":"text"},{"name":"unit","type":"text"},{"name":"category","type":"text"},{"name":"short_desc","type":"text"},{"name":"extra_desc","type":"text"},{"name":"context","type":"text"},{"name":"vartype","type":"text"},{"name":"source","type":"text"},{"name":"min_val","type":"text"},{"name":"max_val","type":"text"},{"name":"enumvals","type":"_text","array":true},{"name":"boot_val","type":"text"},{"name":"reset_val","type":"text"},{"name":"sourcefile","type":"text"},{"name":"sourceline","type":"int4","length":4},{"name":"pending_restart","type":"bool","length":1}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_shadow","columns":[{"name":"usename","type":"name","length":64},{"name":"usesysid","type":"oid","length":4},{"name":"usecreatedb","type":"bool","length":1},{"name":"usesuper","type":"bool","length":1},{"name":"userepl","type":"bool","length":1},{"name":"usebypassrls","type":"bool","length":1},{"name":"passwd","type":"text"},{"name":"valuntil","type":"timestamptz","length":8},{"name":"useconfig","type":"_text","array":true}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_settings","columns":[{"name":"name","type":"text"},{"name":"setting","type":"text"},{"name":"unit","type":"text"},{"name":"category","type":"text"},{"name":"short_desc","type":"text"},{"name":"extra_desc","type":"text"},{"name":"context","type":"text"},{"name":"vartype","type":"text"},{"name":"source","type":"text"},{"name":"min_val","type":"text"},{"name":"max_val","type":"text"},{"name":"enumvals","type":"text","array":true},{"name":"boot_val","type":"text"},{"name":"reset_val","type":"text"},{"name":"sourcefile","type":"text"},{"name":"sourceline","type":"int4","length":4},{"name":"pending_restart","type":"bool","length":1}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_shadow","columns":[{"name":"usename","type":"name","length":64},{"name":"usesysid","type":"oid","length":4},{"name":"usecreatedb","type":"bool","length":1},{"name":"usesuper","type":"bool","length":1},{"name":"userepl","type":"bool","length":1},{"name":"usebypassrls","type":"bool","length":1},{"name":"passwd","type":"text"},{"name":"valuntil","type":"timestamptz","length":8},{"name":"useconfig","type":"text","array":true}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_shdepend","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"dbid","type":"oid","not_null":true,"length":4},{"name":"classid","type":"oid","not_null":true,"length":4},{"name":"objid","type":"oid","not_null":true,"length":4},{"name":"objsubid","type":"int4","not_null":true,"length":4},{"name":"refclassid","type":"oid","not_null":true,"length":4},{"name":"refobjid","type":"oid","not_null":true,"length":4},{"name":"deptype","type":"char","not_null":true,"length":1}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_shdescription","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"objoid","type":"oid","not_null":true,"length":4},{"name":"classoid","type":"oid","not_null":true,"length":4},{"name":"description","type":"text","not_null":true}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_shmem_allocations","columns":[{"name":"name","type":"text"},{"name":"off","type":"int8","length":8},{"name":"size","type":"int8","length":8},{"name":"allocated_size","type":"int8","length":8}]} @@ -114,35 +114,35 @@ {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_statio_user_indexes","columns":[{"name":"relid","type":"oid","length":4},{"name":"indexrelid","type":"oid","length":4},{"name":"schemaname","type":"name","length":64},{"name":"relname","type":"name","length":64},{"name":"indexrelname","type":"name","length":64},{"name":"idx_blks_read","type":"int8","length":8},{"name":"idx_blks_hit","type":"int8","length":8}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_statio_user_sequences","columns":[{"name":"relid","type":"oid","length":4},{"name":"schemaname","type":"name","length":64},{"name":"relname","type":"name","length":64},{"name":"blks_read","type":"int8","length":8},{"name":"blks_hit","type":"int8","length":8}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_statio_user_tables","columns":[{"name":"relid","type":"oid","length":4},{"name":"schemaname","type":"name","length":64},{"name":"relname","type":"name","length":64},{"name":"heap_blks_read","type":"int8","length":8},{"name":"heap_blks_hit","type":"int8","length":8},{"name":"idx_blks_read","type":"int8","length":8},{"name":"idx_blks_hit","type":"int8","length":8},{"name":"toast_blks_read","type":"int8","length":8},{"name":"toast_blks_hit","type":"int8","length":8},{"name":"tidx_blks_read","type":"int8","length":8},{"name":"tidx_blks_hit","type":"int8","length":8}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_statistic","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"starelid","type":"oid","not_null":true,"length":4},{"name":"staattnum","type":"int2","not_null":true,"length":2},{"name":"stainherit","type":"bool","not_null":true,"length":1},{"name":"stanullfrac","type":"float4","not_null":true,"length":4},{"name":"stawidth","type":"int4","not_null":true,"length":4},{"name":"stadistinct","type":"float4","not_null":true,"length":4},{"name":"stakind1","type":"int2","not_null":true,"length":2},{"name":"stakind2","type":"int2","not_null":true,"length":2},{"name":"stakind3","type":"int2","not_null":true,"length":2},{"name":"stakind4","type":"int2","not_null":true,"length":2},{"name":"stakind5","type":"int2","not_null":true,"length":2},{"name":"staop1","type":"oid","not_null":true,"length":4},{"name":"staop2","type":"oid","not_null":true,"length":4},{"name":"staop3","type":"oid","not_null":true,"length":4},{"name":"staop4","type":"oid","not_null":true,"length":4},{"name":"staop5","type":"oid","not_null":true,"length":4},{"name":"stacoll1","type":"oid","not_null":true,"length":4},{"name":"stacoll2","type":"oid","not_null":true,"length":4},{"name":"stacoll3","type":"oid","not_null":true,"length":4},{"name":"stacoll4","type":"oid","not_null":true,"length":4},{"name":"stacoll5","type":"oid","not_null":true,"length":4},{"name":"stanumbers1","type":"_float4","array":true},{"name":"stanumbers2","type":"_float4","array":true},{"name":"stanumbers3","type":"_float4","array":true},{"name":"stanumbers4","type":"_float4","array":true},{"name":"stanumbers5","type":"_float4","array":true},{"name":"stavalues1","type":"anyarray"},{"name":"stavalues2","type":"anyarray"},{"name":"stavalues3","type":"anyarray"},{"name":"stavalues4","type":"anyarray"},{"name":"stavalues5","type":"anyarray"}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_statistic_ext","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"stxrelid","type":"oid","not_null":true,"length":4},{"name":"stxname","type":"name","not_null":true,"length":64},{"name":"stxnamespace","type":"oid","not_null":true,"length":4},{"name":"stxowner","type":"oid","not_null":true,"length":4},{"name":"stxstattarget","type":"int4","not_null":true,"length":4},{"name":"stxkeys","type":"int2vector","not_null":true,"array":true},{"name":"stxkind","type":"_char","not_null":true,"array":true},{"name":"stxexprs","type":"pg_node_tree"}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_statistic_ext_data","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"stxoid","type":"oid","not_null":true,"length":4},{"name":"stxdinherit","type":"bool","not_null":true,"length":1},{"name":"stxdndistinct","type":"pg_ndistinct"},{"name":"stxddependencies","type":"pg_dependencies"},{"name":"stxdmcv","type":"pg_mcv_list"},{"name":"stxdexpr","type":"_pg_statistic","array":true}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_stats","columns":[{"name":"schemaname","type":"name","length":64},{"name":"tablename","type":"name","length":64},{"name":"attname","type":"name","length":64},{"name":"inherited","type":"bool","length":1},{"name":"null_frac","type":"float4","length":4},{"name":"avg_width","type":"int4","length":4},{"name":"n_distinct","type":"float4","length":4},{"name":"most_common_vals","type":"anyarray"},{"name":"most_common_freqs","type":"_float4","array":true},{"name":"histogram_bounds","type":"anyarray"},{"name":"correlation","type":"float4","length":4},{"name":"most_common_elems","type":"anyarray"},{"name":"most_common_elem_freqs","type":"_float4","array":true},{"name":"elem_count_histogram","type":"_float4","array":true}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_stats_ext","columns":[{"name":"schemaname","type":"name","length":64},{"name":"tablename","type":"name","length":64},{"name":"statistics_schemaname","type":"name","length":64},{"name":"statistics_name","type":"name","length":64},{"name":"statistics_owner","type":"name","length":64},{"name":"attnames","type":"_name","array":true},{"name":"exprs","type":"_text","array":true},{"name":"kinds","type":"_char","array":true},{"name":"inherited","type":"bool","length":1},{"name":"n_distinct","type":"pg_ndistinct"},{"name":"dependencies","type":"pg_dependencies"},{"name":"most_common_vals","type":"_text","array":true},{"name":"most_common_val_nulls","type":"_bool","array":true},{"name":"most_common_freqs","type":"_float8","array":true},{"name":"most_common_base_freqs","type":"_float8","array":true}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_stats_ext_exprs","columns":[{"name":"schemaname","type":"name","length":64},{"name":"tablename","type":"name","length":64},{"name":"statistics_schemaname","type":"name","length":64},{"name":"statistics_name","type":"name","length":64},{"name":"statistics_owner","type":"name","length":64},{"name":"expr","type":"text"},{"name":"inherited","type":"bool","length":1},{"name":"null_frac","type":"float4","length":4},{"name":"avg_width","type":"int4","length":4},{"name":"n_distinct","type":"float4","length":4},{"name":"most_common_vals","type":"anyarray"},{"name":"most_common_freqs","type":"_float4","array":true},{"name":"histogram_bounds","type":"anyarray"},{"name":"correlation","type":"float4","length":4},{"name":"most_common_elems","type":"anyarray"},{"name":"most_common_elem_freqs","type":"_float4","array":true},{"name":"elem_count_histogram","type":"_float4","array":true}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_subscription","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"subdbid","type":"oid","not_null":true,"length":4},{"name":"subskiplsn","type":"pg_lsn","not_null":true,"length":8},{"name":"subname","type":"name","not_null":true,"length":64},{"name":"subowner","type":"oid","not_null":true,"length":4},{"name":"subenabled","type":"bool","not_null":true,"length":1},{"name":"subbinary","type":"bool","not_null":true,"length":1},{"name":"substream","type":"char","not_null":true,"length":1},{"name":"subtwophasestate","type":"char","not_null":true,"length":1},{"name":"subdisableonerr","type":"bool","not_null":true,"length":1},{"name":"subpasswordrequired","type":"bool","not_null":true,"length":1},{"name":"subrunasowner","type":"bool","not_null":true,"length":1},{"name":"subconninfo","type":"text","not_null":true},{"name":"subslotname","type":"name","length":64},{"name":"subsynccommit","type":"text","not_null":true},{"name":"subpublications","type":"_text","not_null":true,"array":true},{"name":"suborigin","type":"text"}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_statistic","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"starelid","type":"oid","not_null":true,"length":4},{"name":"staattnum","type":"int2","not_null":true,"length":2},{"name":"stainherit","type":"bool","not_null":true,"length":1},{"name":"stanullfrac","type":"float4","not_null":true,"length":4},{"name":"stawidth","type":"int4","not_null":true,"length":4},{"name":"stadistinct","type":"float4","not_null":true,"length":4},{"name":"stakind1","type":"int2","not_null":true,"length":2},{"name":"stakind2","type":"int2","not_null":true,"length":2},{"name":"stakind3","type":"int2","not_null":true,"length":2},{"name":"stakind4","type":"int2","not_null":true,"length":2},{"name":"stakind5","type":"int2","not_null":true,"length":2},{"name":"staop1","type":"oid","not_null":true,"length":4},{"name":"staop2","type":"oid","not_null":true,"length":4},{"name":"staop3","type":"oid","not_null":true,"length":4},{"name":"staop4","type":"oid","not_null":true,"length":4},{"name":"staop5","type":"oid","not_null":true,"length":4},{"name":"stacoll1","type":"oid","not_null":true,"length":4},{"name":"stacoll2","type":"oid","not_null":true,"length":4},{"name":"stacoll3","type":"oid","not_null":true,"length":4},{"name":"stacoll4","type":"oid","not_null":true,"length":4},{"name":"stacoll5","type":"oid","not_null":true,"length":4},{"name":"stanumbers1","type":"float4","array":true,"length":4},{"name":"stanumbers2","type":"float4","array":true,"length":4},{"name":"stanumbers3","type":"float4","array":true,"length":4},{"name":"stanumbers4","type":"float4","array":true,"length":4},{"name":"stanumbers5","type":"float4","array":true,"length":4},{"name":"stavalues1","type":"anyarray"},{"name":"stavalues2","type":"anyarray"},{"name":"stavalues3","type":"anyarray"},{"name":"stavalues4","type":"anyarray"},{"name":"stavalues5","type":"anyarray"}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_statistic_ext","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"stxrelid","type":"oid","not_null":true,"length":4},{"name":"stxname","type":"name","not_null":true,"length":64},{"name":"stxnamespace","type":"oid","not_null":true,"length":4},{"name":"stxowner","type":"oid","not_null":true,"length":4},{"name":"stxstattarget","type":"int4","not_null":true,"length":4},{"name":"stxkeys","type":"int2vector","not_null":true},{"name":"stxkind","type":"char","not_null":true,"array":true,"length":1},{"name":"stxexprs","type":"pg_node_tree"}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_statistic_ext_data","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"stxoid","type":"oid","not_null":true,"length":4},{"name":"stxdinherit","type":"bool","not_null":true,"length":1},{"name":"stxdndistinct","type":"pg_ndistinct"},{"name":"stxddependencies","type":"pg_dependencies"},{"name":"stxdmcv","type":"pg_mcv_list"},{"name":"stxdexpr","type":"pg_statistic","array":true}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_stats","columns":[{"name":"schemaname","type":"name","length":64},{"name":"tablename","type":"name","length":64},{"name":"attname","type":"name","length":64},{"name":"inherited","type":"bool","length":1},{"name":"null_frac","type":"float4","length":4},{"name":"avg_width","type":"int4","length":4},{"name":"n_distinct","type":"float4","length":4},{"name":"most_common_vals","type":"anyarray"},{"name":"most_common_freqs","type":"float4","array":true,"length":4},{"name":"histogram_bounds","type":"anyarray"},{"name":"correlation","type":"float4","length":4},{"name":"most_common_elems","type":"anyarray"},{"name":"most_common_elem_freqs","type":"float4","array":true,"length":4},{"name":"elem_count_histogram","type":"float4","array":true,"length":4}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_stats_ext","columns":[{"name":"schemaname","type":"name","length":64},{"name":"tablename","type":"name","length":64},{"name":"statistics_schemaname","type":"name","length":64},{"name":"statistics_name","type":"name","length":64},{"name":"statistics_owner","type":"name","length":64},{"name":"attnames","type":"name","array":true,"length":64},{"name":"exprs","type":"text","array":true},{"name":"kinds","type":"char","array":true,"length":1},{"name":"inherited","type":"bool","length":1},{"name":"n_distinct","type":"pg_ndistinct"},{"name":"dependencies","type":"pg_dependencies"},{"name":"most_common_vals","type":"text","array":true},{"name":"most_common_val_nulls","type":"bool","array":true,"length":1},{"name":"most_common_freqs","type":"float8","array":true,"length":8},{"name":"most_common_base_freqs","type":"float8","array":true,"length":8}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_stats_ext_exprs","columns":[{"name":"schemaname","type":"name","length":64},{"name":"tablename","type":"name","length":64},{"name":"statistics_schemaname","type":"name","length":64},{"name":"statistics_name","type":"name","length":64},{"name":"statistics_owner","type":"name","length":64},{"name":"expr","type":"text"},{"name":"inherited","type":"bool","length":1},{"name":"null_frac","type":"float4","length":4},{"name":"avg_width","type":"int4","length":4},{"name":"n_distinct","type":"float4","length":4},{"name":"most_common_vals","type":"anyarray"},{"name":"most_common_freqs","type":"float4","array":true,"length":4},{"name":"histogram_bounds","type":"anyarray"},{"name":"correlation","type":"float4","length":4},{"name":"most_common_elems","type":"anyarray"},{"name":"most_common_elem_freqs","type":"float4","array":true,"length":4},{"name":"elem_count_histogram","type":"float4","array":true,"length":4}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_subscription","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"subdbid","type":"oid","not_null":true,"length":4},{"name":"subskiplsn","type":"pg_lsn","not_null":true,"length":8},{"name":"subname","type":"name","not_null":true,"length":64},{"name":"subowner","type":"oid","not_null":true,"length":4},{"name":"subenabled","type":"bool","not_null":true,"length":1},{"name":"subbinary","type":"bool","not_null":true,"length":1},{"name":"substream","type":"char","not_null":true,"length":1},{"name":"subtwophasestate","type":"char","not_null":true,"length":1},{"name":"subdisableonerr","type":"bool","not_null":true,"length":1},{"name":"subpasswordrequired","type":"bool","not_null":true,"length":1},{"name":"subrunasowner","type":"bool","not_null":true,"length":1},{"name":"subconninfo","type":"text","not_null":true},{"name":"subslotname","type":"name","length":64},{"name":"subsynccommit","type":"text","not_null":true},{"name":"subpublications","type":"text","not_null":true,"array":true},{"name":"suborigin","type":"text"}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_subscription_rel","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"srsubid","type":"oid","not_null":true,"length":4},{"name":"srrelid","type":"oid","not_null":true,"length":4},{"name":"srsubstate","type":"char","not_null":true,"length":1},{"name":"srsublsn","type":"pg_lsn","length":8}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_tables","columns":[{"name":"schemaname","type":"name","length":64},{"name":"tablename","type":"name","length":64},{"name":"tableowner","type":"name","length":64},{"name":"tablespace","type":"name","length":64},{"name":"hasindexes","type":"bool","length":1},{"name":"hasrules","type":"bool","length":1},{"name":"hastriggers","type":"bool","length":1},{"name":"rowsecurity","type":"bool","length":1}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_tablespace","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"spcname","type":"name","not_null":true,"length":64},{"name":"spcowner","type":"oid","not_null":true,"length":4},{"name":"spcacl","type":"_aclitem","array":true},{"name":"spcoptions","type":"_text","array":true}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_tablespace","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"spcname","type":"name","not_null":true,"length":64},{"name":"spcowner","type":"oid","not_null":true,"length":4},{"name":"spcacl","type":"aclitem","array":true,"length":16},{"name":"spcoptions","type":"text","array":true}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_timezone_abbrevs","columns":[{"name":"abbrev","type":"text"},{"name":"utc_offset","type":"interval","length":16},{"name":"is_dst","type":"bool","length":1}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_timezone_names","columns":[{"name":"name","type":"text"},{"name":"abbrev","type":"text"},{"name":"utc_offset","type":"interval","length":16},{"name":"is_dst","type":"bool","length":1}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_transform","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"trftype","type":"oid","not_null":true,"length":4},{"name":"trflang","type":"oid","not_null":true,"length":4},{"name":"trffromsql","type":"regproc","not_null":true,"length":4},{"name":"trftosql","type":"regproc","not_null":true,"length":4}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_trigger","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"tgrelid","type":"oid","not_null":true,"length":4},{"name":"tgparentid","type":"oid","not_null":true,"length":4},{"name":"tgname","type":"name","not_null":true,"length":64},{"name":"tgfoid","type":"oid","not_null":true,"length":4},{"name":"tgtype","type":"int2","not_null":true,"length":2},{"name":"tgenabled","type":"char","not_null":true,"length":1},{"name":"tgisinternal","type":"bool","not_null":true,"length":1},{"name":"tgconstrrelid","type":"oid","not_null":true,"length":4},{"name":"tgconstrindid","type":"oid","not_null":true,"length":4},{"name":"tgconstraint","type":"oid","not_null":true,"length":4},{"name":"tgdeferrable","type":"bool","not_null":true,"length":1},{"name":"tginitdeferred","type":"bool","not_null":true,"length":1},{"name":"tgnargs","type":"int2","not_null":true,"length":2},{"name":"tgattr","type":"int2vector","not_null":true,"array":true},{"name":"tgargs","type":"bytea","not_null":true},{"name":"tgqual","type":"pg_node_tree"},{"name":"tgoldtable","type":"name","length":64},{"name":"tgnewtable","type":"name","length":64}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_trigger","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"tgrelid","type":"oid","not_null":true,"length":4},{"name":"tgparentid","type":"oid","not_null":true,"length":4},{"name":"tgname","type":"name","not_null":true,"length":64},{"name":"tgfoid","type":"oid","not_null":true,"length":4},{"name":"tgtype","type":"int2","not_null":true,"length":2},{"name":"tgenabled","type":"char","not_null":true,"length":1},{"name":"tgisinternal","type":"bool","not_null":true,"length":1},{"name":"tgconstrrelid","type":"oid","not_null":true,"length":4},{"name":"tgconstrindid","type":"oid","not_null":true,"length":4},{"name":"tgconstraint","type":"oid","not_null":true,"length":4},{"name":"tgdeferrable","type":"bool","not_null":true,"length":1},{"name":"tginitdeferred","type":"bool","not_null":true,"length":1},{"name":"tgnargs","type":"int2","not_null":true,"length":2},{"name":"tgattr","type":"int2vector","not_null":true},{"name":"tgargs","type":"bytea","not_null":true},{"name":"tgqual","type":"pg_node_tree"},{"name":"tgoldtable","type":"name","length":64},{"name":"tgnewtable","type":"name","length":64}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_ts_config","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"cfgname","type":"name","not_null":true,"length":64},{"name":"cfgnamespace","type":"oid","not_null":true,"length":4},{"name":"cfgowner","type":"oid","not_null":true,"length":4},{"name":"cfgparser","type":"oid","not_null":true,"length":4}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_ts_config_map","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"mapcfg","type":"oid","not_null":true,"length":4},{"name":"maptokentype","type":"int4","not_null":true,"length":4},{"name":"mapseqno","type":"int4","not_null":true,"length":4},{"name":"mapdict","type":"oid","not_null":true,"length":4}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_ts_dict","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"dictname","type":"name","not_null":true,"length":64},{"name":"dictnamespace","type":"oid","not_null":true,"length":4},{"name":"dictowner","type":"oid","not_null":true,"length":4},{"name":"dicttemplate","type":"oid","not_null":true,"length":4},{"name":"dictinitoption","type":"text"}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_ts_parser","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"prsname","type":"name","not_null":true,"length":64},{"name":"prsnamespace","type":"oid","not_null":true,"length":4},{"name":"prsstart","type":"regproc","not_null":true,"length":4},{"name":"prstoken","type":"regproc","not_null":true,"length":4},{"name":"prsend","type":"regproc","not_null":true,"length":4},{"name":"prsheadline","type":"regproc","not_null":true,"length":4},{"name":"prslextype","type":"regproc","not_null":true,"length":4}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_ts_template","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"tmplname","type":"name","not_null":true,"length":64},{"name":"tmplnamespace","type":"oid","not_null":true,"length":4},{"name":"tmplinit","type":"regproc","not_null":true,"length":4},{"name":"tmpllexize","type":"regproc","not_null":true,"length":4}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_type","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"typname","type":"name","not_null":true,"length":64},{"name":"typnamespace","type":"oid","not_null":true,"length":4},{"name":"typowner","type":"oid","not_null":true,"length":4},{"name":"typlen","type":"int2","not_null":true,"length":2},{"name":"typbyval","type":"bool","not_null":true,"length":1},{"name":"typtype","type":"char","not_null":true,"length":1},{"name":"typcategory","type":"char","not_null":true,"length":1},{"name":"typispreferred","type":"bool","not_null":true,"length":1},{"name":"typisdefined","type":"bool","not_null":true,"length":1},{"name":"typdelim","type":"char","not_null":true,"length":1},{"name":"typrelid","type":"oid","not_null":true,"length":4},{"name":"typsubscript","type":"regproc","not_null":true,"length":4},{"name":"typelem","type":"oid","not_null":true,"length":4},{"name":"typarray","type":"oid","not_null":true,"length":4},{"name":"typinput","type":"regproc","not_null":true,"length":4},{"name":"typoutput","type":"regproc","not_null":true,"length":4},{"name":"typreceive","type":"regproc","not_null":true,"length":4},{"name":"typsend","type":"regproc","not_null":true,"length":4},{"name":"typmodin","type":"regproc","not_null":true,"length":4},{"name":"typmodout","type":"regproc","not_null":true,"length":4},{"name":"typanalyze","type":"regproc","not_null":true,"length":4},{"name":"typalign","type":"char","not_null":true,"length":1},{"name":"typstorage","type":"char","not_null":true,"length":1},{"name":"typnotnull","type":"bool","not_null":true,"length":1},{"name":"typbasetype","type":"oid","not_null":true,"length":4},{"name":"typtypmod","type":"int4","not_null":true,"length":4},{"name":"typndims","type":"int4","not_null":true,"length":4},{"name":"typcollation","type":"oid","not_null":true,"length":4},{"name":"typdefaultbin","type":"pg_node_tree"},{"name":"typdefault","type":"text"},{"name":"typacl","type":"_aclitem","array":true}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_user","columns":[{"name":"usename","type":"name","length":64},{"name":"usesysid","type":"oid","length":4},{"name":"usecreatedb","type":"bool","length":1},{"name":"usesuper","type":"bool","length":1},{"name":"userepl","type":"bool","length":1},{"name":"usebypassrls","type":"bool","length":1},{"name":"passwd","type":"text"},{"name":"valuntil","type":"timestamptz","length":8},{"name":"useconfig","type":"_text","array":true}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_user_mapping","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"umuser","type":"oid","not_null":true,"length":4},{"name":"umserver","type":"oid","not_null":true,"length":4},{"name":"umoptions","type":"_text","array":true}]} -{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_user_mappings","columns":[{"name":"umid","type":"oid","length":4},{"name":"srvid","type":"oid","length":4},{"name":"srvname","type":"name","length":64},{"name":"umuser","type":"oid","length":4},{"name":"usename","type":"name","length":64},{"name":"umoptions","type":"_text","array":true}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_type","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"typname","type":"name","not_null":true,"length":64},{"name":"typnamespace","type":"oid","not_null":true,"length":4},{"name":"typowner","type":"oid","not_null":true,"length":4},{"name":"typlen","type":"int2","not_null":true,"length":2},{"name":"typbyval","type":"bool","not_null":true,"length":1},{"name":"typtype","type":"char","not_null":true,"length":1},{"name":"typcategory","type":"char","not_null":true,"length":1},{"name":"typispreferred","type":"bool","not_null":true,"length":1},{"name":"typisdefined","type":"bool","not_null":true,"length":1},{"name":"typdelim","type":"char","not_null":true,"length":1},{"name":"typrelid","type":"oid","not_null":true,"length":4},{"name":"typsubscript","type":"regproc","not_null":true,"length":4},{"name":"typelem","type":"oid","not_null":true,"length":4},{"name":"typarray","type":"oid","not_null":true,"length":4},{"name":"typinput","type":"regproc","not_null":true,"length":4},{"name":"typoutput","type":"regproc","not_null":true,"length":4},{"name":"typreceive","type":"regproc","not_null":true,"length":4},{"name":"typsend","type":"regproc","not_null":true,"length":4},{"name":"typmodin","type":"regproc","not_null":true,"length":4},{"name":"typmodout","type":"regproc","not_null":true,"length":4},{"name":"typanalyze","type":"regproc","not_null":true,"length":4},{"name":"typalign","type":"char","not_null":true,"length":1},{"name":"typstorage","type":"char","not_null":true,"length":1},{"name":"typnotnull","type":"bool","not_null":true,"length":1},{"name":"typbasetype","type":"oid","not_null":true,"length":4},{"name":"typtypmod","type":"int4","not_null":true,"length":4},{"name":"typndims","type":"int4","not_null":true,"length":4},{"name":"typcollation","type":"oid","not_null":true,"length":4},{"name":"typdefaultbin","type":"pg_node_tree"},{"name":"typdefault","type":"text"},{"name":"typacl","type":"aclitem","array":true,"length":16}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_user","columns":[{"name":"usename","type":"name","length":64},{"name":"usesysid","type":"oid","length":4},{"name":"usecreatedb","type":"bool","length":1},{"name":"usesuper","type":"bool","length":1},{"name":"userepl","type":"bool","length":1},{"name":"usebypassrls","type":"bool","length":1},{"name":"passwd","type":"text"},{"name":"valuntil","type":"timestamptz","length":8},{"name":"useconfig","type":"text","array":true}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_user_mapping","columns":[{"name":"tableoid","type":"oid","not_null":true,"length":4},{"name":"cmax","type":"cid","not_null":true,"length":4},{"name":"xmax","type":"xid","not_null":true,"length":4},{"name":"cmin","type":"cid","not_null":true,"length":4},{"name":"xmin","type":"xid","not_null":true,"length":4},{"name":"ctid","type":"tid","not_null":true,"length":6},{"name":"oid","type":"oid","not_null":true,"length":4},{"name":"umuser","type":"oid","not_null":true,"length":4},{"name":"umserver","type":"oid","not_null":true,"length":4},{"name":"umoptions","type":"text","array":true}]} +{"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_user_mappings","columns":[{"name":"umid","type":"oid","length":4},{"name":"srvid","type":"oid","length":4},{"name":"srvname","type":"name","length":64},{"name":"umuser","type":"oid","length":4},{"name":"usename","type":"name","length":64},{"name":"umoptions","type":"text","array":true}]} {"catalog":"pg_catalog","schema":"pg_catalog","name":"pg_views","columns":[{"name":"schemaname","type":"name","length":64},{"name":"viewname","type":"name","length":64},{"name":"viewowner","type":"name","length":64},{"name":"definition","type":"text"}]} -{"catalog":"pg_catalog","schema":"information_schema","name":"_pg_foreign_data_wrappers","columns":[{"name":"oid","type":"oid","length":4},{"name":"fdwowner","type":"oid","length":4},{"name":"fdwoptions","type":"_text","array":true},{"name":"foreign_data_wrapper_catalog","type":"sql_identifier","length":64},{"name":"foreign_data_wrapper_name","type":"sql_identifier","length":64},{"name":"authorization_identifier","type":"sql_identifier","length":64},{"name":"foreign_data_wrapper_language","type":"character_data"}]} -{"catalog":"pg_catalog","schema":"information_schema","name":"_pg_foreign_servers","columns":[{"name":"oid","type":"oid","length":4},{"name":"srvoptions","type":"_text","array":true},{"name":"foreign_server_catalog","type":"sql_identifier","length":64},{"name":"foreign_server_name","type":"sql_identifier","length":64},{"name":"foreign_data_wrapper_catalog","type":"sql_identifier","length":64},{"name":"foreign_data_wrapper_name","type":"sql_identifier","length":64},{"name":"foreign_server_type","type":"character_data"},{"name":"foreign_server_version","type":"character_data"},{"name":"authorization_identifier","type":"sql_identifier","length":64}]} -{"catalog":"pg_catalog","schema":"information_schema","name":"_pg_foreign_table_columns","columns":[{"name":"nspname","type":"name","length":64},{"name":"relname","type":"name","length":64},{"name":"attname","type":"name","length":64},{"name":"attfdwoptions","type":"_text","array":true}]} -{"catalog":"pg_catalog","schema":"information_schema","name":"_pg_foreign_tables","columns":[{"name":"foreign_table_catalog","type":"sql_identifier","length":64},{"name":"foreign_table_schema","type":"sql_identifier","length":64},{"name":"foreign_table_name","type":"sql_identifier","length":64},{"name":"ftoptions","type":"_text","array":true},{"name":"foreign_server_catalog","type":"sql_identifier","length":64},{"name":"foreign_server_name","type":"sql_identifier","length":64},{"name":"authorization_identifier","type":"sql_identifier","length":64}]} -{"catalog":"pg_catalog","schema":"information_schema","name":"_pg_user_mappings","columns":[{"name":"oid","type":"oid","length":4},{"name":"umoptions","type":"_text","array":true},{"name":"umuser","type":"oid","length":4},{"name":"authorization_identifier","type":"sql_identifier","length":64},{"name":"foreign_server_catalog","type":"sql_identifier","length":64},{"name":"foreign_server_name","type":"sql_identifier","length":64},{"name":"srvowner","type":"sql_identifier","length":64}]} +{"catalog":"pg_catalog","schema":"information_schema","name":"_pg_foreign_data_wrappers","columns":[{"name":"oid","type":"oid","length":4},{"name":"fdwowner","type":"oid","length":4},{"name":"fdwoptions","type":"text","array":true},{"name":"foreign_data_wrapper_catalog","type":"sql_identifier","length":64},{"name":"foreign_data_wrapper_name","type":"sql_identifier","length":64},{"name":"authorization_identifier","type":"sql_identifier","length":64},{"name":"foreign_data_wrapper_language","type":"character_data"}]} +{"catalog":"pg_catalog","schema":"information_schema","name":"_pg_foreign_servers","columns":[{"name":"oid","type":"oid","length":4},{"name":"srvoptions","type":"text","array":true},{"name":"foreign_server_catalog","type":"sql_identifier","length":64},{"name":"foreign_server_name","type":"sql_identifier","length":64},{"name":"foreign_data_wrapper_catalog","type":"sql_identifier","length":64},{"name":"foreign_data_wrapper_name","type":"sql_identifier","length":64},{"name":"foreign_server_type","type":"character_data"},{"name":"foreign_server_version","type":"character_data"},{"name":"authorization_identifier","type":"sql_identifier","length":64}]} +{"catalog":"pg_catalog","schema":"information_schema","name":"_pg_foreign_table_columns","columns":[{"name":"nspname","type":"name","length":64},{"name":"relname","type":"name","length":64},{"name":"attname","type":"name","length":64},{"name":"attfdwoptions","type":"text","array":true}]} +{"catalog":"pg_catalog","schema":"information_schema","name":"_pg_foreign_tables","columns":[{"name":"foreign_table_catalog","type":"sql_identifier","length":64},{"name":"foreign_table_schema","type":"sql_identifier","length":64},{"name":"foreign_table_name","type":"sql_identifier","length":64},{"name":"ftoptions","type":"text","array":true},{"name":"foreign_server_catalog","type":"sql_identifier","length":64},{"name":"foreign_server_name","type":"sql_identifier","length":64},{"name":"authorization_identifier","type":"sql_identifier","length":64}]} +{"catalog":"pg_catalog","schema":"information_schema","name":"_pg_user_mappings","columns":[{"name":"oid","type":"oid","length":4},{"name":"umoptions","type":"text","array":true},{"name":"umuser","type":"oid","length":4},{"name":"authorization_identifier","type":"sql_identifier","length":64},{"name":"foreign_server_catalog","type":"sql_identifier","length":64},{"name":"foreign_server_name","type":"sql_identifier","length":64},{"name":"srvowner","type":"sql_identifier","length":64}]} {"catalog":"pg_catalog","schema":"information_schema","name":"administrable_role_authorizations","columns":[{"name":"grantee","type":"sql_identifier","length":64},{"name":"role_name","type":"sql_identifier","length":64},{"name":"is_grantable","type":"yes_or_no"}]} {"catalog":"pg_catalog","schema":"information_schema","name":"applicable_roles","columns":[{"name":"grantee","type":"sql_identifier","length":64},{"name":"role_name","type":"sql_identifier","length":64},{"name":"is_grantable","type":"yes_or_no"}]} {"catalog":"pg_catalog","schema":"information_schema","name":"attributes","columns":[{"name":"udt_catalog","type":"sql_identifier","length":64},{"name":"udt_schema","type":"sql_identifier","length":64},{"name":"udt_name","type":"sql_identifier","length":64},{"name":"attribute_name","type":"sql_identifier","length":64},{"name":"ordinal_position","type":"cardinal_number","length":4},{"name":"attribute_default","type":"character_data"},{"name":"is_nullable","type":"yes_or_no"},{"name":"data_type","type":"character_data"},{"name":"character_maximum_length","type":"cardinal_number","length":4},{"name":"character_octet_length","type":"cardinal_number","length":4},{"name":"character_set_catalog","type":"sql_identifier","length":64},{"name":"character_set_schema","type":"sql_identifier","length":64},{"name":"character_set_name","type":"sql_identifier","length":64},{"name":"collation_catalog","type":"sql_identifier","length":64},{"name":"collation_schema","type":"sql_identifier","length":64},{"name":"collation_name","type":"sql_identifier","length":64},{"name":"numeric_precision","type":"cardinal_number","length":4},{"name":"numeric_precision_radix","type":"cardinal_number","length":4},{"name":"numeric_scale","type":"cardinal_number","length":4},{"name":"datetime_precision","type":"cardinal_number","length":4},{"name":"interval_type","type":"character_data"},{"name":"interval_precision","type":"cardinal_number","length":4},{"name":"attribute_udt_catalog","type":"sql_identifier","length":64},{"name":"attribute_udt_schema","type":"sql_identifier","length":64},{"name":"attribute_udt_name","type":"sql_identifier","length":64},{"name":"scope_catalog","type":"sql_identifier","length":64},{"name":"scope_schema","type":"sql_identifier","length":64},{"name":"scope_name","type":"sql_identifier","length":64},{"name":"maximum_cardinality","type":"cardinal_number","length":4},{"name":"dtd_identifier","type":"sql_identifier","length":64},{"name":"is_derived_reference_attribute","type":"yes_or_no"}]} diff --git a/internal/engine/postgresql/dialect/types.jsonl b/internal/engine/postgresql/dialect/types.jsonl index da56a7af13..ac394f1616 100644 --- a/internal/engine/postgresql/dialect/types.jsonl +++ b/internal/engine/postgresql/dialect/types.jsonl @@ -1,25 +1,22 @@ -{"name": "bool", "category": "B", "aliases": ["boolean"]} -{"name": "int2", "category": "N", "aliases": ["smallint"]} -{"name": "int4", "category": "N", "aliases": ["integer", "int"]} -{"name": "int8", "category": "N", "aliases": ["bigint"]} -{"name": "float4", "category": "N", "aliases": ["real"]} -{"name": "float8", "category": "N", "aliases": ["double precision"]} +{"name": "boolean", "category": "B", "aliases": ["bool"]} +{"name": "smallint", "category": "N", "aliases": ["int2", "smallserial", "serial2"]} +{"name": "integer", "category": "N", "aliases": ["int4", "int", "serial", "serial4"]} +{"name": "bigint", "category": "N", "aliases": ["int8", "bigserial", "serial8"]} +{"name": "real", "category": "N", "aliases": ["float4"]} +{"name": "double precision", "category": "N", "aliases": ["float8"]} {"name": "numeric", "category": "N", "aliases": ["decimal"]} {"name": "money", "category": "N"} {"name": "oid", "category": "N"} -{"name": "serial2", "category": "N", "aliases": ["smallserial"]} -{"name": "serial4", "category": "N", "aliases": ["serial"]} -{"name": "serial8", "category": "N", "aliases": ["bigserial"]} {"name": "text", "category": "S"} -{"name": "varchar", "category": "S", "aliases": ["character varying"]} -{"name": "bpchar", "category": "S", "aliases": ["char", "character"]} +{"name": "character varying", "category": "S", "aliases": ["varchar"]} +{"name": "character", "category": "S", "aliases": ["bpchar", "char"]} {"name": "name", "category": "S"} {"name": "citext", "category": "S"} {"name": "date", "category": "D"} -{"name": "time", "category": "D", "aliases": ["time without time zone"]} -{"name": "timetz", "category": "D", "aliases": ["time with time zone"]} -{"name": "timestamp", "category": "D", "aliases": ["timestamp without time zone"]} -{"name": "timestamptz", "category": "D", "aliases": ["timestamp with time zone"]} +{"name": "time without time zone", "category": "D", "aliases": ["time"]} +{"name": "time with time zone", "category": "D", "aliases": ["timetz"]} +{"name": "timestamp without time zone", "category": "D", "aliases": ["timestamp"]} +{"name": "timestamp with time zone", "category": "D", "aliases": ["timestamptz"]} {"name": "interval", "category": "T"} {"name": "uuid", "category": "U"} {"name": "bytea", "category": "U"} @@ -31,7 +28,7 @@ {"name": "macaddr", "category": "U"} {"name": "macaddr8", "category": "U"} {"name": "bit", "category": "U"} -{"name": "varbit", "category": "U", "aliases": ["bit varying"]} +{"name": "bit varying", "category": "U", "aliases": ["varbit"]} {"name": "tsvector", "category": "U"} {"name": "tsquery", "category": "U"} {"name": "point", "category": "U"} @@ -47,4 +44,5 @@ {"name": "tsrange", "category": "U"} {"name": "tstzrange", "category": "U"} {"name": "daterange", "category": "U"} -{"name": "anyarray", "category": "A", "aliases": ["array"]} +{"name": "anyarray", "category": "A"} +{"name": "array", "category": "A"} diff --git a/internal/engine/postgresql/parse.go b/internal/engine/postgresql/parse.go index 0de54e6eb3..58f7c3d431 100644 --- a/internal/engine/postgresql/parse.go +++ b/internal/engine/postgresql/parse.go @@ -346,7 +346,7 @@ func translate(node *nodes.Node) (ast.Node, error) { item.Subtype = ast.AT_AddColumn item.Def = &ast.ColumnDef{ Colname: d.ColumnDef.Colname, - TypeName: rel.TypeName(), + TypeName: columnTypeName(rel, d.ColumnDef.TypeName), IsNotNull: isNotNull(d.ColumnDef), IsArray: isArray(d.ColumnDef.TypeName), ArrayDims: len(d.ColumnDef.TypeName.ArrayBounds), @@ -372,7 +372,7 @@ func translate(node *nodes.Node) (ast.Node, error) { item.Subtype = ast.AT_AlterColumnType item.Def = &ast.ColumnDef{ Colname: col, - TypeName: rel.TypeName(), + TypeName: columnTypeName(rel, d.ColumnDef.TypeName), IsNotNull: isNotNull(d.ColumnDef), IsArray: isArray(d.ColumnDef.TypeName), ArrayDims: len(d.ColumnDef.TypeName.ArrayBounds), @@ -457,9 +457,27 @@ func translate(node *nodes.Node) (ast.Node, error) { case *nodes.Node_CompositeTypeStmt: n := inner.CompositeTypeStmt rel := parseRelationFromRangeVar(n.Typevar) - return &ast.CompositeTypeStmt{ - TypeName: rel.TypeName(), - }, nil + stmt := &ast.CompositeTypeStmt{ + TypeName: rel.TypeName(), + Coldeflist: &ast.List{}, + } + for _, node := range n.Coldeflist { + field, ok := node.Node.(*nodes.Node_ColumnDef) + if !ok { + continue + } + rel, err := parseRelationFromNodes(field.ColumnDef.TypeName.Names) + if err != nil { + return nil, err + } + stmt.Coldeflist.Items = append(stmt.Coldeflist.Items, &ast.ColumnDef{ + Colname: field.ColumnDef.Colname, + TypeName: columnTypeName(rel, field.ColumnDef.TypeName), + IsArray: isArray(field.ColumnDef.TypeName), + ArrayDims: len(field.ColumnDef.TypeName.ArrayBounds), + }) + } + return stmt, nil case *nodes.Node_CreateStmt: n := inner.CreateStmt @@ -510,7 +528,7 @@ func translate(node *nodes.Node) (ast.Node, error) { create.Cols = append(create.Cols, &ast.ColumnDef{ Colname: item.ColumnDef.Colname, - TypeName: rel.TypeName(), + TypeName: columnTypeName(rel, item.ColumnDef.TypeName), IsNotNull: isNotNull(item.ColumnDef) || primaryKey[item.ColumnDef.Colname], IsArray: isArray(item.ColumnDef.TypeName), ArrayDims: len(item.ColumnDef.TypeName.ArrayBounds), @@ -708,3 +726,73 @@ func translate(node *nodes.Node) (ast.Node, error) { return convert(node) } } + +// columnTypeName is a column's type as the catalog needs it: the name the +// relation resolves, with the type modifiers the parser reported. Every +// modifier is an integer constant, except that an interval's first one is a +// bit mask of the fields it keeps, which is decoded into the words +// format_type prints, so that "interval day to second" carries "day to +// second" as its first argument. +func columnTypeName(rel *relation, tn *nodes.TypeName) *ast.TypeName { + out := rel.TypeName() + if tn == nil || len(tn.Typmods) == 0 { + return out + } + out.Typmods = &ast.List{} + for i, mod := range tn.Typmods { + c, ok := mod.Node.(*nodes.Node_AConst) + if !ok { + continue + } + ival, ok := c.AConst.Val.(*nodes.A_Const_Ival) + if !ok { + continue + } + if i == 0 && rel.Name == "interval" { + fields, ok := intervalFields[ival.Ival.Ival] + if !ok { + continue + } + if fields != "" { + out.Typmods.Items = append(out.Typmods.Items, &ast.String{Str: fields}) + } + continue + } + out.Typmods.Items = append(out.Typmods.Items, &ast.A_Const{Val: &ast.Integer{Ival: int64(ival.Ival.Ival)}}) + } + if len(out.Typmods.Items) == 0 { + out.Typmods = nil + } + return out +} + +// intervalFields decodes the field mask an interval typmod starts with — +// INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH) and so on, with the field +// numbers PostgreSQL's datetime.h assigns — into the words a declaration +// spells. The full range is written as nothing. +var intervalFields = func() map[int32]string { + const ( + month = 1 << 1 + year = 1 << 2 + day = 1 << 3 + hour = 1 << 10 + minute = 1 << 11 + second = 1 << 12 + ) + return map[int32]string{ + 0x7FFF: "", + year: "year", + month: "month", + day: "day", + hour: "hour", + minute: "minute", + second: "second", + year | month: "year to month", + day | hour: "day to hour", + day | hour | minute: "day to minute", + day | hour | minute | second: "day to second", + hour | minute: "hour to minute", + hour | minute | second: "hour to second", + minute | second: "minute to second", + } +}() diff --git a/internal/engine/sqlite/dialect/dialect.json b/internal/engine/sqlite/dialect/dialect.json index 36129df83a..60bce0eaf3 100644 --- a/internal/engine/sqlite/dialect/dialect.json +++ b/internal/engine/sqlite/dialect/dialect.json @@ -1,5 +1,6 @@ { "dialect": "sqlite", + "alias": "base", "const": { "integer": "integer", "float": "real", @@ -19,5 +20,26 @@ "geopoly": "enable_geopoly", "rtree": "enable_rtree", "rtree_i32": "enable_rtree" - } + }, + "affinity": [ + { + "contains": ["INT"], + "type": "integer" + }, + { + "contains": ["CHAR", "CLOB", "TEXT"], + "type": "text" + }, + { + "contains": ["BLOB"], + "type": "blob" + }, + { + "contains": ["REAL", "FLOA", "DOUB"], + "type": "real" + }, + { + "type": "numeric" + } + ] } diff --git a/internal/goldeneye/analysis/analysis.go b/internal/goldeneye/analysis/analysis.go index fe907766a3..1433f50904 100644 --- a/internal/goldeneye/analysis/analysis.go +++ b/internal/goldeneye/analysis/analysis.go @@ -40,13 +40,16 @@ type TypeExpr struct { Args []TypeArg `json:"args,omitempty"` } -// TypeArg is one argument of a TypeExpr. +// TypeArg is one argument of a TypeExpr: a type, an integer, a boolean, a +// quoted string, or an identifier — a bare word that is not a type, such as +// the function an AggregateFunction names. type TypeArg struct { Label string `json:"label,omitempty"` Type *TypeExpr `json:"type,omitempty"` Int *int64 `json:"int,omitempty"` Bool *bool `json:"bool,omitempty"` String *string `json:"string,omitempty"` + Ident *string `json:"ident,omitempty"` } // Encode prints the answer the way sqlc analyze does. diff --git a/internal/goldeneye/clickhouse/types.go b/internal/goldeneye/clickhouse/types.go index 57f6caf731..96de5124f3 100644 --- a/internal/goldeneye/clickhouse/types.go +++ b/internal/goldeneye/clickhouse/types.go @@ -34,8 +34,8 @@ import ( // {"name": "datetime64", "args": [{"int": 3}, {"string": "UTC"}]} // // An identifier argument such as the function in AggregateFunction(uniq, -// String) is a type with no arguments. Resolving names against the catalog -// is the reader's job; the output only records what was said. +// String) is a word rather than a type. Resolving names against the +// catalog is the reader's job; the output only records what was said. // parseType turns a ClickHouse type string into its expression. func parseType(t string) *analysis.TypeExpr { @@ -53,6 +53,20 @@ func parseType(t string) *analysis.TypeExpr { for _, a := range args { expr.Args = append(expr.Args, parseArg(a)) } + // LowCardinality(Nullable(T)) is the only order ClickHouse accepts for + // a nullable low-cardinality column, and the nullability is the + // column's: it reads as a nullable LowCardinality(T). + if name == "lowcardinality" && len(expr.Args) == 1 && expr.Args[0].Type != nil && expr.Args[0].Type.Nullable { + expr.Nullable = true + expr.Args[0].Type.Nullable = false + } + // The function an aggregate-function type names is a word, not a type. + if name == "aggregatefunction" || name == "simpleaggregatefunction" { + if len(expr.Args) > 0 && expr.Args[0].Type != nil && len(expr.Args[0].Type.Args) == 0 { + fn := expr.Args[0].Type.Name + expr.Args[0] = analysis.TypeArg{Ident: &fn} + } + } return expr } diff --git a/internal/goldeneye/endtoend/query.go b/internal/goldeneye/endtoend/query.go index ea15ad89e2..70a8ae7658 100644 --- a/internal/goldeneye/endtoend/query.go +++ b/internal/goldeneye/endtoend/query.go @@ -72,10 +72,14 @@ func ParseQueries(src string) ([]Query, error) { var namedArgRe = regexp.MustCompile(`^sqlc\.(n?arg|slice)\(\s*'?([A-Za-z_][A-Za-z0-9_]*)'?\s*\)`) +// typedParamRe matches ClickHouse's {name:Type} parameter, whose type is +// the query's own business: the engine binds it as it binds any other. +var typedParamRe = regexp.MustCompile(`^\{\s*([A-Za-z_][A-Za-z0-9_]*)\s*:\s*[^}]+\}`) + // Rewrite replaces every parameter reference in a query — ?, sqlc.arg(name), -// sqlc.narg(name) and sqlc.slice(name) — with what bind returns for it, in -// order of appearance, skipping string literals, quoted identifiers and -// comments. bind is handed the name, empty for a ?, and the word before the +// sqlc.narg(name), sqlc.slice(name) and ClickHouse's {name:Type} — with +// what bind returns for it, in order of appearance, skipping string +// literals, quoted identifiers and comments. bind is handed the name, empty for a ?, and the word before the // reference, so that a LIMIT or OFFSET can be bound differently from a // value; the second count of a LIMIT ?, ? is handed LIMIT as well. Each // engine decides what a reference becomes and how the references are @@ -120,6 +124,11 @@ func Rewrite(sql string, bind func(name, lastWord string) string) string { out.WriteString(bind(m[2], lastWord)) lastWord = afterReference(lastWord) i += len(m[0]) + case c == '{' && typedParamRe.MatchString(sql[i:]): + m := typedParamRe.FindStringSubmatch(sql[i:]) + out.WriteString(bind(m[1], lastWord)) + lastWord = afterReference(lastWord) + i += len(m[0]) case isWordByte(c): end := i for end < len(sql) && isWordByte(sql[end]) { diff --git a/internal/goldeneye/mysql/analyze.go b/internal/goldeneye/mysql/analyze.go index b25c87c8a8..a2c4240817 100644 --- a/internal/goldeneye/mysql/analyze.go +++ b/internal/goldeneye/mysql/analyze.go @@ -1,9 +1,12 @@ package mysql import ( + "bytes" "context" "database/sql" + "encoding/json" "fmt" + "github.com/sqlc-dev/sqlc/internal/goldeneye/dialect" "os" "regexp" "strconv" @@ -76,13 +79,96 @@ func bind(sql string) (string, []placeholder) { return out, phs } -// column is what information_schema says about a column. +// column is what information_schema says about a column: its type as +// COLUMN_TYPE spells it, read into an expression. type column struct { name string - typ string + typ *analysis.TypeExpr nullable bool } +// typeOfColumn is a column's type as it was declared, from COLUMN_TYPE, which +// carries the arguments and the unsigned that DATA_TYPE does not: "decimal(10,2) +// unsigned" is the family "decimal unsigned" applied to 10 and 2, and +// "enum('a','b')" is enum applied to its members. A trailing word such as +// zerofill is part of the family too. +func typeOfColumn(columnType string) *analysis.TypeExpr { + s := strings.TrimSpace(columnType) + open := strings.IndexByte(s, '(') + if open < 0 { + return &analysis.TypeExpr{Name: strings.ToLower(s)} + } + close := strings.LastIndexByte(s, ')') + if close < open { + return &analysis.TypeExpr{Name: strings.ToLower(s)} + } + // The family is spelled in lower case; an enum's members keep theirs, + // since they are values. + name := strings.ToLower(strings.TrimSpace(s[:open])) + if rest := strings.ToLower(strings.TrimSpace(s[close+1:])); rest != "" { + name += " " + rest + } + t := &analysis.TypeExpr{Name: name} + for _, a := range splitArgs(s[open+1 : close]) { + a = strings.TrimSpace(a) + if strings.HasPrefix(a, "'") && strings.HasSuffix(a, "'") && len(a) >= 2 { + v := unquoteMember(a[1 : len(a)-1]) + t.Args = append(t.Args, analysis.TypeArg{String: &v}) + continue + } + if n, err := strconv.ParseInt(a, 10, 64); err == nil { + t.Args = append(t.Args, analysis.TypeArg{Int: &n}) + } + } + return t +} + +// splitArgs splits a type's argument list on the commas outside quotes. A +// backslash inside a quoted member escapes the character after it. +func splitArgs(s string) []string { + var out []string + start, quoted := 0, false + for i := 0; i < len(s); i++ { + switch { + case quoted && s[i] == '\\': + i++ + case s[i] == '\'': + quoted = !quoted + case s[i] == ',' && !quoted: + out = append(out, s[start:i]) + start = i + 1 + } + } + return append(out, s[start:]) +} + +// unquoteMember reads the body of a quoted enum or set member as +// information_schema spells it: a quote is doubled and a backslash escapes +// the character after it. +func unquoteMember(s string) string { + var out strings.Builder + for i := 0; i < len(s); i++ { + switch { + case s[i] == '\\' && i+1 < len(s): + i++ + out.WriteByte(s[i]) + case s[i] == '\'' && i+1 < len(s) && s[i+1] == '\'': + i++ + out.WriteByte('\'') + default: + out.WriteByte(s[i]) + } + } + return out.String() +} + +// withNullable copies a type with its nullability set. +func withNullable(t *analysis.TypeExpr, nullable bool) *analysis.TypeExpr { + out := *t + out.Nullable = nullable + return &out +} + // relation is a table the catalog knows, by schema and name. type relation struct { schema, name string @@ -185,12 +271,48 @@ func Analyze(ctx context.Context, dsn string, c endtoend.Case) ([]byte, error) { // Check compares what MySQL reports for a case with the output the case // committed, returning a diff when they differ. +// Check compares a case's committed output with what MySQL reports. A +// column read from a table is compared in full, since information_schema +// spells its whole type; an expression's type comes from the wire, which +// carries the family and nothing of its arguments, so an expression, and +// a parameter typed by one, is compared by family alone. func Check(ctx context.Context, dsn string, c endtoend.Case) (string, error) { got, err := Analyze(ctx, dsn, c) if err != nil { return "", err } - return c.Compare(got) + want, err := os.ReadFile(c.Output) + if err != nil { + return "", err + } + var queries []analysis.Query + if err := json.Unmarshal(want, &queries); err != nil { + return "", fmt.Errorf("%s: %w", c.Output, err) + } + for i := range queries { + for j := range queries[i].Columns { + familyOnly(&queries[i].Columns[j]) + } + for j := range queries[i].Params { + familyOnly(&queries[i].Params[j].Column) + } + } + want, err = analysis.Encode(queries) + if err != nil { + return "", err + } + if bytes.Equal(want, got) { + return "", nil + } + return dialect.Diff(string(want), string(got)), nil +} + +// familyOnly drops the arguments of a column's type when the column is not +// read from a table, which is as much as the wire says about it. +func familyOnly(col *analysis.Column) { + if col.Table == "" && col.Type != nil { + col.Type.Args = nil + } } const catalogQuery = ` @@ -217,7 +339,7 @@ func readCatalog(ctx context.Context, conn *sql.Conn, db string) (map[relation][ rel := relation{schema, table} catalog[rel] = append(catalog[rel], column{ name: name, - typ: typeName(dataType, columnType), + typ: typeOfColumn(columnType), nullable: nullable == "YES", }) } @@ -313,7 +435,7 @@ func (a *analyzer) analyzeQuery(ctx context.Context, q endtoend.Query) (analysis ac.Table = rel.name } if col, ok := s.origin(top, tok, 0); ok { - ac.Type.Name = col.typ + ac.Type = withNullable(col.typ, ac.Type.Nullable) } } } @@ -582,7 +704,7 @@ func (s *statement) column(rel relation, name string) analysis.Column { if col.name == name { return analysis.Column{ Name: name, - Type: &analysis.TypeExpr{Name: col.typ, Nullable: col.nullable}, + Type: withNullable(col.typ, col.nullable), Table: rel.name, } } diff --git a/internal/goldeneye/mysql/relations.go b/internal/goldeneye/mysql/relations.go index 1dde46f89c..63e422cd9d 100644 --- a/internal/goldeneye/mysql/relations.go +++ b/internal/goldeneye/mysql/relations.go @@ -34,10 +34,9 @@ ORDER BY t.TABLE_NAME, c.ORDINAL_POSITION` // in lower case: information_schema names its views in upper case and // matches them in any case, MySQL matches every column name in any case, // and sqlc's MySQL parser lowercases every identifier, so lower case is -// how a query reaches them. A column's type is its data type as MySQL -// names it, with UNSIGNED kept as part of the name the way a column -// declaration spells it; the length and precision a declaration adds are -// not part of the type. +// how a query reaches them. A column's type is spelled the way a +// declaration does, as COLUMN_TYPE reports it, arguments and UNSIGNED +// included: varchar(64), bigint unsigned. func readRelations(ctx context.Context, conn *sql.Conn, schema string) ([]dialect.Relation, error) { rows, err := conn.QueryContext(ctx, relationQuery, schema) if err != nil { @@ -69,13 +68,32 @@ func readRelations(ctx context.Context, conn *sql.Conn, schema string) ([]dialec return relations, rows.Err() } -// typeName spells a column's type the way a declaration does, from the -// DATA_TYPE and COLUMN_TYPE information_schema reports for it: "bigint", -// or "bigint unsigned" when the column is unsigned. +// typeName spells a column's type the way a declaration does, which is +// COLUMN_TYPE as information_schema reports it: "varchar(64)", "bigint +// unsigned", "enum('a','b')". The family is spelled in lower case; the +// members of an enum or set are values and keep theirs. func typeName(dataType, columnType string) string { - name := strings.ToLower(dataType) - if strings.Contains(strings.ToLower(columnType), " unsigned") { - name += " unsigned" + if columnType == "" { + return strings.ToLower(dataType) } - return name + var out strings.Builder + quoted := false + for i := 0; i < len(columnType); i++ { + c := columnType[i] + switch { + case quoted && c == '\\' && i+1 < len(columnType): + out.WriteByte(c) + i++ + out.WriteByte(columnType[i]) + continue + case c == '\'': + quoted = !quoted + } + if quoted { + out.WriteByte(c) + } else { + out.WriteString(strings.ToLower(string(c))) + } + } + return out.String() } diff --git a/internal/goldeneye/postgresql/relation.go b/internal/goldeneye/postgresql/relation.go index ecd20e2d1f..7e036a0ff2 100644 --- a/internal/goldeneye/postgresql/relation.go +++ b/internal/goldeneye/postgresql/relation.go @@ -19,13 +19,20 @@ select relations.name as tablename, pg_attribute.attname as column_name, attnotnull as column_notnull, - column_type.typname as column_type, - nullif(column_type.typlen, -1) as column_length, - column_type.typcategory = 'A' as column_isarray + -- An array column's type is its element's, with the array flag set, + -- rather than pg_type's own _text spelling of the array type. Only the + -- _-prefixed array types count: int2vector and oidvector are in the + -- array category and carry an element, but are types of their own. + coalesce(element_type.typname, column_type.typname) as column_type, + nullif(coalesce(element_type.typlen, column_type.typlen), -1) as column_length, + element_type.oid is not null as column_isarray from relations inner join pg_catalog.pg_class on pg_class.relname = relations.name left join pg_catalog.pg_attribute on pg_attribute.attrelid = pg_class.oid inner join pg_catalog.pg_type column_type on pg_attribute.atttypid = column_type.oid +left join pg_catalog.pg_type element_type + on column_type.typcategory = 'A' and column_type.typname like '\_%' + and element_type.oid = column_type.typelem where relations.schemaname = $1 -- Make sure these columns are always generated in the same order -- so that the output is stable diff --git a/internal/sql/ast/composite_type_stmt.go b/internal/sql/ast/composite_type_stmt.go index eab6f7f4cc..a7f27a8b54 100644 --- a/internal/sql/ast/composite_type_stmt.go +++ b/internal/sql/ast/composite_type_stmt.go @@ -4,6 +4,8 @@ type CompositeTypeStmt struct { Tag NodeTag[CompositeTypeStmt] `json:"tag"` TypeName *TypeName `json:"type_name,omitempty"` + // Coldeflist is the type's fields, each a ColumnDef. + Coldeflist *List `json:"coldeflist,omitempty"` } func (n *CompositeTypeStmt) Pos() int { diff --git a/internal/sql/ast/constr_type.go b/internal/sql/ast/constr_type.go index d84e4d8c4a..c058682672 100644 --- a/internal/sql/ast/constr_type.go +++ b/internal/sql/ast/constr_type.go @@ -5,3 +5,10 @@ type ConstrType uint func (n *ConstrType) Pos() int { return 0 } + +// The constraint kinds the analysis reads, numbered as PostgreSQL's parser +// numbers them, which is what an engine's converter records. +const ( + ConstrTypeNull ConstrType = 1 + ConstrTypeNotNull ConstrType = 2 +) diff --git a/internal/sql/ast/param_ref.go b/internal/sql/ast/param_ref.go index 2b7ec5c527..0936c60d30 100644 --- a/internal/sql/ast/param_ref.go +++ b/internal/sql/ast/param_ref.go @@ -8,6 +8,9 @@ type ParamRef struct { Number int `json:"number"` Location int `json:"location"` Dollar bool `json:"dollar"` + // Name is the name the query gave the placeholder, when its syntax + // has one: ClickHouse's {name:Type}. + Name string `json:"name,omitempty"` } func (n *ParamRef) Pos() int { diff --git a/internal/sql/ast/type_name.go b/internal/sql/ast/type_name.go index 9a557707b8..ddf7decfaa 100644 --- a/internal/sql/ast/type_name.go +++ b/internal/sql/ast/type_name.go @@ -13,6 +13,11 @@ type TypeName struct { // CHARACTER" resolves as "VARYINGCHARACTER" in the catalog), so the // formatter prints this back instead of the folded form. Spelling string `json:"spelling"` + // Canonical is the type as a call expression the analysis core reads, + // when an engine spells it differently from what the formatter prints + // back: DuckDB's STRUCT(a INTEGER, b VARCHAR) as struct(a: integer, b: + // varchar), ClickHouse's Enum('a', 'b') as Enum8('a' = 1, 'b' = 2). + Canonical string `json:"canonical,omitempty"` // From pg.TypeName Names *List `json:"names,omitempty"`