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

Use CTE instead of inheritance views when generating ranges for types #7455

Merged
merged 26 commits into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
146ac41
Create CTE when creating range for a material type.
dnwpark Jun 6, 2024
762da6d
Order type CTEs in sql statement.
dnwpark Jun 11, 2024
578f3f3
Prevent using type CTE when explaining.
dnwpark Jun 11, 2024
9c00d28
Default to use_type_inheritance_cte
msullivan Jun 19, 2024
7a925f8
Propagate type creation/deletion to functions that depend on ancestors
msullivan Jun 19, 2024
d847bb6
Separate range_for_ptrref into helper functions.
dnwpark Jul 2, 2024
b2e0772
Ignore expand inhview flag and always expand.
dnwpark Jul 2, 2024
52bf2d6
Ensure column name is aliased correctly.
dnwpark Jul 2, 2024
7cab3c4
Add PathId from ptrref.
dnwpark Jul 3, 2024
809fce0
Create rvar for each ptrref component separately.
dnwpark Jul 4, 2024
fad929f
Add ptr_inheritance_ctes to pgsql compiler context.
dnwpark Jul 4, 2024
fab272e
Create CTE for pointer references.
dnwpark Jul 4, 2024
479088e
Fix link properties on back links not finding output.
dnwpark Jul 5, 2024
cfa05fe
Rename type inheritance variables to be more general.
dnwpark Jul 5, 2024
f394397
Reorder some functions.
dnwpark Jul 5, 2024
4dccd62
Replace expand_inhview flag with is_explain and update comments.
dnwpark Jul 8, 2024
46e8083
Fix spelling.
dnwpark Jul 9, 2024
b0ffb07
Refactor range_for_material_objtype to remove recursion and extra bra…
dnwpark Jul 9, 2024
add6e7f
Remove ptr_cte field and keep pointer ctes separate from type ctes.
dnwpark Jul 10, 2024
0d2f2b9
Move assert forward in range for typeref process.
dnwpark Jul 10, 2024
7c8352d
Fix CTEs in pointer conversion expressions.
dnwpark Jul 11, 2024
e3d7541
Remove special case for cfg and sys.
dnwpark Jul 11, 2024
6f38582
Remove special case for schema.
dnwpark Jul 11, 2024
1b4643b
Remove use_inheritance_ctes flag.
dnwpark Jul 11, 2024
bafd35b
Remove cfg view children from non-cfg view typerefs.
dnwpark Jul 11, 2024
08f6fdd
Fix CTEs not being added to non-set expr statements after compile.
dnwpark Jul 11, 2024
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
3 changes: 0 additions & 3 deletions edb/common/debug.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,6 @@ class flags(metaclass=FlagsMeta):
edgeql_disable_normalization = Flag(
doc="Disable EdgeQL normalization (constant extraction etc)")

edgeql_expand_inhviews = Flag(
doc="Force the EdgeQL compiler to expand inhviews *always*")

graphql_compile = Flag(
doc="Debug GraphQL compiler.")

Expand Down
6 changes: 3 additions & 3 deletions edb/edgeql/compiler/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,10 @@ class GlobalCompilerOptions:
#: definitions.
func_params: Optional[s_func.ParameterLikeList] = None

#: Should the backend compiler expand out inheritance views instead of
#: using them. This is needed by EXPLAIN to maintain alias names in
#: Should the backend compiler expand inheritance CTEs in place.
#: This is needed by EXPLAIN to maintain alias names in
#: the query plan.
expand_inhviews: bool = False
is_explain: bool = False

#: The name that can be used in a "DML is disallowed in ..."
#: error. When this is not None, any DML should cause an error.
Expand Down
5 changes: 1 addition & 4 deletions edb/edgeql/compiler/typegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,10 +401,7 @@ def type_to_typeref(
include_children = (
expr_type is s_types.ExprType.Update
or expr_type is s_types.ExprType.Delete
or (
env.options.expand_inhviews
and isinstance(t, s_objtypes.ObjectType)
)
or isinstance(t, s_objtypes.ObjectType)
Copy link
Member

Choose a reason for hiding this comment

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

We can collapse out the expr_type conditions--those can only hold if the type is an object anyway.

)
include_ancestors = (
expr_type is s_types.ExprType.Insert
Expand Down
2 changes: 2 additions & 0 deletions edb/ir/ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ class TypeRef(ImmutableBase):
is_scalar: bool = False
# True, if this describes a view
is_view: bool = False
# True, if this describes a cfg view
is_cfg_view: bool = False
# True, if this describes an abstract type
is_abstract: bool = False
# True, if the collection type is persisted in the schema
Expand Down
24 changes: 22 additions & 2 deletions edb/ir/pathid.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,8 +257,6 @@ def from_typeref(
which case it is used instead.

Args:
schema:
A schema instance where the type *t* is defined.
typeref:
The descriptor of a type of the variable being defined.
namespace:
Expand All @@ -278,6 +276,28 @@ def from_typeref(
pid._namespace = frozenset(namespace)
return pid

@classmethod
def from_ptrref(
cls,
ptrref: irast.PointerRef,
*,
namespace: AbstractSet[Namespace] = frozenset(),
) -> PathId:
"""Return a ``PathId`` instance for a given :class:`ir.ast.PointerRef`

Args:
ptrref:
The descriptor of a ptr of the variable being defined.
namespace:
Optional namespace in which the variable is defined.

Returns:
A ``PathId`` instance of type described by *ptrref*.
"""
pid = cls.from_typeref(ptrref.out_source, namespace=namespace)
pid = pid.extend(ptrref=ptrref)
return pid

@classmethod
def new_dummy(cls, name: str) -> PathId:
name_hint = s_name.QualName(module='__derived__', name=name)
Expand Down
31 changes: 31 additions & 0 deletions edb/ir/typeutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,36 @@
TypeRefCache = dict[TypeRefCacheKey, 'irast.TypeRef']


# Modules where all the "types" in them are really just custom views
# provided by metaschema.
VIEW_MODULES = ('sys', 'cfg')


def is_cfg_view(
obj: s_obj.Object,
schema: s_schema.Schema,
) -> bool:
return (
isinstance(obj, (s_objtypes.ObjectType, s_pointers.Pointer))
and (
obj.get_name(schema).module in VIEW_MODULES
or bool(
(cfg_object := schema.get(
'cfg::ConfigObject',
type=s_objtypes.ObjectType, default=None
))
and (
nobj := (
obj if isinstance(obj, s_objtypes.ObjectType)
else obj.get_source(schema)
)
)
and nobj.issubclass(schema, cfg_object)
)
)
)


def is_scalar(typeref: irast.TypeRef) -> bool:
"""Return True if *typeref* describes a scalar type."""
return typeref.is_scalar
Expand Down Expand Up @@ -400,6 +430,7 @@ def _typeref(
is_scalar=t.is_scalar(),
is_abstract=t.get_abstract(schema),
is_view=t.is_view(schema),
is_cfg_view=is_cfg_view(t, schema),
is_opaque_union=t.get_is_opaque_union(schema),
needs_custom_json_cast=needs_custom_json_cast,
sql_type=sql_type,
Expand Down
16 changes: 11 additions & 5 deletions edb/pgsql/compiler/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def compile_ir_to_sql_tree(
singleton_mode: bool = False,
named_param_prefix: Optional[tuple[str, ...]] = None,
expected_cardinality_one: bool = False,
expand_inhviews: bool = False,
is_explain: bool = False,
external_rvars: Optional[
Mapping[Tuple[irast.PathId, pgce.PathAspect], pgast.PathRangeVar]
] = None,
Expand Down Expand Up @@ -127,7 +127,7 @@ def compile_ir_to_sql_tree(
type_rewrites=type_rewrites,
ignore_object_shapes=ignore_shapes,
explicit_top_cast=explicit_top_cast,
expand_inhviews=expand_inhviews,
is_explain=is_explain,
singleton_mode=singleton_mode,
scope_tree_nodes=scope_tree_nodes,
external_rvars=external_rvars,
Expand Down Expand Up @@ -156,9 +156,15 @@ def compile_ir_to_sql_tree(
qtree = dispatch.compile(ir_expr, ctx=ctx)
dml.compile_triggers(triggers, qtree, ctx=ctx)

if isinstance(ir_expr, irast.Set) and not singleton_mode:
assert isinstance(qtree, pgast.Query)
clauses.fini_toplevel(qtree, ctx)
if not singleton_mode:
if isinstance(ir_expr, irast.Set):
assert isinstance(qtree, pgast.Query)
clauses.fini_toplevel(qtree, ctx)

elif isinstance(qtree, pgast.Query):
# Other types of expressions may compile to queries which may
# use inheritance CTEs. Ensure they are added here.
clauses.insert_ctes(qtree, ctx)

if detach_params:
detached_params_idx = {
Expand Down
22 changes: 14 additions & 8 deletions edb/pgsql/compiler/clauses.py
Original file line number Diff line number Diff line change
Expand Up @@ -409,20 +409,26 @@ def scan_check_ctes(
))


def fini_toplevel(
stmt: pgast.Query, ctx: context.CompilerContextLevel) -> None:

scan_check_ctes(stmt, ctx.env.check_ctes, ctx=ctx)

# Type rewrites go first.
def insert_ctes(
stmt: pgast.Query, ctx: context.CompilerContextLevel
) -> None:
if stmt.ctes is None:
stmt.ctes = []
stmt.ctes[:0] = [
*ctx.param_ctes.values(),
*ctx.ptr_ctes.values(),
*ctx.type_ctes.values(),
*ctx.ptr_inheritance_ctes.values(),
*ctx.ordered_type_ctes,
]


def fini_toplevel(
stmt: pgast.Query, ctx: context.CompilerContextLevel) -> None:

scan_check_ctes(stmt, ctx.env.check_ctes, ctx=ctx)

# Type rewrites and inheritance CTEs go first.
insert_ctes(stmt, ctx)

if ctx.env.named_param_prefix is None:
# Adding unused parameters into a CTE

Expand Down
40 changes: 26 additions & 14 deletions edb/pgsql/compiler/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,15 +242,21 @@ class CompilerContextLevel(compiler.ContextLevel):
#: CTEs representing decoded parameters
param_ctes: Dict[str, pgast.CommonTableExpr]

#: CTEs representing pointer tables that we need to force to be
#: materialized for performance reasons.
ptr_ctes: Dict[uuid.UUID, pgast.CommonTableExpr]
#: CTEs representing pointers and their inherited pointers
ptr_inheritance_ctes: Dict[uuid.UUID, pgast.CommonTableExpr]

#: CTEs representing types, when rewritten based on access policy
type_ctes: Dict[FullRewriteKey, pgast.CommonTableExpr]
type_rewrite_ctes: Dict[FullRewriteKey, pgast.CommonTableExpr]

#: A set of type CTEs currently being generated
pending_type_ctes: Set[RewriteKey]
pending_type_rewrite_ctes: Set[RewriteKey]

#: CTEs representing types and their inherited types
type_inheritance_ctes: Dict[uuid.UUID, pgast.CommonTableExpr]

# Type and type inheriance CTEs in creation order. This ensures type CTEs
# referring to other CTEs are in the correct order.
ordered_type_ctes: list[pgast.CommonTableExpr]

#: The logical parent of the current query in the
#: query hierarchy
Expand Down Expand Up @@ -351,9 +357,11 @@ def __init__(
self.rel = NO_STMT
self.rel_hierarchy = {}
self.param_ctes = {}
self.ptr_ctes = {}
self.type_ctes = {}
self.pending_type_ctes = set()
self.ptr_inheritance_ctes = {}
self.type_rewrite_ctes = {}
self.pending_type_rewrite_ctes = set()
self.type_inheritance_ctes = {}
self.ordered_type_ctes = []
self.dml_stmts = {}
self.parent_rel = None
self.pending_query = None
Expand Down Expand Up @@ -391,9 +399,11 @@ def __init__(
self.rel = prevlevel.rel
self.rel_hierarchy = prevlevel.rel_hierarchy
self.param_ctes = prevlevel.param_ctes
self.ptr_ctes = prevlevel.ptr_ctes
self.type_ctes = prevlevel.type_ctes
self.pending_type_ctes = prevlevel.pending_type_ctes
self.ptr_inheritance_ctes = prevlevel.ptr_inheritance_ctes
self.type_rewrite_ctes = prevlevel.type_rewrite_ctes
self.pending_type_rewrite_ctes = prevlevel.pending_type_rewrite_ctes
self.type_inheritance_ctes = prevlevel.type_inheritance_ctes
self.ordered_type_ctes = prevlevel.ordered_type_ctes
self.dml_stmts = prevlevel.dml_stmts
self.parent_rel = prevlevel.parent_rel
self.pending_query = prevlevel.pending_query
Expand Down Expand Up @@ -456,7 +466,9 @@ def __init__(
self.disable_semi_join = frozenset()
self.force_optional = frozenset()
self.intersection_narrowing = {}
self.pending_type_ctes = set(prevlevel.pending_type_ctes)
self.pending_type_rewrite_ctes = set(
prevlevel.pending_type_rewrite_ctes
)

elif mode == ContextSwitchMode.NEWSCOPE:
self.path_scope = prevlevel.path_scope.new_child()
Expand Down Expand Up @@ -536,7 +548,7 @@ def __init__(
expected_cardinality_one: bool,
ignore_object_shapes: bool,
singleton_mode: bool,
expand_inhviews: bool,
is_explain: bool,
explicit_top_cast: Optional[irast.TypeRef],
query_params: List[irast.Param],
type_rewrites: Dict[RewriteKey, irast.Set],
Expand All @@ -555,7 +567,7 @@ def __init__(
self.expected_cardinality_one = expected_cardinality_one
self.ignore_object_shapes = ignore_object_shapes
self.singleton_mode = singleton_mode
self.expand_inhviews = expand_inhviews
self.is_explain = is_explain
self.explicit_top_cast = explicit_top_cast
self.query_params = query_params
self.type_rewrites = type_rewrites
Expand Down
6 changes: 4 additions & 2 deletions edb/pgsql/compiler/dml.py
Original file line number Diff line number Diff line change
Expand Up @@ -3139,7 +3139,9 @@ def compile_triggers(
# FIXME: I think we actually need to keep the old type_ctes
# available for pointers off of __old__ to use.
ictx.trigger_mode = True
ictx.type_ctes = {}
ictx.type_rewrite_ctes = {}
ictx.type_inheritance_ctes = {}
ictx.ordered_type_ctes = []
ictx.toplevel_stmt = stmt

for stage in triggers:
Expand All @@ -3156,7 +3158,7 @@ def compile_triggers(

# Install any newly created type CTEs before the CTEs created from
# this trigger compilation but after anything compiled before.
stmt.ctes[start_ctes:start_ctes] = list(ictx.type_ctes.values())
stmt.ctes[start_ctes:start_ctes] = ictx.ordered_type_ctes


def compile_trigger(
Expand Down
Loading
Loading