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

Implement compilation of triggers #5088

Merged
merged 5 commits into from Mar 1, 2023
Merged

Implement compilation of triggers #5088

merged 5 commits into from Mar 1, 2023

Conversation

msullivan
Copy link
Member

Closes #4936.

The interesting part of the compilation runs at the end of IR->SQL and
injects the triggers into CTEs. The overlay system is (somewhat hackily)
used to drive what objects are triggered on and (slightly less hackily) to
provide a view of the new database state.

I have one known bug at the moment, which is approximately that we apply
access policies too much in one case. I have a plan for fixing it that
doesn't change that much of the big picture, and I wanted to get something
up for review.

@@ -98,10 +98,15 @@ def inherit_fields(
inherited_fields_update = {}
deferred_complex_ops = []

for field_name in field_names:
# Iterate over mcls.get_schema_fields() instead of field_names for
Copy link
Member

Choose a reason for hiding this comment

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

Why is this important?

Copy link
Member Author

Choose a reason for hiding this comment

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

Compilation of the trigger expression depends on the values of kind and scope, and so we need to arrange to inherit those before we try to inherit expr

Copy link
Member

@elprans elprans left a comment

Choose a reason for hiding this comment

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

👍

Copy link
Contributor

@aljazerzen aljazerzen left a comment

Choose a reason for hiding this comment

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

Looks good!

I still have to re-read the pg compiler side with a fresh set of brain, but I can do that even after the merge.

@@ -1025,7 +1026,22 @@ class GroupStmt(FilteredStmt):
] = ast.field(factory=dict)


class MutatingStmt(Stmt):
# XXX: DOC
class MutatingLikeStmt(Expr):
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
class MutatingLikeStmt(Expr):
class MutatingBaseStmt(Expr):

Copy link
Member Author

Choose a reason for hiding this comment

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

Eh, I like MutatingLike more, since it's not really a MutatingBase

edb/edgeql/compiler/stmt.py Show resolved Hide resolved
kinds = set(trigger.get_kinds(schema))
source = trigger.get_subject(schema)

with ctx.detached() as _, ctx.newscope(fenced=True) as sctx:
Copy link
Contributor

Choose a reason for hiding this comment

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

How is using ctx.detached() different then wrapping the expr into a qlast.DetactedExpr? Because this is what we do for defaults (and now rewrites):

https://github.com/edgedb/edgedb/blob/master/edb/edgeql/compiler/viewgen.py#L711-L746

Copy link
Member Author

Choose a reason for hiding this comment

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

DetachedExpr will trigger a new detached context when processing. I think the main difference is I'm just doing it directly

# Process all the types, starting with the base type
for subtype in sorted(stypes, key=lambda t: t != stype):
for trigger in subtype.get_relevant_triggers(kind, schema):
mro = (trigger, *trigger.get_ancestors(schema).objects(schema))
Copy link
Contributor

Choose a reason for hiding this comment

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

Does the get_ancestors guarantee mro order? This should probably be documented somewhere.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, it does, though we don't actually care here.

Though also: #5118 😢

for stmt in dml_stmts:
kind = TRIGGER_KINDS[type(stmt)]

stype = schemactx.concretify(
Copy link
Contributor

Choose a reason for hiding this comment

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

What does this do? I cannot gather from the function documentation. What are "views" in this context?

Copy link
Member Author

Choose a reason for hiding this comment

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

"view" is what "shape" used to be called, and which it is still sometimes called internally. But more generally, all of the transient subtypes we generate during compilation.

concretify finds non-view concrete base types, but it does it recursively through unions and intersections.

Arguably this should be the normal thing? Idk.

Comment on lines 140 to 148
# N.B: If the *base type* of the DML appears, that suffices,
# because it covers everything, and we don't need to duplicate.
if (stype, stmt) not in tmap:
tmap.add((subtype, stmt))
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this could be "If any of the previously handled triggers of ancestors appears, ...

This would have effect when you have a trigger on Child1 in hierarchy Updated > Child1 > Child2.
You would first add the trigger on Child1, but when processing Child2, the trigger would be added again, even though it's effects have already been covered.

(I may not be understanding this whole chunk correctly)

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, it is a specific interaction with how the pgsql/dml.py side is implemented. I'm elaborating a bit more in the comment.

Closes #4936.

The interesting part of the compilation runs at the end of IR->SQL and
injects the triggers into CTEs. The overlay system is (somewhat
hackily) used to drive what objects are triggered on and (slightly
less hackily) to provide a view of the new database state.

I have one known bug at the moment, which is approximately that we
apply access policies *too much* in one case. I have a plan for fixing
it that doesn't change that much of the big picture, and I wanted to
get something up for review.
Track deletes also, and track all types of dml in the same way, at the
in fini_stmt.

This requires more logic where we consume the data when compiling
conflicts, but the data structure logic is more consistent.
This also lets us drop the search for DML for triggers.
@msullivan msullivan merged commit 60493f1 into master Mar 1, 2023
@msullivan msullivan deleted the triggers branch March 1, 2023 20:56
msullivan added a commit that referenced this pull request Mar 1, 2023
msullivan added a commit that referenced this pull request Mar 1, 2023
Closes #4936.

The interesting part of the compilation runs at the end of IR->SQL and
injects the triggers into CTEs. The overlay system is (somewhat
hackily) used to drive what objects are triggered on and (slightly
less hackily) to provide a view of the new database state.

I have one known bug at the moment, which is approximately that we
apply access policies *too much* in one case. I have a plan for fixing
it that doesn't change that much of the big picture, and I wanted to
get something up for review.
msullivan added a commit that referenced this pull request Mar 23, 2023
Adds a test for #5241 which was fixed slightly by #5088
while implementing triggers.

I'll cherry-pick the relevant commit and then this.
msullivan added a commit that referenced this pull request Mar 24, 2023
Adds a test for #5241 which was fixed slightly by #5088
while implementing triggers.

I'll cherry-pick the relevant commit and then this.
msullivan added a commit that referenced this pull request Mar 24, 2023
Adds a test for #5241 which was fixed slightly by #5088
while implementing triggers.

I'll cherry-pick the relevant commit and then this.
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.

Implement triggers RFC
3 participants