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

Reporting unique nulls not distinct in analyze schema and assessment report #2125

Merged
merged 16 commits into from
Jan 9, 2025

Conversation

ShivanshGahlot
Copy link
Collaborator

Describe the changes in this pull request

Reporting UNIQUE NULLS NOT DISTINCT feature in CREATE and ALTER TABLE as unsupported in the analyze schema report and migration assessment report.
Issue:
#1978

Describe if there are any user-facing changes

Changes in assessment report:
image

Changes in schema report:
image

How was this pull request tested?

Tested locally
Also added unit tests and end to end tests

Does your PR have changes that can cause upgrade issues?

Component Breaking changes?
MetaDB No
Name registry json No
Data File Descriptor Json No
Export Snapshot Status Json No
Import Data State No
Export Status Json No
Data .sql files of tables No
Export and import data queue No
Schema Dump No
AssessmentDB No
Sizing DB No
Migration Assessment Report Json No
Callhome Json No
YugabyteD Tables No
TargetDB Metadata Tables No

);

ALTER TABLE sales_unique_nulls_not_distinct_alter
ADD CONSTRAINT sales_unique_nulls_not_distinct_alter_unique UNIQUE NULLS NOT DISTINCT (store_id, product_id, sale_date);
Copy link
Collaborator

Choose a reason for hiding this comment

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

This can also come up as a CREATE UNIQUE INDEX not just constraints.. https://www.postgresql.org/docs/current/indexes-unique.html

I think we should check for that as well? cc: @priyanshi-yb

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 have added check for CREATE UNIQUE INDEX too and am using struct now.

if indexStmt.Unique && indexStmt.NullsNotDistinct {
d.detected = true
}
} else if queryparser.GetMsgFullName(msg) == queryparser.PG_QUERY_TABLECONSTRAINT_NODE {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Will this node come up for both ALTER TABLE ADD CONSTRAINT as well as CREATE TABLE ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yep it does

Copy link
Collaborator

Choose a reason for hiding this comment

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

nice. I was initially going to suggest we write this code inside tableIssueDetector and alterTableIssueDetector, but this is useful, since we just have to find the constraint node and check.
cc: @priyanshi-yb

// Detect checks if a unique constraint is defined which has nulls not distinct
func (d *UniqueNullsNotDistinctDetector) Detect(msg protoreflect.Message) error {
if queryparser.GetMsgFullName(msg) == queryparser.PG_QUERY_INDEX_STMT_NODE {
proto := msg.Interface().(proto.Message)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you define a method in queryparser similar to ProtoAsSelectStmt that gets the struct itself.
Also, when you are doing type assertions, always prefer using x, ok := syntax to avoid panics. if !ok, return an 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.

Yep done

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Haven't created a function for the PG_QUERY_TABLECONSTRAINT_NODE code below since it doesn't seem like a regularly used pattern. Do you think otherwise?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think the goal here is to keep most of the pure parser/proto related code in queryparser pkg. So even if not very re-usable, would recommend defining a function there. We also avoid importing and directly using pg_query pkg in queryissue package that way.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done

return fmt.Errorf("failed to cast msg to %s", queryparser.PG_QUERY_TABLECONSTRAINT_NODE)
}

if constraintNode.Contype == pg_query.ConstrType_CONSTR_UNIQUE && constraintNode.NullsNotDistinct {
Copy link
Collaborator

Choose a reason for hiding this comment

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

define pg_query.ConstrType_CONSTR_UNIQUE in queryparser pkg.
Again, high level goal is to not import pg_query pkg in queryissue as much as possible; keep all the code related to parser inside queryparser pkg.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done

Comment on lines +408 to +477
indexStmt, err := queryparser.ProtoAsIndexStmt(msg)
if err != nil {
return err
}

if indexStmt.Unique && indexStmt.NullsNotDistinct {
d.detected = true
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't see a need to convert here, and add a overhead.

unique and nullsnotdistinct are directly present in the protomsg as fields.
You can directly use GetBoolField(msg, fieldName) to get that.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Hey @sanyamsinghal I am a little confused. So according to yesterday's discussion what should I do? Keep it as a struct implementation since it is inside the Detect() function?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah you can keep it as it is

Comment on lines +417 to +486
constraintNode, err := queryparser.ProtoAsTableConstraint(msg)
if err != nil {
return err
}

if constraintNode.Contype == queryparser.UNIQUE_CONSTR_TYPE && constraintNode.NullsNotDistinct {
d.detected = true
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

not sure about this. but same might apply here.

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 had earlier implemented it using the protomsg approach. I had to use a new function to convert the enum number of Contype to the name of that contype like UNIQUE_CONSTR_TYPE to make it more readable and not susceptible to any changes in the enum numbers map.
But the current approach seemed more direct and easier to read.
What do you think should be done here?

@@ -52,6 +52,9 @@ const (
PG_QUERY_JSON_IS_PREDICATE_NODE = "pg_query.JsonIsPredicate"
PG_QUERY_VIEWSTMT_NODE = "pg_query.ViewStmt"
PG_QUERY_COPYSTSMT_NODE = "pg_query.CopyStmt"

PG_QUERY_TABLECONSTRAINT_NODE = "pg_query.Constraint"
PG_QUERY_INDEX_STMT_NODE = "pg_query.IndexStmt"
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: PG_QUERY_INDEXSTMT_NODE

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done

@@ -52,6 +52,9 @@ const (
PG_QUERY_JSON_IS_PREDICATE_NODE = "pg_query.JsonIsPredicate"
PG_QUERY_VIEWSTMT_NODE = "pg_query.ViewStmt"
PG_QUERY_COPYSTSMT_NODE = "pg_query.CopyStmt"

PG_QUERY_TABLECONSTRAINT_NODE = "pg_query.Constraint"
Copy link
Collaborator

Choose a reason for hiding this comment

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

lets keep the constant name same as node name - PG_QUERY_CONSTRAINT_NODE ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah makes sense. Done.

@ShivanshGahlot ShivanshGahlot merged commit ac37160 into main Jan 9, 2025
67 checks passed
@ShivanshGahlot ShivanshGahlot deleted the shivansh/unique-nulls branch January 9, 2025 09:01
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.

3 participants