Skip to content
Open
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
88 changes: 86 additions & 2 deletions internal/migration_acceptance_tests/function_cases_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ var functionAcceptanceTestCases = []acceptanceTestCase{
LANGUAGE SQL
IMMUTABLE
RETURNS NULL ON NULL INPUT
RETURN CONCAT(a, b);
RETURN CONCAT(a, b);
`},
expectedHazardTypes: []diff.MigrationHazardType{diff.MigrationHazardTypeHasUntrackableDependencies},
},
Expand Down Expand Up @@ -246,7 +246,7 @@ var functionAcceptanceTestCases = []acceptanceTestCase{
LANGUAGE SQL
IMMUTABLE
RETURNS NULL ON NULL INPUT
RETURN CONCAT(a, b);
RETURN CONCAT(a, b);
`,
},
expectedHazardTypes: []diff.MigrationHazardType{diff.MigrationHazardTypeHasUntrackableDependencies},
Expand Down Expand Up @@ -571,6 +571,90 @@ var functionAcceptanceTestCases = []acceptanceTestCase{
},
expectedHazardTypes: []diff.MigrationHazardType{diff.MigrationHazardTypeHasUntrackableDependencies},
},

{
name: "Non-sql function used a default for a column",
oldSchemaDDL: nil,
newSchemaDDL: []string{
`
CREATE FUNCTION add() RETURNS text
LANGUAGE plpgsql
AS $$
declare
begin
return 'hi';
end;
$$;

CREATE TABLE foobar (
foo text DEFAULT add() NOT NULL
);

`,
},
expectedHazardTypes: []diff.MigrationHazardType{diff.MigrationHazardTypeHasUntrackableDependencies},
},
{
name: "Deletion of non-sql function used a default for a column",
oldSchemaDDL: []string{
`
CREATE FUNCTION add() RETURNS text
LANGUAGE plpgsql
AS $$
declare
begin
return 'hi';
end;
$$;

CREATE TABLE foobar (
foo text DEFAULT add() NOT NULL
);

`,
},
newSchemaDDL: nil,
expectedHazardTypes: []diff.MigrationHazardType{diff.MigrationHazardTypeHasUntrackableDependencies, diff.MigrationHazardTypeDeletesData},
},

{
name: "Sql function used a default for a column",
oldSchemaDDL: nil,
newSchemaDDL: []string{
`
CREATE FUNCTION add() RETURNS text
LANGUAGE SQL
IMMUTABLE
RETURNS NULL ON NULL INPUT
RETURN 'hi';

CREATE TABLE foobar (
foo text DEFAULT add() NOT NULL
);

`,
},
expectedHazardTypes: []diff.MigrationHazardType{},
},
{
name: "Deletion of sql function used a default for a column",
oldSchemaDDL: []string{
`
CREATE FUNCTION add() RETURNS text
LANGUAGE SQL
IMMUTABLE
RETURNS NULL ON NULL INPUT
RETURN 'hi';

CREATE TABLE foobar (
foo text DEFAULT add() NOT NULL
);

`,
},
newSchemaDDL: nil,
expectedHazardTypes: []diff.MigrationHazardType{diff.MigrationHazardTypeDeletesData},
},
}

func (suite *acceptanceTestSuite) TestFunctionTestCases() {
Expand Down
2 changes: 1 addition & 1 deletion internal/queries/dml.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions internal/queries/models.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion internal/queries/queries.sql
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ SELECT
identity_col_seq.seqmin AS min_value,
identity_col_seq.seqcache AS cache_size,
identity_col_seq.seqcycle AS is_cycle,
pg_catalog.format_type(a.atttypid, a.atttypmod) AS column_type
pg_catalog.format_type(a.atttypid, a.atttypmod) AS column_type,
default_value.oid AS default_value_oid
FROM pg_catalog.pg_attribute AS a
LEFT JOIN
pg_catalog.pg_attrdef AS d
Expand All @@ -117,6 +118,11 @@ LEFT JOIN
ON
a.attrelid = identity_col_seq.owner_relid
AND a.attnum = identity_col_seq.owner_attnum
LEFT JOIN
pg_catalog.pg_attrdef AS default_value
ON
a.attrelid = default_value.adrelid
AND a.attnum = default_value.adnum
WHERE
a.attrelid = $1
AND a.attnum > 0
Expand Down
10 changes: 9 additions & 1 deletion internal/queries/queries.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 12 additions & 3 deletions internal/schema/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,8 @@ type (
// It is used for data-packing purposes
Size int
Identity *ColumnIdentity

DependsOnFunctions []SchemaQualifiedName
}
)

Expand Down Expand Up @@ -878,6 +880,11 @@ func (s *schemaFetcher) buildTable(
}
}

dependsOnFunctions, _ := s.fetchDependsOnFunctions(ctx, "pg_attrdef", column.DefaultValueOid)
if err != nil {
return Table{}, fmt.Errorf("fetchDependsOnFunctions(%s): %w", column.DefaultValueOid, err)
}

columns = append(columns, Column{
Name: column.ColumnName,
Type: column.ColumnType,
Expand All @@ -888,9 +895,10 @@ func (s *schemaFetcher) buildTable(
// ''::text
// CURRENT_TIMESTAMP
// If empty, indicates that there is no default value.
Default: column.DefaultValue,
Size: int(column.ColumnSize),
Identity: identity,
Default: column.DefaultValue,
Size: int(column.ColumnSize),
Identity: identity,
DependsOnFunctions: dependsOnFunctions,
})
}

Expand All @@ -905,6 +913,7 @@ func (s *schemaFetcher) buildTable(
SchemaName: table.TableSchemaName,
EscapedName: EscapeIdentifier(table.TableName),
}

return Table{
SchemaQualifiedName: schemaQualifiedName,
Columns: columns,
Expand Down
35 changes: 31 additions & 4 deletions pkg/diff/sql_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -1074,6 +1074,13 @@ func (t *tableSQLVertexGenerator) GetAddAlterDependencies(table, _ schema.Table)
mustRun(t.GetSQLVertexId(table, diffTypeAddAlter)).after(buildTableVertexId(*table.ParentTable, diffTypeAddAlter)),
)
}

for _, col := range table.Columns {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the currently awkward part about column sql generation: add/delete of columns is pushed under table add/alter.

As a result, what I believe you need to do:

  • If the column is new/altered, then you need to build a dependency between the table and the function such that function add/alter comes BEFORE the table add/alter
  • If the column is being deleted, then you need to build a dependency between the table and the function such that the function deletes comes BEFORE the table add/alter
    ^
    The same is true if the table is being totally created or totally deleted.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but that what I'm doing no ?

Here we're in table add/alter, and we add a dep for each column's function that have a dependency, and just bellow the delete (in opposite mode)

diffTypeDelete may be wrong there however ^^'

for _, depFunction := range col.DependsOnFunctions {
deps = append(deps, mustRun(t.GetSQLVertexId(table, diffTypeDelete)).after(buildFunctionVertexId(depFunction, diffTypeDelete)))
}
}

return deps, nil
}

Expand Down Expand Up @@ -1142,6 +1149,13 @@ func (t *tableSQLVertexGenerator) GetDeleteDependencies(table schema.Table) ([]d
mustRun(t.GetSQLVertexId(table, diffTypeDelete)).after(buildTableVertexId(*table.ParentTable, diffTypeDelete)),
)
}

for _, col := range table.Columns {
for _, depFunction := range col.DependsOnFunctions {
deps = append(deps, mustRun(t.GetSQLVertexId(table, diffTypeDelete)).before(buildFunctionVertexId(depFunction, diffTypeDelete)))
}
}

return deps, nil
}

Expand Down Expand Up @@ -1407,13 +1421,26 @@ func buildColumnVertexId(columnName string, diffType diffType) sqlVertexId {
}

func (csg *columnSQLVertexGenerator) GetAddAlterDependencies(col, _ schema.Column) ([]dependency, error) {
return []dependency{

var deps []dependency = []dependency{
mustRun(csg.GetSQLVertexId(col, diffTypeDelete)).before(csg.GetSQLVertexId(col, diffTypeAddAlter)),
}, nil
}

for _, depFunction := range col.DependsOnFunctions {
deps = append(deps, mustRun(csg.GetSQLVertexId(col, diffTypeDelete)).after(buildFunctionVertexId(depFunction, diffTypeDelete)))
}

return deps, nil

}

func (csg *columnSQLVertexGenerator) GetDeleteDependencies(_ schema.Column) ([]dependency, error) {
return nil, nil
func (csg *columnSQLVertexGenerator) GetDeleteDependencies(col schema.Column) ([]dependency, error) {

var deps []dependency
for _, depFunction := range col.DependsOnFunctions {
deps = append(deps, mustRun(csg.GetSQLVertexId(col, diffTypeDelete)).before(buildFunctionVertexId(depFunction, diffTypeDelete)))
}
return deps, nil
Comment on lines +1424 to +1443
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this does nothing right now, because the functions exist in the root graph. Ideally, we merge the graphs, but that's too much effort right now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So they should be removed ?

}

type renameConflictingIndexSQLVertexGenerator struct {
Expand Down