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

sql2pgroll: Support set and drop column defaults #526

Merged
merged 6 commits into from
Dec 11, 2024

Conversation

ryanslade
Copy link
Collaborator

@ryanslade ryanslade commented Dec 11, 2024

Support translating the following alter table statements into pgroll operations:

ALTER TABLE foo COLUMN bar SET DEFAULT 'foo'
ALTER TABLE foo COLUMN bar SET DEFAULT 123
ALTER TABLE foo COLUMN bar SET DEFAULT 123.456
ALTER TABLE foo COLUMN bar SET DEFAULT true
ALTER TABLE foo COLUMN bar SET DEFAULT B'0101'
ALTER TABLE foo COLUMN bar SET DEFAULT null
ALTER TABLE foo COLUMN bar DROP DEFAULT

For cases where the default is set to something other than a simple literal, we fall back to raw SQL.

//
// to an OpDropColumn operation.
// to an OpAlterColumn operation.
func convertAlterTableSetColumnDefault(stmt *pgq.AlterTableStmt, cmd *pgq.AlterTableCmd) (migrations.Operation, error) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Since OpAlterColumn only supports nullable string defaults, this will fail for any other kind of default for example non strings or the value of a function call.

In those cases should we fall back to raw sql?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It looks like if the new default value is a constant, we can support these types:

type A_Const struct {
	state         protoimpl.MessageState
	sizeCache     protoimpl.SizeCache
	unknownFields protoimpl.UnknownFields

	// Types that are assignable to Val:
	//
	//	*A_Const_Ival
	//	*A_Const_Fval
	//	*A_Const_Boolval
	//	*A_Const_Sval
	//	*A_Const_Bsval
	Val      isA_Const_Val `protobuf_oneof:"val"`
	Isnull   bool          `protobuf:"varint,10,opt,name=isnull,proto3" json:"isnull,omitempty"`
	Location int32         `protobuf:"varint,11,opt,name=location,proto3" json:"location,omitempty"`
}

And then convert them to a string

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I've done this

Copy link
Collaborator

@andrew-farries andrew-farries left a comment

Choose a reason for hiding this comment

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

This is a good start 👍

This won't work for all types of column default though:

-- integers
ALTER TABLE foo ALTER COLUMN bar SET DEFAULT 2
-- booleans
ALTER TABLE foo ALTER COLUMN bar SET DEFAULT true
-- floating point values
ALTER TABLE foo ALTER COLUMN bar SET DEFAULT 2.0
-- bitstrings
ALTER TABLE foo ALTER COLUMN bar SET DEFAULT B'10101010'
-- function calls
ALTER TABLE foo ALTER COLUMN bar SET DEFAULT NOW()

These cases all have a different AST structure and need to be handled separately. In general a column DEFAULT can be an expression of arbitrary complexity, such as:

ALTER TABLE foo ALTER COLUMN bar SET DEFAULT (CASE WHEN EXTRACT(DOW FROM CURRENT_TIMESTAMP) IN (0, 6) THEN 1 ELSE 5 END)

In the latter case I think we need to make changes to the pg_query_go dependency to support deparsing arbitrary SQL expressions, rather than only the full SQL statements that it currently supports.

For now we should aim to convert DEFAULT expressions where the expression is a simple literal:

  • integer
  • boolean
  • floating point
  • bit string

We can leave handling function calls and more complex SQL until later.

@ryanslade
Copy link
Collaborator Author

Cool, that's exactly what I did 😄

I'll throw in a test case where it's a function value, for example now() and fall back to raw SQL in that case.

@ryanslade
Copy link
Collaborator Author

@andrew-farries Ok, I think I've handled all the cases now.

@ryanslade ryanslade merged commit f429ee2 into main Dec 11, 2024
28 checks passed
@ryanslade ryanslade deleted the rs/set-and-drop-defaults branch December 11, 2024 16:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants