-
Notifications
You must be signed in to change notification settings - Fork 391
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
Catch aggregate calls in constraints and indexes in ql compiler #7343
Changes from 1 commit
5ad368d
a3bda07
10a7776
61862f5
19c3fcf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -48,6 +48,7 @@ | |
from edb.common import ordered | ||
|
||
from edb.edgeql import qltypes as ft | ||
from edb.schema import name as sn | ||
|
||
from . import ast as irast | ||
from . import typeutils | ||
|
@@ -498,6 +499,49 @@ def flt(n: irast.Call) -> bool: | |
return bool(ast.find_children(ir, irast.Call, flt, terminate_early=True)) | ||
|
||
|
||
def is_singleton_set_of_call( | ||
call: irast.Call | ||
) -> bool: | ||
# Some set functions and operators are allowed in singleton mode | ||
# as long as their inputs are singletons | ||
|
||
return call.func_shortname in { | ||
sn.QualName('std', 'IN'), | ||
sn.QualName('std', 'NOT IN'), | ||
sn.QualName('std', 'EXISTS'), | ||
sn.QualName('std', '??'), | ||
sn.QualName('std', 'IF'), | ||
} | ||
|
||
|
||
def has_set_of_param( | ||
call: irast.Call, | ||
) -> bool: | ||
return any( | ||
arg.param_typemod == ft.TypeModifier.SetOfType | ||
for arg in call.args.values() | ||
) | ||
|
||
|
||
def returns_set_of( | ||
call: irast.Call, | ||
) -> bool: | ||
return call.typemod == ft.TypeModifier.SetOfType | ||
|
||
|
||
def find_set_of_op( | ||
ir: irast.Base, | ||
has_multi_param: bool, | ||
) -> Optional[irast.Call]: | ||
def flt(n: irast.Call) -> bool: | ||
return ( | ||
(has_multi_param or not is_singleton_set_of_call(n)) | ||
and (has_set_of_param(n) or returns_set_of(n)) | ||
) | ||
calls = ast.find_children(ir, irast.Call, flt, terminate_early=True) | ||
return next(iter(calls or []), None) | ||
Comment on lines
+532
to
+533
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, you're trying to get the actual value, OK |
||
|
||
|
||
T = TypeVar('T') | ||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -433,10 +433,16 @@ def compile_OperatorCall( | |
dispatch.compile(r_expr, ctx=ctx), | ||
], | ||
) | ||
elif expr.typemod is ql_ft.TypeModifier.SetOfType: | ||
elif irutils.is_singleton_set_of_call(expr): | ||
... | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
elif irutils.returns_set_of(expr): | ||
raise errors.UnsupportedFeatureError( | ||
f'set returning operator {expr.func_shortname} is not supported ' | ||
f'in singleton expressions') | ||
f"set returning operator '{expr.func_shortname}' is not supported " | ||
f"in singleton expressions") | ||
elif irutils.has_set_of_param(expr): | ||
raise errors.UnsupportedFeatureError( | ||
f"aggregate operator '{expr.func_shortname}' is not supported " | ||
f"in singleton expressions") | ||
|
||
args, maybe_null = _compile_call_args(expr, ctx=ctx) | ||
return _wrap_call( | ||
|
@@ -683,9 +689,15 @@ def compile_FunctionCall( | |
f'unimplemented function for singleton mode: {fname}' | ||
) | ||
|
||
if expr.typemod is ql_ft.TypeModifier.SetOfType: | ||
if irutils.is_singleton_set_of_call(expr): | ||
... | ||
elif irutils.returns_set_of(expr): | ||
raise errors.UnsupportedFeatureError( | ||
'set returning functions are not supported in simple expressions') | ||
elif irutils.has_set_of_param(expr): | ||
raise errors.UnsupportedFeatureError( | ||
f"aggregate function '{expr.func_shortname}' is not supported " | ||
f"in singleton expressions") | ||
|
||
args, maybe_null = _compile_call_args(expr, ctx=ctx) | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -931,12 +931,20 @@ def _populate_concrete_constraint_attrs( | |
span=sourcectx | ||
) | ||
|
||
if has_any_multi and ir_utils.contains_set_of_op( | ||
final_subjectexpr.irast): | ||
raise errors.InvalidConstraintDefinitionError( | ||
"cannot use aggregate functions or operators " | ||
"in a non-aggregating constraint", | ||
span=sourcectx | ||
if set_of_op := ir_utils.find_set_of_op( | ||
final_subjectexpr.irast, | ||
has_any_multi, | ||
): | ||
label = ( | ||
'function' | ||
if isinstance(set_of_op, irast.FunctionCall) else | ||
'operator' | ||
) | ||
op_name = str(set_of_op.func_shortname) | ||
raise errors.UnsupportedFeatureError( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should say SET OF instead of aggregate. Also, I know I wrote the original error message, but I have no idea what "non-aggregating constraint" means, so we should stop saying it. :P |
||
f"cannot use aggregate {label} '{op_name}' " | ||
f"in a non-aggregating constraint", | ||
span=set_of_op.span | ||
) | ||
|
||
if ( | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could make this a new flag on operators that we configure in the standard library creation code. No sure if it is worth it, though?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I initially was going to do that, but it seemed like a lot of machinery. I think it's probably the "correct" thing to do in the long run.