Skip to content

Commit

Permalink
Merge pull request #103 from nktks/fix/panic-fk-column
Browse files Browse the repository at this point in the history
support FOREIGN KEY without CONSTRAINTS clause
  • Loading branch information
double-di authored May 30, 2024
2 parents 211cd94 + ed75ced commit 6807aff
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 19 deletions.
11 changes: 8 additions & 3 deletions server/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -1274,20 +1274,25 @@ func (db *database) registerInformationSchemaTables(ctx context.Context, stmt *a
}
}

for _, tcnst := range stmt.TableConstraints {
for i, tcnst := range stmt.TableConstraints {
switch cnst := tcnst.Constraint.(type) {
case *ast.ForeignKey:
var onDeleteAction string
var constraintName string
switch cnst.OnDelete {
case ast.OnDeleteCascade:
onDeleteAction = `"CASCADE"`
default:
onDeleteAction = `"NO ACTION"`
}

if tcnst.Name != nil {
constraintName = tcnst.Name.Name
} else {
constraintName = fmt.Sprintf("FK_%s_%s_%d", tableName, cnst.ReferenceTable.Name, i)
}
query := fmt.Sprintf(
`INSERT INTO __INFORMATION_SCHEMA__REFERENTIAL_CONSTRAINTS VALUES("", "", %q, "", "", %q, "SIMPLE", "NO ACTION", %s, "COMMITTED")`,
tcnst.Name.Name, cnst.ReferenceTable.Name, onDeleteAction,
constraintName, cnst.ReferenceTable.Name, onDeleteAction,
)
if _, err := db.db.ExecContext(ctx, query); err != nil {
return fmt.Errorf("failed to insert into INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS for table %s: %v", tableName, err)
Expand Down
46 changes: 30 additions & 16 deletions server/database_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,10 @@ INTERLEAVE IN PARENT ParentTableNoAction ON DELETE NO ACTION;
CREATE TABLE ForeignChildCascade (
Id INT64 NOT NULL,
ForeignId INT64 NOT NULL,
ForeignSecondId INT64 NOT NULL,
Value STRING(MAX) NOT NULL,
CONSTRAINT FK_Cascade FOREIGN KEY (ForeignId) REFERENCES ForeignParentCascade (Id) ON DELETE CASCADE,
FOREIGN KEY (ForeignSecondId) REFERENCES ForeignParentCascade (Id) ON DELETE CASCADE,
) PRIMARY KEY(Id, ForeignId);
`

Expand All @@ -100,8 +102,10 @@ CREATE TABLE ForeignChildCascade (
CREATE TABLE ForeignChildNoAction (
Id INT64 NOT NULL,
ForeignId INT64 NOT NULL,
ForeignSecondId INT64 NOT NULL,
Value STRING(MAX) NOT NULL,
CONSTRAINT FK_NoAction FOREIGN KEY (ForeignId) REFERENCES ForeignParentNoAction (Id),
FOREIGN KEY (ForeignSecondId) REFERENCES ForeignParentNoAction (Id),
) PRIMARY KEY(Id, ForeignId);
`

Expand Down Expand Up @@ -3982,10 +3986,12 @@ func TestInformationSchema(t *testing.T) {
{"", "", "DefaultValues", "Date", int64(8), nil, nil, "NO", "TIMESTAMP"},
{"", "", "ForeignChildCascade", "Id", int64(1), nil, nil, "NO", "INT64"},
{"", "", "ForeignChildCascade", "ForeignId", int64(2), nil, nil, "NO", "INT64"},
{"", "", "ForeignChildCascade", "Value", int64(3), nil, nil, "NO", "STRING(MAX)"},
{"", "", "ForeignChildCascade", "ForeignSecondId", int64(3), nil, nil, "NO", "INT64"},
{"", "", "ForeignChildCascade", "Value", int64(4), nil, nil, "NO", "STRING(MAX)"},
{"", "", "ForeignChildNoAction", "Id", int64(1), nil, nil, "NO", "INT64"},
{"", "", "ForeignChildNoAction", "ForeignId", int64(2), nil, nil, "NO", "INT64"},
{"", "", "ForeignChildNoAction", "Value", int64(3), nil, nil, "NO", "STRING(MAX)"},
{"", "", "ForeignChildNoAction", "ForeignSecondId", int64(3), nil, nil, "NO", "INT64"},
{"", "", "ForeignChildNoAction", "Value", int64(4), nil, nil, "NO", "STRING(MAX)"},
{"", "", "ForeignParentCascade", "Id", int64(1), nil, nil, "NO", "INT64"},
{"", "", "ForeignParentCascade", "Value", int64(2), nil, nil, "NO", "STRING(MAX)"},
{"", "", "ForeignParentNoAction", "Id", int64(1), nil, nil, "NO", "INT64"},
Expand Down Expand Up @@ -4240,7 +4246,9 @@ func TestInformationSchema(t *testing.T) {
sql: `SELECT CONSTRAINT_CATALOG, CONSTRAINT_SCHEMA, CONSTRAINT_NAME, UNIQUE_CONSTRAINT_CATALOG, UNIQUE_CONSTRAINT_SCHEMA, UNIQUE_CONSTRAINT_NAME, MATCH_OPTION, UPDATE_RULE, DELETE_RULE, SPANNER_STATE FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS`,
expected: [][]interface{}{
{"", "", "FK_Cascade", "", "", "ForeignParentCascade", "SIMPLE", "NO ACTION", "CASCADE", "COMMITTED"},
{"", "", "FK_ForeignChildCascade_ForeignParentCascade_1", "", "", "ForeignParentCascade", "SIMPLE", "NO ACTION", "CASCADE", "COMMITTED"},
{"", "", "FK_NoAction", "", "", "ForeignParentNoAction", "SIMPLE", "NO ACTION", "NO ACTION", "COMMITTED"},
{"", "", "FK_ForeignChildNoAction_ForeignParentNoAction_1", "", "", "ForeignParentNoAction", "SIMPLE", "NO ACTION", "NO ACTION", "COMMITTED"},
},
},
}
Expand Down Expand Up @@ -4328,13 +4336,14 @@ func TestInsertUnderForeignConstraint(t *testing.T) {
"InsertWithoutMaster": {
child: &tableConfig{
tbl: "ForeignChildNoAction",
wcols: []string{"Id", "ForeignId", "Value"},
wcols: []string{"Id", "ForeignId", "ForeignSecondId", "Value"},
values: []*structpb.Value{
makeStringValue("100"),
makeStringValue("200"),
makeStringValue("200"),
makeStringValue("yyy"),
},
cols: []string{"Id", "ForeignId", "Value"},
cols: []string{"Id", "ForeignId", "ForeignSecondId", "Value"},
limit: 100,
expected: nil,
},
Expand All @@ -4356,16 +4365,17 @@ func TestInsertUnderForeignConstraint(t *testing.T) {
},
child: &tableConfig{
tbl: "ForeignChildNoAction",
wcols: []string{"Id", "ForeignId", "Value"},
wcols: []string{"Id", "ForeignId", "ForeignSecondId", "Value"},
values: []*structpb.Value{
makeStringValue("100"),
makeStringValue("200"),
makeStringValue("200"),
makeStringValue("yyy"),
},
cols: []string{"Id", "ForeignId", "Value"},
cols: []string{"Id", "ForeignId", "ForeignSecondId", "Value"},
limit: 100,
expected: [][]interface{}{
{int64(100), int64(200), "yyy"},
{int64(100), int64(200), int64(200), "yyy"},
},
},
expectsError: false,
Expand All @@ -4374,13 +4384,14 @@ func TestInsertUnderForeignConstraint(t *testing.T) {
"InsertWithoutMaster(Cascade)": {
child: &tableConfig{
tbl: "ForeignChildCascade",
wcols: []string{"Id", "ForeignId", "Value"},
wcols: []string{"Id", "ForeignId", "ForeignSecondId", "Value"},
values: []*structpb.Value{
makeStringValue("100"),
makeStringValue("200"),
makeStringValue("200"),
makeStringValue("yyy"),
},
cols: []string{"Id", "ForeignId", "Value"},
cols: []string{"Id", "ForeignId", "ForeignSecondId", "Value"},
limit: 100,
expected: nil,
},
Expand All @@ -4402,16 +4413,17 @@ func TestInsertUnderForeignConstraint(t *testing.T) {
},
child: &tableConfig{
tbl: "ForeignChildCascade",
wcols: []string{"Id", "ForeignId", "Value"},
wcols: []string{"Id", "ForeignId", "ForeignSecondId", "Value"},
values: []*structpb.Value{
makeStringValue("100"),
makeStringValue("200"),
makeStringValue("200"),
makeStringValue("yyy"),
},
cols: []string{"Id", "ForeignId", "Value"},
cols: []string{"Id", "ForeignId", "ForeignSecondId", "Value"},
limit: 100,
expected: [][]interface{}{
{int64(100), int64(200), "yyy"},
{int64(100), int64(200), int64(200), "yyy"},
},
},
expectsError: false,
Expand Down Expand Up @@ -4486,13 +4498,14 @@ func TestDeleteUnderForeignConstraint(t *testing.T) {
},
child: &tableConfig{
tbl: "ForeignChildNoAction",
wcols: []string{"Id", "ForeignId", "Value"},
wcols: []string{"Id", "ForeignId", "ForeignSecondId", "Value"},
values: []*structpb.Value{
makeStringValue("100"),
makeStringValue("200"),
makeStringValue("200"),
makeStringValue("yyy"),
},
cols: []string{"Id", "ForeignId", "Value"},
cols: []string{"Id", "ForeignId", "ForeignSecondId", "Value"},
ks: &KeySet{
Keys: []*structpb.ListValue{
makeListValue(
Expand Down Expand Up @@ -4521,13 +4534,14 @@ func TestDeleteUnderForeignConstraint(t *testing.T) {
},
child: &tableConfig{
tbl: "ForeignChildCascade",
wcols: []string{"Id", "ForeignId", "Value"},
wcols: []string{"Id", "ForeignId", "ForeignSecondId", "Value"},
values: []*structpb.Value{
makeStringValue("100"),
makeStringValue("200"),
makeStringValue("200"),
makeStringValue("yyy"),
},
cols: []string{"Id", "ForeignId", "Value"},
cols: []string{"Id", "ForeignId", "ForeignSecondId", "Value"},
ks: &KeySet{
Keys: []*structpb.ListValue{
makeListValue(
Expand Down

0 comments on commit 6807aff

Please sign in to comment.