def process_view( *, stype: s_objtypes.ObjectType, path_id: irast.PathId, elements: List[qlast.ShapeElement], view_rptr: Optional[context.ViewRPtr]=None, view_name: Optional[sn.SchemaName]=None, is_insert: bool=False, is_update: bool=False, ctx: context.ContextLevel) -> s_objtypes.ObjectType: cache_key = (stype, tuple(elements)) view_scls = ctx.shape_type_cache.get(cache_key) if view_scls is not None: return view_scls with ctx.newscope(fenced=True, temporary=True) as scopectx: scopectx.path_scope.attach_path(path_id) view_path_id_ns = None if ctx.expr_exposed or is_insert or is_update: view_path_id_ns = irast.WeakNamespace(ctx.aliases.get('ns')) scopectx.path_id_namespace |= {view_path_id_ns} scopectx.path_scope.add_namespaces({view_path_id_ns}) view_scls = _process_view( stype=stype, path_id=path_id, elements=elements, view_rptr=view_rptr, view_name=view_name, is_insert=is_insert, is_update=is_update, path_id_namespace=view_path_id_ns, ctx=scopectx ) ctx.shape_type_cache[cache_key] = view_scls return view_scls
def declare_view( expr: qlast.Base, alias: str, *, fully_detached: bool=False, temporary_scope: bool=True, ctx: context.ContextLevel) -> irast.Set: with ctx.newscope(temporary=temporary_scope, fenced=True) as subctx: if not fully_detached: cached_view_set = ctx.expr_view_cache.get((expr, alias)) # Detach the view namespace and record the prefix # in the parent statement's fence node. view_path_id_ns = irast.WeakNamespace(ctx.aliases.get('ns')) subctx.path_id_namespace |= {view_path_id_ns} ctx.path_scope.add_namespaces((view_path_id_ns,)) else: cached_view_set = None if ctx.stmt is not None: subctx.stmt = ctx.stmt.parent_stmt if cached_view_set is not None: subctx.view_scls = setgen.get_set_type(cached_view_set, ctx=ctx) view_name = subctx.view_scls.get_name(ctx.env.schema) else: if isinstance(alias, s_name.SchemaName): basename = alias else: basename = s_name.SchemaName(module='__derived__', name=alias) view_name = s_name.SchemaName( module=ctx.derived_target_module or '__derived__', name=s_name.get_specialized_name( basename, ctx.aliases.get('w') ) ) subctx.toplevel_result_view_name = view_name view_set = dispatch.compile(astutils.ensure_qlstmt(expr), ctx=subctx) if not fully_detached: # The view path id _itself_ should not be in the nested namespace. # The fully_detached case should be handled by the caller. view_set.path_id = view_set.path_id.replace_namespace( ctx.path_id_namespace) ctx.aliased_views[alias] = setgen.get_set_type(view_set, ctx=ctx) ctx.path_scope_map[view_set] = subctx.path_scope ctx.expr_view_cache[expr, alias] = view_set return view_set
def newctx() -> Iterator[context.ContextLevel]: with ctx.new() as subctx: subctx.class_view_overrides = {} subctx.partial_path_prefix = None subctx.modaliases = qlctx.modaliases.copy() subctx.aliased_views = qlctx.aliased_views.new_child() source_stype = get_set_type(source, ctx=ctx) if source_scls.is_view(ctx.env.schema): scls_name = source_stype.get_name(ctx.env.schema) subctx.aliased_views[scls_name] = None subctx.source_map = qlctx.source_map.copy() subctx.view_nodes = qlctx.view_nodes.copy() subctx.view_map = qlctx.view_map.new_child() source_scope = pathctx.get_set_scope(rptr.source, ctx=ctx) if source_scope and source_scope.namespaces: subctx.path_id_namespace |= source_scope.namespaces if path_id_ns is not None: subctx.path_id_namespace |= {path_id_ns} pending_pid_ns: Set[irast.AnyNamespace] = { irast.WeakNamespace(ctx.aliases.get('ns')), } if path_id_ns is not None and same_scope: pending_pid_ns.add(path_id_ns) subctx.pending_stmt_own_path_id_namespace = ( frozenset(pending_pid_ns)) subns = set(pending_pid_ns) self_view = ctx.view_sets.get(source_stype) if self_view: if self_view.path_id.namespace: subns.update(self_view.path_id.namespace) inner_path_id = self_view.path_id.merge_namespace( subctx.path_id_namespace | subns) else: if source.path_id.namespace: subns.update(source.path_id.namespace) if inner_source_path_id is not None: # The path id recorded in the source map may # contain namespaces referring to a temporary # scope subtree used by `process_view()`. # Since we recompile the computable expression # using the current path id namespace, the # original source path id needs to be fixed. inner_path_id = inner_source_path_id \ .strip_namespace(qlctx.path_id_namespace) \ .merge_namespace(subctx.path_id_namespace) else: inner_path_id = pathctx.get_path_id(source_stype, ctx=subctx) inner_path_id = inner_path_id.merge_namespace(subns) subctx.pending_stmt_full_path_id_namespace = frozenset(subns) remapped_source = new_set_from_set(rptr.source, rptr=rptr.source.rptr, preserve_scope_ns=True, ctx=ctx) subctx.view_map[inner_path_id] = remapped_source yield subctx
def declare_view( expr: qlast.Expr, alias: s_name.Name, *, factoring_fence: bool = False, fully_detached: bool = False, must_be_used: bool = False, path_id_namespace: Optional[FrozenSet[str]] = None, ctx: context.ContextLevel, ) -> irast.Set: pinned_pid_ns = path_id_namespace with ctx.newscope(fenced=True) as subctx: subctx.path_scope.factoring_fence = factoring_fence if path_id_namespace is not None: subctx.path_id_namespace = path_id_namespace if not fully_detached: cached_view_set = ctx.expr_view_cache.get((expr, alias)) # Detach the view namespace and record the prefix # in the parent statement's fence node. view_path_id_ns = irast.WeakNamespace(ctx.aliases.get('ns')) subctx.path_id_namespace |= {view_path_id_ns} ctx.path_scope.add_namespaces({view_path_id_ns}) else: cached_view_set = None if ctx.stmt is not None: subctx.stmt = ctx.stmt.parent_stmt if cached_view_set is not None: subctx.view_scls = setgen.get_set_type(cached_view_set, ctx=ctx) view_name = subctx.view_scls.get_name(ctx.env.schema) assert isinstance(view_name, s_name.QualName) else: if isinstance(alias, s_name.QualName): basename = alias else: basename = s_name.QualName(module='__derived__', name=alias.name) if (isinstance(alias, s_name.QualName) and subctx.env.options.schema_view_mode): view_name = basename subctx.recompiling_schema_alias = True else: view_name = s_name.QualName( module=ctx.derived_target_module or '__derived__', name=s_name.get_specialized_name(basename, ctx.aliases.get('w'))) subctx.toplevel_result_view_name = view_name view_set = dispatch.compile(astutils.ensure_qlstmt(expr), ctx=subctx) assert isinstance(view_set, irast.Set) ctx.path_scope_map[view_set] = context.ScopeInfo( path_scope=subctx.path_scope, pinned_path_id_ns=pinned_pid_ns, ) if not fully_detached: # The view path id _itself_ should not be in the nested namespace. # The fully_detached case should be handled by the caller. if path_id_namespace is None: path_id_namespace = ctx.path_id_namespace view_set.path_id = view_set.path_id.replace_namespace( path_id_namespace) view_type = setgen.get_set_type(view_set, ctx=ctx) ctx.aliased_views[alias] = view_type ctx.expr_view_cache[expr, alias] = view_set if must_be_used: ctx.must_use_views[view_type] = (alias, expr.context) return view_set