Skip to content

Commit 04b8243

Browse files
committed
Fixed issues 2299, 2301, and 2307
1 parent b80aedc commit 04b8243

File tree

11 files changed

+2249
-5
lines changed

11 files changed

+2249
-5
lines changed

server/analyzer/resolve_type.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,21 @@ func ResolveTypeForNodes(ctx *sql.Context, a *analyzer.Analyzer, node sql.Node,
9797
same = transform.NewTree
9898
col.Type = dt
9999
}
100+
resolvedDefault, err := resolveDefaultColumnType(ctx, col.Default)
101+
if err != nil {
102+
return nil, transform.NewTree, err
103+
}
104+
resolvedGenerated, err := resolveDefaultColumnType(ctx, col.Generated)
105+
if err != nil {
106+
return nil, transform.NewTree, err
107+
}
108+
resolvedOnUpdate, err := resolveDefaultColumnType(ctx, col.OnUpdate)
109+
if err != nil {
110+
return nil, transform.NewTree, err
111+
}
112+
if resolvedDefault || resolvedGenerated || resolvedOnUpdate {
113+
same = transform.NewTree
114+
}
100115
}
101116
return node, same, nil
102117
case *plan.ModifyColumn:
@@ -187,3 +202,19 @@ func resolveType(ctx *sql.Context, typ *pgtypes.DoltgresType) (*pgtypes.Doltgres
187202
}
188203
return resolvedTyp, nil
189204
}
205+
206+
// resolveDefaultColumnType resolves the OutType of a *sql.ColumnDefaultValue if it's not nil (and not already resolved).
207+
func resolveDefaultColumnType(ctx *sql.Context, defaultVal *sql.ColumnDefaultValue) (bool, error) {
208+
if defaultVal == nil {
209+
return false, nil
210+
}
211+
if rt, ok := defaultVal.OutType.(*pgtypes.DoltgresType); ok && !rt.IsResolvedType() {
212+
dt, err := resolveType(ctx, rt)
213+
if err != nil {
214+
return false, err
215+
}
216+
defaultVal.OutType = dt
217+
return true, nil
218+
}
219+
return false, nil
220+
}

server/analyzer/type_sanitizer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ func TypeSanitizer(ctx *sql.Context, a *analyzer.Analyzer, node sql.Node, scope
8383
}
8484
}
8585
case *plan.ExistsSubquery:
86-
return pgexprs.NewGMSCast(expr), transform.NewTree, nil
86+
return pgexprs.NewExplicitCast(pgexprs.NewGMSCast(expr), pgtypes.Bool), transform.NewTree, nil
8787
case *sql.ColumnDefaultValue:
8888
// Due to how interfaces work, we sometimes pass (*ColumnDefaultValue)(nil), so we have to check for it
8989
if expr != nil && expr.Expr != nil {

server/doltgres_handler.go

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import (
3434
"github.com/dolthub/go-mysql-server/server"
3535
"github.com/dolthub/go-mysql-server/sql"
3636
"github.com/dolthub/go-mysql-server/sql/analyzer"
37+
"github.com/dolthub/go-mysql-server/sql/expression"
3738
"github.com/dolthub/go-mysql-server/sql/plan"
3839
"github.com/dolthub/go-mysql-server/sql/types"
3940
"github.com/dolthub/vitess/go/mysql"
@@ -45,6 +46,7 @@ import (
4546
"github.com/dolthub/doltgresql/core/id"
4647
"github.com/dolthub/doltgresql/postgres/parser/uuid"
4748
pgexprs "github.com/dolthub/doltgresql/server/expression"
49+
pgtransform "github.com/dolthub/doltgresql/server/transform"
4850
pgtypes "github.com/dolthub/doltgresql/server/types"
4951
)
5052

@@ -158,14 +160,33 @@ func (h *DoltgresHandler) ComPrepareParsed(ctx context.Context, c *mysql.Conn, q
158160
return nil, nil, err
159161
}
160162

161-
analyzed, err := h.e.PrepareParsedQuery(sqlCtx, query, query, parsed)
163+
node, err := h.e.PrepareParsedQuery(sqlCtx, query, query, parsed)
162164
if err != nil {
163165
if printErrorStackTraces {
164166
fmt.Printf("unable to prepare query: %+v\n", err)
165167
}
166168
logrus.WithField("query", query).Errorf("unable to prepare query: %s", err.Error())
167-
err := sql.CastSQLError(err)
168-
return nil, nil, err
169+
return nil, nil, sql.CastSQLError(err)
170+
}
171+
analyzed := node
172+
// We do not analyze expressions with bind variables, since that step comes later and analysis will return invalid results
173+
hasBindVars := false
174+
pgtransform.InspectNodeExprs(node, func(expr sql.Expression) bool {
175+
if _, ok := expr.(*expression.BindVar); ok {
176+
hasBindVars = true
177+
return true
178+
}
179+
return false
180+
})
181+
if !hasBindVars {
182+
analyzed, err = h.e.Analyzer.Analyze(sqlCtx, node, nil, nil)
183+
if err != nil {
184+
if printErrorStackTraces {
185+
fmt.Printf("unable to prepare query: %+v\n", err)
186+
}
187+
logrus.WithField("query", query).Errorf("unable to prepare query: %s", err.Error())
188+
return nil, nil, sql.CastSQLError(err)
189+
}
169190
}
170191

171192
var fields []pgproto3.FieldDescription

server/types/serialization.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ func init() {
3636
// by DoltgreSQL.
3737
func SerializeType(extendedType sql.ExtendedType) ([]byte, error) {
3838
if doltgresType, ok := extendedType.(*DoltgresType); ok {
39+
if doltgresType.IsUnresolved {
40+
return nil, errors.Errorf(`attempted to serialize the unresolved type: %s`, doltgresType.Name())
41+
}
3942
return doltgresType.Serialize(), nil
4043
}
4144
return nil, errors.Errorf("unknown type to serialize")

testing/PostgresDockerfile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ RUN apt update -y && \
4242
postgresql-server-dev-15 && \
4343
update-ca-certificates -f
4444

45+
# install rust (cargo)
46+
ENV RUSTUP_HOME=/root/.rustup \
47+
CARGO_HOME=/root/.cargo
48+
ENV PATH="${CARGO_HOME}/bin:${PATH}"
49+
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --profile minimal && \
50+
rustc --version && cargo --version
51+
4552
# install go
4653
WORKDIR /root
4754
ENV GO_VERSION=1.23.3

testing/go/framework.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,12 @@ type ScriptTestAssertion struct {
122122
// This is checked only if no Expected is defined
123123
ExpectedTag string
124124

125-
// ExpectedColNames is used to check the column names returned from the server.
125+
// ExpectedColNames are used to check the column names returned from the server.
126126
ExpectedColNames []string
127127

128+
// ExpectedColTypes are used to check the column types returned from the server.
129+
ExpectedColTypes []id.Type
130+
128131
// CopyFromSTDIN is used to test the COPY FROM STDIN command.
129132
CopyFromStdInFile string
130133
}
@@ -274,6 +277,17 @@ func runScript(t *testing.T, ctx context.Context, script ScriptTest, conn *Conne
274277
}
275278
}
276279
}
280+
if assertion.ExpectedColTypes != nil {
281+
fields := rows.FieldDescriptions()
282+
if assert.Len(t, fields, len(assertion.ExpectedColTypes),
283+
"columns returned and types expected are not the same length") {
284+
for i, colId := range assertion.ExpectedColTypes {
285+
assert.Equal(t, id.Cache().ToOID(colId.AsId()), fields[i].DataTypeOID,
286+
`"%s" expected type "%s" but received "%s"`, fields[i].Name,
287+
colId.TypeName(), id.Type(id.Cache().ToInternal(fields[i].DataTypeOID)).TypeName())
288+
}
289+
}
290+
}
277291

278292
// not an exact match but works well enough for our tests
279293
orderBy := strings.Contains(strings.ToLower(assertion.Query), "order by")

testing/go/issues_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ import (
1818
"testing"
1919

2020
"github.com/dolthub/go-mysql-server/sql"
21+
22+
"github.com/dolthub/doltgresql/core/id"
23+
pgtypes "github.com/dolthub/doltgresql/server/types"
2124
)
2225

2326
func TestIssues(t *testing.T) {
@@ -366,5 +369,38 @@ limit 1`,
366369
},
367370
},
368371
},
372+
{
373+
Name: "Issue #2299",
374+
SetUpScript: []string{
375+
"CREATE TYPE team_role AS ENUM ('admin', 'editor', 'member');",
376+
},
377+
Assertions: []ScriptTestAssertion{
378+
{
379+
Query: `CREATE TABLE users (id UUID PRIMARY KEY DEFAULT gen_random_uuid(), role team_role NOT NULL DEFAULT 'member');`,
380+
Expected: []sql.Row{},
381+
},
382+
{
383+
Query: `INSERT INTO users (role) VALUES (DEFAULT);`,
384+
Expected: []sql.Row{},
385+
},
386+
{
387+
Query: `SELECT role FROM users;`,
388+
Expected: []sql.Row{{"member"}},
389+
},
390+
},
391+
},
392+
{
393+
Name: "Issue #2307",
394+
SetUpScript: []string{
395+
"CREATE TABLE test (pk INT4);",
396+
},
397+
Assertions: []ScriptTestAssertion{
398+
{
399+
Query: `SELECT EXISTS(SELECT 1 FROM pg_catalog.pg_tables WHERE tablename = 'test');`,
400+
ExpectedColTypes: []id.Type{pgtypes.Bool.ID},
401+
Expected: []sql.Row{{"t"}},
402+
},
403+
},
404+
},
369405
})
370406
}

testing/postgres-client-tests/postgres-client-tests.bats

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,9 @@ teardown() {
7676
@test "python postgres: sqlalcchemy client" {
7777
cd $BATS_TEST_DIRNAME/python
7878
python3 sqlalchemy-test.py $USER $PORT
79+
}
80+
81+
@test "rust sqlx" {
82+
cd $BATS_TEST_DIRNAME/rust
83+
cargo run -- $USER $PORT
7984
}

0 commit comments

Comments
 (0)