Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions server/ast/alter_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ func nodeAlterTableCmds(
statement, err = nodeAlterTableAddColumn(cmd, tableName, ifExists)
case *tree.AlterTableDropColumn:
statement, err = nodeAlterTableDropColumn(cmd, tableName, ifExists)
case *tree.AlterTableDropConstraint:
statement, err = nodeAlterTableDropConstraint(cmd, tableName, ifExists)
case *tree.AlterTableRenameColumn:
statement, err = nodeAlterTableRenameColumn(cmd, tableName, ifExists)
case *tree.AlterTableSetDefault:
Expand Down Expand Up @@ -116,6 +118,8 @@ func nodeAlterTableAddConstraint(
}

switch constraintDef := node.ConstraintDef.(type) {
case *tree.CheckConstraintTableDef:
return nodeCheckConstraintTableDef(constraintDef, tableName, ifExists)
case *tree.UniqueConstraintTableDef:
return nodeUniqueConstraintTableDef(constraintDef, tableName, ifExists)
case *tree.ForeignKeyConstraintTableDef:
Expand Down
92 changes: 80 additions & 12 deletions server/ast/constraint_table_def.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,73 @@ import (
"github.com/dolthub/doltgresql/postgres/parser/sem/tree"
)

// nodeCheckConstraintTableDef converts a tree.CheckConstraintTableDef instance
// into a vitess.DDL instance that can be executed by GMS. |tableName| identifies
// the table being altered, and |ifExists| indicates whether the IF EXISTS clause
// was specified.
func nodeCheckConstraintTableDef(
node *tree.CheckConstraintTableDef,
tableName vitess.TableName,
ifExists bool) (*vitess.DDL, error) {

if node.NoInherit {
return nil, fmt.Errorf("NO INHERIT is not yet supported for check constraints")
}

expr, err := nodeExpr(node.Expr)
if err != nil {
return nil, err
}

return &vitess.DDL{
Action: "alter",
Table: tableName,
IfExists: ifExists,
ConstraintAction: "add",
TableSpec: &vitess.TableSpec{
Constraints: []*vitess.ConstraintDefinition{
{
Name: node.Name.String(),
Details: &vitess.CheckConstraintDefinition{
Expr: expr,
Enforced: true,
},
},
},
},
}, nil
}

// nodeAlterTableDropConstraint converts a tree.AlterTableDropConstraint instance
// into a vitess.DDL instance that can be executed by GMS. |tableName| identifies
// the table being altered, and |ifExists| indicates whether the IF EXISTS clause
// was specified.
func nodeAlterTableDropConstraint(
node *tree.AlterTableDropConstraint,
tableName vitess.TableName,
ifExists bool) (*vitess.DDL, error) {

if node.DropBehavior == tree.DropCascade {
return nil, fmt.Errorf("CASCADE is not yet supported for drop constraint")
}

if node.IfExists {
return nil, fmt.Errorf("IF EXISTS is not yet supported for drop constraint")
}

return &vitess.DDL{
Action: "alter",
Table: tableName,
IfExists: ifExists,
ConstraintAction: "drop",
TableSpec: &vitess.TableSpec{
Constraints: []*vitess.ConstraintDefinition{
{Name: node.Constraint.String()},
},
},
}, nil
}

// nodeUniqueConstraintTableDef converts a tree.UniqueConstraintTableDef instance
// into a vitess.DDL instance that can be executed by GMS. |tableName| identifies
// the table being altered, and |ifExists| indicates whether the IF EXISTS clause
Expand All @@ -48,18 +115,19 @@ func nodeUniqueConstraintTableDef(
return nil, err
}

indexType := "unique"
if node.PrimaryKey {
return &vitess.DDL{
Action: "alter",
Table: tableName,
IfExists: ifExists,
IndexSpec: &vitess.IndexSpec{
Action: "create",
Type: "primary",
Columns: columns,
},
}, nil
} else {
return nil, fmt.Errorf("Only PRIMARY KEY constraints are supported currently")
indexType = "primary"
}

return &vitess.DDL{
Action: "alter",
Table: tableName,
IfExists: ifExists,
IndexSpec: &vitess.IndexSpec{
Action: "create",
Type: indexType,
Columns: columns,
},
}, nil
}
3 changes: 3 additions & 0 deletions server/ast/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,9 @@ func nodeExpr(node tree.Expr) (vitess.Expr, error) {
return retExpr, nil
case *tree.StrVal:
// TODO: determine what to do when node.WasScannedAsBytes() is true
// For string literals, we mark the type as unknown, because Postgres has
// more permissive implicit casting rules for literals than it does for strongly
// typed values from a schema for example.
unknownLiteral := pgexprs.NewUnknownLiteral(node.RawString())
return vitess.InjectedExpr{
Expression: unknownLiteral,
Expand Down
9 changes: 8 additions & 1 deletion server/ast/select.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package ast

import (
"fmt"
"strings"

vitess "github.com/dolthub/vitess/go/vt/sqlparser"

Expand Down Expand Up @@ -157,10 +158,16 @@ func nodeSelectExpr(node tree.SelectExpr) (vitess.SelectExpr, error) {
if ce, ok := expr.(*tree.CastExpr); ok && node.As == "" {
node.As = tree.UnrestrictedName(tree.AsString(ce.Expr))
}
// To be consistent with vitess handling, InputExpression always gets its outer qoutes trimmed
inputExpression := tree.AsString(&node)
if strings.HasPrefix(inputExpression, "'") && strings.HasSuffix(inputExpression, "'") {
inputExpression = inputExpression[1 : len(inputExpression)-1]
}

return &vitess.AliasedExpr{
Expr: vitessExpr,
As: vitess.NewColIdent(string(node.As)),
InputExpression: tree.AsString(&node),
InputExpression: inputExpression,
}, nil
}
}
Expand Down
75 changes: 75 additions & 0 deletions testing/go/alter_table_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,81 @@ func TestAlterTable(t *testing.T) {
},
},
},
{
Name: "Add Unique Constraint",
SetUpScript: []string{
"create table t1 (pk int primary key, c1 int);",
"insert into t1 values (1,1);",
"create table t2 (pk int primary key, c1 int);",
"insert into t2 values (1,1);",
},
Assertions: []ScriptTestAssertion{
{
// Add a secondary unique index using create index
Query: "CREATE UNIQUE INDEX ON t1(c1);",
Expected: []sql.Row{},
},
{
// Test that the unique constraint is working
Query: "INSERT INTO t1 VALUES (2, 1);",
ExpectedErr: "unique",
},
{
// Add a secondary unique index using alter table
Query: "ALTER TABLE t2 ADD CONSTRAINT uniq1 UNIQUE (c1);",
Expected: []sql.Row{},
},
{
// Test that the unique constraint is working
Query: "INSERT INTO t2 VALUES (2, 1);",
ExpectedErr: "unique",
},
},
},
{
Name: "Add Check Constraint",
SetUpScript: []string{
"create table t1 (pk int primary key, c1 int);",
"insert into t1 values (1,1);",
},
Assertions: []ScriptTestAssertion{
{
// Add a check constraint that is already violated by the existing data
Query: "ALTER TABLE t1 ADD CONSTRAINT constraint1 CHECK (c1 > 100);",
ExpectedErr: "violated",
},
{
// Add a check constraint
Query: "ALTER TABLE t1 ADD CONSTRAINT constraint1 CHECK (c1 < 100);",
Expected: []sql.Row{},
},
{
Query: "INSERT INTO t1 VALUES (2, 2);",
Expected: []sql.Row{},
},
{
Query: "INSERT INTO t1 VALUES (3, 101);",
ExpectedErr: "violated",
},
},
},
{
Name: "Drop Constraint",
SetUpScript: []string{
"create table t1 (pk int primary key, c1 int);",
"ALTER TABLE t1 ADD CONSTRAINT constraint1 CHECK (c1 > 100);",
},
Assertions: []ScriptTestAssertion{
{
Query: "ALTER TABLE t1 DROP CONSTRAINT constraint1;",
Expected: []sql.Row{},
},
{
Query: "INSERT INTO t1 VALUES (1, 1);",
Expected: []sql.Row{},
},
},
},
{
Name: "Add Primary Key",
SetUpScript: []string{
Expand Down
Loading