Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix "char" and array types for system functions and tables #519

Merged
merged 11 commits into from
Jul 31, 2024
6 changes: 3 additions & 3 deletions server/ast/resolvable_type_reference.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,13 @@ func nodeResolvableTypeReference(typ tree.ResolvableTypeReference) (*vitess.Conv
}
case oid.T_char:
width := uint32(columnType.Width())
if width > pgtypes.StringMaxLength {
return nil, nil, fmt.Errorf("length for type char cannot exceed %d", pgtypes.StringMaxLength)
if width > pgtypes.InternalCharLength {
return nil, nil, fmt.Errorf("length for type \"char\" cannot exceed %d", pgtypes.InternalCharLength)
}
if width == 0 {
width = 1
}
resolvedType = pgtypes.CharType{Length: width}
resolvedType = pgtypes.InternalChar
case oid.T_date:
resolvedType = pgtypes.Date
case oid.T_float4:
Expand Down
14 changes: 14 additions & 0 deletions server/cast/char.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ func initChar() {

// charExplicit registers all explicit casts. This comprises only the "From" types.
func charExplicit() {
framework.MustAddExplicitTypeCast(framework.TypeCast{
FromType: pgtypes.BpChar,
ToType: pgtypes.InternalChar,
Function: func(ctx *sql.Context, val any, targetType pgtypes.DoltgresType) (any, error) {
return targetType.IoInput(ctx, val.(string))
},
})
tbantle22 marked this conversation as resolved.
Show resolved Hide resolved
framework.MustAddExplicitTypeCast(framework.TypeCast{
FromType: pgtypes.BpChar,
ToType: pgtypes.Int32,
Expand All @@ -58,6 +65,13 @@ func charImplicit() {
return targetType.IoInput(ctx, val.(string))
},
})
framework.MustAddImplicitTypeCast(framework.TypeCast{
FromType: pgtypes.BpChar,
ToType: pgtypes.InternalChar,
Function: func(ctx *sql.Context, val any, targetType pgtypes.DoltgresType) (any, error) {
return targetType.IoInput(ctx, val.(string))
},
})
tbantle22 marked this conversation as resolved.
Show resolved Hide resolved
framework.MustAddImplicitTypeCast(framework.TypeCast{
FromType: pgtypes.BpChar,
ToType: pgtypes.Name,
Expand Down
1 change: 1 addition & 0 deletions server/cast/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func Init() {
initInt16()
initInt32()
initInt64()
initInternalChar()
initJson()
initJsonB()
initName()
Expand Down
129 changes: 129 additions & 0 deletions server/cast/internal_char.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// Copyright 2024 Dolthub, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cast

import (
"fmt"
"strconv"
"strings"
"unicode"

"github.com/dolthub/go-mysql-server/sql"

"github.com/dolthub/doltgresql/server/functions/framework"
pgtypes "github.com/dolthub/doltgresql/server/types"
)

// initInternalChar handles all casts that are built-in. This comprises only the "From" types.
func initInternalChar() {
internalCharExplicit()
internalCharImplicit()
}

// internalCharExplicit registers all explicit casts. This comprises only the "From" types.
func internalCharExplicit() {
tbantle22 marked this conversation as resolved.
Show resolved Hide resolved
framework.MustAddExplicitTypeCast(framework.TypeCast{
FromType: pgtypes.InternalChar,
ToType: pgtypes.BpChar,
Function: func(ctx *sql.Context, val any, targetType pgtypes.DoltgresType) (any, error) {
return targetType.IoInput(ctx, val.(string))
},
})
framework.MustAddExplicitTypeCast(framework.TypeCast{
FromType: pgtypes.InternalChar,
ToType: pgtypes.Int32,
Function: func(ctx *sql.Context, val any, targetType pgtypes.DoltgresType) (any, error) {
s := val.(string)
if len(s) == 0 {
return int32(0), nil
}
if unicode.IsLetter(rune(s[0])) {
return int32(s[0]), nil
}
i, err := strconv.ParseInt(s, 10, 32)
if err != nil {
return 0, err
}
return int32(i), nil
},
})
framework.MustAddExplicitTypeCast(framework.TypeCast{
FromType: pgtypes.InternalChar,
ToType: pgtypes.Name,
Function: func(ctx *sql.Context, val any, targetType pgtypes.DoltgresType) (any, error) {
return handleStringCast(val.(string), targetType)
},
})
framework.MustAddExplicitTypeCast(framework.TypeCast{
FromType: pgtypes.InternalChar,
ToType: pgtypes.Text,
Function: func(ctx *sql.Context, val any, targetType pgtypes.DoltgresType) (any, error) {
return val, nil
},
})
framework.MustAddExplicitTypeCast(framework.TypeCast{
FromType: pgtypes.InternalChar,
ToType: pgtypes.VarChar,
Function: func(ctx *sql.Context, val any, targetType pgtypes.DoltgresType) (any, error) {
return handleStringCast(val.(string), targetType)
},
})
}

// internalCharImplicit registers all implicit casts. This comprises only the "From" types.
func internalCharImplicit() {
framework.MustAddImplicitTypeCast(framework.TypeCast{
FromType: pgtypes.InternalChar,
ToType: pgtypes.BpChar,
Function: func(ctx *sql.Context, val any, targetType pgtypes.DoltgresType) (any, error) {
return targetType.IoInput(ctx, val.(string))
},
})
framework.MustAddImplicitTypeCast(framework.TypeCast{
FromType: pgtypes.InternalChar,
ToType: pgtypes.Int32,
Function: func(ctx *sql.Context, val any, targetType pgtypes.DoltgresType) (any, error) {
out, err := strconv.ParseInt(strings.TrimSpace(val.(string)), 10, 32)
if err != nil {
return nil, fmt.Errorf("invalid input syntax for type %s: %q", targetType.String(), val.(string))
}
if out > 2147483647 || out < -2147483648 {
return nil, fmt.Errorf("value %q is out of range for type %s", val.(string), targetType.String())
}
return int32(out), nil
},
})
framework.MustAddImplicitTypeCast(framework.TypeCast{
FromType: pgtypes.InternalChar,
ToType: pgtypes.Name,
Function: func(ctx *sql.Context, val any, targetType pgtypes.DoltgresType) (any, error) {
return handleStringCast(val.(string), targetType)
},
})
framework.MustAddImplicitTypeCast(framework.TypeCast{
FromType: pgtypes.InternalChar,
ToType: pgtypes.Text,
Function: func(ctx *sql.Context, val any, targetType pgtypes.DoltgresType) (any, error) {
return val, nil
},
})
framework.MustAddImplicitTypeCast(framework.TypeCast{
FromType: pgtypes.InternalChar,
ToType: pgtypes.VarChar,
Function: func(ctx *sql.Context, val any, targetType pgtypes.DoltgresType) (any, error) {
return handleStringCast(val.(string), targetType)
},
})
}
7 changes: 7 additions & 0 deletions server/cast/name.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ func nameAssignment() {
return handleStringCast(val.(string), targetType)
},
})
framework.MustAddAssignmentTypeCast(framework.TypeCast{
FromType: pgtypes.Name,
ToType: pgtypes.InternalChar,
Function: func(ctx *sql.Context, val any, targetType pgtypes.DoltgresType) (any, error) {
return handleStringCast(val.(string), targetType)
},
})
tbantle22 marked this conversation as resolved.
Show resolved Hide resolved
framework.MustAddAssignmentTypeCast(framework.TypeCast{
FromType: pgtypes.Name,
ToType: pgtypes.VarChar,
Expand Down
14 changes: 14 additions & 0 deletions server/cast/text.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ func textAssignment() {
return handleStringCast(val.(string), targetType)
},
})
framework.MustAddAssignmentTypeCast(framework.TypeCast{
FromType: pgtypes.Text,
ToType: pgtypes.InternalChar,
Function: func(ctx *sql.Context, val any, targetType pgtypes.DoltgresType) (any, error) {
return handleStringCast(val.(string), targetType)
},
})
}

// textImplicit registers all implicit casts. This comprises only the "From" types.
Expand All @@ -47,6 +54,13 @@ func textImplicit() {
return handleStringCast(val.(string), targetType)
},
})
framework.MustAddImplicitTypeCast(framework.TypeCast{
FromType: pgtypes.Text,
ToType: pgtypes.InternalChar,
Function: func(ctx *sql.Context, val any, targetType pgtypes.DoltgresType) (any, error) {
return handleStringCast(val.(string), targetType)
},
})
tbantle22 marked this conversation as resolved.
Show resolved Hide resolved
framework.MustAddImplicitTypeCast(framework.TypeCast{
FromType: pgtypes.Text,
ToType: pgtypes.Name,
Expand Down
3 changes: 3 additions & 0 deletions server/cast/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ func handleStringCast(str string, targetType pgtypes.DoltgresType) (string, erro
return str, nil
}
}
case pgtypes.InternalCharType:
str, _ := truncateString(str, pgtypes.InternalCharLength)
return str, nil
Hydrocharged marked this conversation as resolved.
Show resolved Hide resolved
case pgtypes.NameType:
// Name seems to never throw an error, regardless of the context or how long the input is
str, _ := truncateString(str, targetType.Length)
Expand Down
14 changes: 14 additions & 0 deletions server/cast/varchar.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ func varcharAssignment() {
return handleStringCast(val.(string), targetType)
},
})
framework.MustAddAssignmentTypeCast(framework.TypeCast{
FromType: pgtypes.VarChar,
ToType: pgtypes.InternalChar,
Function: func(ctx *sql.Context, val any, targetType pgtypes.DoltgresType) (any, error) {
return handleStringCast(val.(string), targetType)
},
})
}

// varcharImplicit registers all implicit casts. This comprises only the "From" types.
Expand All @@ -47,6 +54,13 @@ func varcharImplicit() {
return handleStringCast(val.(string), targetType)
},
})
framework.MustAddImplicitTypeCast(framework.TypeCast{
FromType: pgtypes.VarChar,
ToType: pgtypes.InternalChar,
Function: func(ctx *sql.Context, val any, targetType pgtypes.DoltgresType) (any, error) {
return handleStringCast(val.(string), targetType)
},
})
tbantle22 marked this conversation as resolved.
Show resolved Hide resolved
framework.MustAddImplicitTypeCast(framework.TypeCast{
FromType: pgtypes.VarChar,
ToType: pgtypes.Name,
Expand Down
6 changes: 5 additions & 1 deletion server/functions/framework/cast.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ func GetExplicitCast(fromType pgtypes.DoltgresTypeBaseID, toType pgtypes.Doltgre
if fromType == toType && toType.GetTypeCategory() != pgtypes.TypeCategory_StringTypes && fromType.GetTypeCategory() != pgtypes.TypeCategory_StringTypes {
return identityCast
}
// The "char" type is an exception to the built-in explicit cast for string types below
if fromType.GetRepresentativeType() == pgtypes.InternalChar || toType.GetRepresentativeType() == pgtypes.InternalChar {
return nil
}
tbantle22 marked this conversation as resolved.
Show resolved Hide resolved
// All types have a built-in explicit cast to string types: https://www.postgresql.org/docs/15/sql-createcast.html
if toType.GetTypeCategory() == pgtypes.TypeCategory_StringTypes {
return func(ctx *sql.Context, val any, targetType pgtypes.DoltgresType) (any, error) {
Expand Down Expand Up @@ -177,7 +181,7 @@ func GetAssignmentCast(fromType pgtypes.DoltgresTypeBaseID, toType pgtypes.Doltg
}
// We check for the identity after checking the maps, as the identity may be overridden (such as for types that have
// parameters). If the "to" type is a string type, then we do not use the identity, and use the I/O conversion below.
if fromType == toType && fromType.GetTypeCategory() != pgtypes.TypeCategory_StringTypes {
if fromType == toType {
tbantle22 marked this conversation as resolved.
Show resolved Hide resolved
return identityCast
}
// All types have a built-in assignment cast from string types: https://www.postgresql.org/docs/15/sql-createcast.html
Expand Down
3 changes: 3 additions & 0 deletions server/tables/information_schema/columns_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,9 @@ func getDataAndUdtType(colType sql.Type, colName string) (string, string) {
dgType, ok := colType.(pgtypes.DoltgresType)
if ok {
udtName = dgType.BaseName()
if udtName == `"char"` {
udtName = "char"
tbantle22 marked this conversation as resolved.
Show resolved Hide resolved
}
if t, ok := partypes.OidToType[oid.Oid(dgType.OID())]; ok {
dataType = t.SQLStandardName()
}
Expand Down
2 changes: 1 addition & 1 deletion server/tables/pgcatalog/pg_aggregate.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func (p PgAggregateHandler) Schema() sql.PrimaryKeySchema {
// pgAggregateSchema is the schema for pg_aggregate.
var pgAggregateSchema = sql.Schema{
{Name: "aggfnoid", Type: pgtypes.Text, Default: nil, Nullable: false, Source: PgAggregateName}, // TODO: regproc type
{Name: "aggkind", Type: pgtypes.BpChar, Default: nil, Nullable: false, Source: PgAggregateName},
{Name: "aggkind", Type: pgtypes.InternalChar, Default: nil, Nullable: false, Source: PgAggregateName},
{Name: "aggnumdirectargs", Type: pgtypes.Int16, Default: nil, Nullable: false, Source: PgAggregateName},
{Name: "aggtransfn", Type: pgtypes.Text, Default: nil, Nullable: false, Source: PgAggregateName}, // TODO: regproc type
{Name: "aggfinalfn", Type: pgtypes.Text, Default: nil, Nullable: false, Source: PgAggregateName}, // TODO: regproc type
Expand Down
2 changes: 1 addition & 1 deletion server/tables/pgcatalog/pg_am.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ var pgAmSchema = sql.Schema{
{Name: "oid", Type: pgtypes.Oid, Default: nil, Nullable: false, Source: PgAmName},
{Name: "amname", Type: pgtypes.Name, Default: nil, Nullable: false, Source: PgAmName},
{Name: "amhandler", Type: pgtypes.Text, Default: nil, Nullable: false, Source: PgAmName}, // TODO: type regproc
{Name: "amtype", Type: pgtypes.BpChar, Default: nil, Nullable: false, Source: PgAmName},
{Name: "amtype", Type: pgtypes.InternalChar, Default: nil, Nullable: false, Source: PgAmName},
}

// pgAmRowIter is the sql.RowIter for the pg_am table.
Expand Down
2 changes: 1 addition & 1 deletion server/tables/pgcatalog/pg_amop.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ var pgAmopSchema = sql.Schema{
{Name: "amoplefttype", Type: pgtypes.Oid, Default: nil, Nullable: false, Source: PgAmopName},
{Name: "amoprighttype", Type: pgtypes.Oid, Default: nil, Nullable: false, Source: PgAmopName},
{Name: "amopstrategy", Type: pgtypes.Int16, Default: nil, Nullable: false, Source: PgAmopName},
{Name: "amoppurpose", Type: pgtypes.BpChar, Default: nil, Nullable: false, Source: PgAmopName},
{Name: "amoppurpose", Type: pgtypes.InternalChar, Default: nil, Nullable: false, Source: PgAmopName},
{Name: "amopopr", Type: pgtypes.Oid, Default: nil, Nullable: false, Source: PgAmopName},
{Name: "amopmethod", Type: pgtypes.Oid, Default: nil, Nullable: false, Source: PgAmopName},
{Name: "amopsortfamily", Type: pgtypes.Oid, Default: nil, Nullable: false, Source: PgAmopName},
Expand Down
10 changes: 5 additions & 5 deletions server/tables/pgcatalog/pg_attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,14 @@ var pgAttributeSchema = sql.Schema{
{Name: "atttypmod", Type: pgtypes.Int32, Default: nil, Nullable: false, Source: PgAttributeName},
{Name: "attndims", Type: pgtypes.Int16, Default: nil, Nullable: false, Source: PgAttributeName},
{Name: "attbyval", Type: pgtypes.Bool, Default: nil, Nullable: false, Source: PgAttributeName},
{Name: "attalign", Type: pgtypes.BpChar, Default: nil, Nullable: false, Source: PgAttributeName},
{Name: "attstorage", Type: pgtypes.BpChar, Default: nil, Nullable: false, Source: PgAttributeName},
{Name: "attcompression", Type: pgtypes.BpChar, Default: nil, Nullable: false, Source: PgAttributeName},
{Name: "attalign", Type: pgtypes.InternalChar, Default: nil, Nullable: false, Source: PgAttributeName},
{Name: "attstorage", Type: pgtypes.InternalChar, Default: nil, Nullable: false, Source: PgAttributeName},
{Name: "attcompression", Type: pgtypes.InternalChar, Default: nil, Nullable: false, Source: PgAttributeName},
{Name: "attnotnull", Type: pgtypes.Bool, Default: nil, Nullable: false, Source: PgAttributeName},
{Name: "atthasdef", Type: pgtypes.Bool, Default: nil, Nullable: false, Source: PgAttributeName},
{Name: "atthasmissing", Type: pgtypes.Bool, Default: nil, Nullable: false, Source: PgAttributeName},
{Name: "attidentity", Type: pgtypes.BpChar, Default: nil, Nullable: false, Source: PgAttributeName},
{Name: "attgenerated", Type: pgtypes.BpChar, Default: nil, Nullable: false, Source: PgAttributeName},
{Name: "attidentity", Type: pgtypes.InternalChar, Default: nil, Nullable: false, Source: PgAttributeName},
{Name: "attgenerated", Type: pgtypes.InternalChar, Default: nil, Nullable: false, Source: PgAttributeName},
{Name: "attisdropped", Type: pgtypes.Bool, Default: nil, Nullable: false, Source: PgAttributeName},
{Name: "attislocal", Type: pgtypes.Bool, Default: nil, Nullable: false, Source: PgAttributeName},
{Name: "attinhcount", Type: pgtypes.Int16, Default: nil, Nullable: false, Source: PgAttributeName},
Expand Down
4 changes: 2 additions & 2 deletions server/tables/pgcatalog/pg_cast.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ var pgCastSchema = sql.Schema{
{Name: "castsource", Type: pgtypes.Oid, Default: nil, Nullable: false, Source: PgCastName},
{Name: "casttarget", Type: pgtypes.Oid, Default: nil, Nullable: false, Source: PgCastName},
{Name: "castfunc", Type: pgtypes.Oid, Default: nil, Nullable: false, Source: PgCastName},
{Name: "castcontext", Type: pgtypes.BpChar, Default: nil, Nullable: false, Source: PgCastName},
{Name: "castmethod", Type: pgtypes.BpChar, Default: nil, Nullable: false, Source: PgCastName},
{Name: "castcontext", Type: pgtypes.InternalChar, Default: nil, Nullable: false, Source: PgCastName},
{Name: "castmethod", Type: pgtypes.InternalChar, Default: nil, Nullable: false, Source: PgCastName},
}

// pgCastRowIter is the sql.RowIter for the pg_cast table.
Expand Down
6 changes: 3 additions & 3 deletions server/tables/pgcatalog/pg_class.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ var pgClassSchema = sql.Schema{
{Name: "reltoastrelid", Type: pgtypes.Oid, Default: nil, Nullable: false, Source: PgClassName},
{Name: "relhasindex", Type: pgtypes.Bool, Default: nil, Nullable: false, Source: PgClassName},
{Name: "relisshared", Type: pgtypes.Bool, Default: nil, Nullable: false, Source: PgClassName},
{Name: "relpersistence", Type: pgtypes.BpChar, Default: nil, Nullable: false, Source: PgClassName},
{Name: "relkind", Type: pgtypes.BpChar, Default: nil, Nullable: false, Source: PgClassName},
{Name: "relpersistence", Type: pgtypes.InternalChar, Default: nil, Nullable: false, Source: PgClassName},
{Name: "relkind", Type: pgtypes.InternalChar, Default: nil, Nullable: false, Source: PgClassName},
{Name: "relnatts", Type: pgtypes.Int16, Default: nil, Nullable: false, Source: PgClassName},
{Name: "relchecks", Type: pgtypes.Int16, Default: nil, Nullable: false, Source: PgClassName},
{Name: "relhasrules", Type: pgtypes.Bool, Default: nil, Nullable: false, Source: PgClassName},
Expand All @@ -137,7 +137,7 @@ var pgClassSchema = sql.Schema{
{Name: "relrowsecurity", Type: pgtypes.Bool, Default: nil, Nullable: false, Source: PgClassName},
{Name: "relforcerowsecurity", Type: pgtypes.Bool, Default: nil, Nullable: false, Source: PgClassName},
{Name: "relispopulated", Type: pgtypes.Bool, Default: nil, Nullable: false, Source: PgClassName},
{Name: "relreplident", Type: pgtypes.BpChar, Default: nil, Nullable: false, Source: PgClassName},
{Name: "relreplident", Type: pgtypes.InternalChar, Default: nil, Nullable: false, Source: PgClassName},
{Name: "relispartition", Type: pgtypes.Bool, Default: nil, Nullable: false, Source: PgClassName},
{Name: "relrewrite", Type: pgtypes.Oid, Default: nil, Nullable: false, Source: PgClassName},
{Name: "relfrozenxid", Type: pgtypes.Xid, Default: nil, Nullable: false, Source: PgClassName},
Expand Down
2 changes: 1 addition & 1 deletion server/tables/pgcatalog/pg_collation.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ var PgCollationSchema = sql.Schema{
{Name: "collname", Type: pgtypes.Name, Default: nil, Nullable: false, Source: PgCollationName},
{Name: "collnamespace", Type: pgtypes.Oid, Default: nil, Nullable: false, Source: PgCollationName},
{Name: "collowner", Type: pgtypes.Oid, Default: nil, Nullable: false, Source: PgCollationName},
{Name: "collprovider", Type: pgtypes.BpChar, Default: nil, Nullable: false, Source: PgCollationName},
{Name: "collprovider", Type: pgtypes.InternalChar, Default: nil, Nullable: false, Source: PgCollationName},
{Name: "collisdeterministic", Type: pgtypes.Bool, Default: nil, Nullable: false, Source: PgCollationName},
{Name: "collencoding", Type: pgtypes.Int32, Default: nil, Nullable: false, Source: PgCollationName},
{Name: "collcollate", Type: pgtypes.Text, Default: nil, Nullable: true, Source: PgCollationName}, // TODO: collation C
Expand Down
Loading
Loading