示例#1
0
文件: config.py 项目: yew1eb/edgedb
def _rewrite_config_insert(ir_set: irast.Set, *,
                           ctx: context.CompilerContextLevel) -> irast.Set:

    relctx.add_type_rel_overlay(
        ir_set.typeref,
        'replace',
        pgast.NullRelation(path_id=ir_set.path_id),
        path_id=ir_set.path_id,
        ctx=ctx,
    )

    # Config objects have derived computed ids,
    # so the autogenerated id must not be returned.
    ir_set.shape = list(
        filter(
            lambda el: el[0].rptr.ptrref.shortname.name != 'id',
            ir_set.shape,
        ))

    for el, _ in ir_set.shape:
        if isinstance(el.expr, irast.InsertStmt):
            el.shape = list(
                filter(
                    lambda e: e[0].rptr.ptrref.shortname.name != 'id',
                    el.shape,
                ))

            result = _rewrite_config_insert(el.expr.subject, ctx=ctx)
            el.expr = irast.SelectStmt(
                result=result,
                parent_stmt=el.expr.parent_stmt,
            )

    return ir_set
示例#2
0
def ensure_stmt(expr: irast.Base, *, ctx: context.ContextLevel) -> irast.Stmt:
    if not isinstance(expr, irast.Stmt):
        expr = irast.SelectStmt(
            result=ensure_set(expr, ctx=ctx),
            implicit_wrapper=True,
        )
    return expr
示例#3
0
def _rewrite_config_insert(ir_set: irast.Set, *,
                           ctx: context.CompilerContextLevel) -> irast.Set:

    overwrite_query = pgast.SelectStmt()
    id_expr = pgast.FuncCall(
        name=(
            'edgedbext',
            'uuid_generate_v1mc',
        ),
        args=[],
    )
    pathctx.put_path_identity_var(overwrite_query,
                                  ir_set.path_id,
                                  id_expr,
                                  force=True,
                                  env=ctx.env)
    pathctx.put_path_value_var(overwrite_query,
                               ir_set.path_id,
                               id_expr,
                               force=True,
                               env=ctx.env)
    pathctx.put_path_source_rvar(overwrite_query,
                                 ir_set.path_id,
                                 relctx.rvar_for_rel(pgast.NullRelation(),
                                                     ctx=ctx),
                                 env=ctx.env)

    relctx.add_type_rel_overlay(
        ir_set.typeref,
        'replace',
        overwrite_query,
        path_id=ir_set.path_id,
        ctx=ctx,
    )

    # Config objects have derived computed ids,
    # so the autogenerated id must not be returned.
    ir_set.shape = tuple(
        filter(
            lambda el: ((rptr := el[0].rptr) is not None and rptr.ptrref.
                        shortname.name != 'id'),
            ir_set.shape,
        ))

    for el, _ in ir_set.shape:
        if isinstance(el.expr, irast.InsertStmt):
            el.shape = tuple(
                filter(
                    lambda e: ((rptr := e[0].rptr) is not None and rptr.ptrref.
                               shortname.name != 'id'),
                    el.shape,
                ))

            result = _rewrite_config_insert(el.expr.subject, ctx=ctx)
            el.expr = irast.SelectStmt(
                result=result,
                parent_stmt=el.expr.parent_stmt,
            )

    return ir_set
示例#4
0
def compile_GroupQuery(
        expr: qlast.Base, *, ctx: context.ContextLevel) -> irast.Set:

    raise errors.UnsupportedFeatureError(
        "'GROUP' statement is not currently implemented",
        context=expr.context)

    with ctx.subquery() as ictx:
        stmt = irast.GroupStmt()
        init_stmt(stmt, expr, ctx=ictx, parent_ctx=ctx)

        typename = s_name.Name(
            module='__group__', name=ctx.aliases.get('Group'))
        obj = ctx.env.get_track_schema_object('std::BaseObject')
        stmt.group_path_id = pathctx.get_path_id(
            obj, typename=typename, ctx=ictx)

        pathctx.register_set_in_scope(stmt.group_path_id, ctx=ictx)

        with ictx.newscope(fenced=True) as subjctx:
            subject_set = setgen.scoped_set(
                dispatch.compile(expr.subject, ctx=subjctx), ctx=subjctx)

            alias = expr.subject_alias or subject_set.path_id.target_name_hint
            stmt.subject = stmtctx.declare_inline_view(
                subject_set, alias, ctx=ictx)

            with subjctx.new() as grpctx:
                stmt.groupby = compile_groupby_clause(
                    expr.groupby, ctx=grpctx)

        with ictx.subquery() as isctx, isctx.newscope(fenced=True) as sctx:
            o_stmt = sctx.stmt = irast.SelectStmt()

            o_stmt.result = compile_result_clause(
                expr.result,
                view_scls=ctx.view_scls,
                view_rptr=ctx.view_rptr,
                result_alias=expr.result_alias,
                view_name=ctx.toplevel_result_view_name,
                ctx=sctx)

            clauses.compile_where_clause(
                o_stmt, expr.where, ctx=sctx)

            o_stmt.orderby = clauses.compile_orderby_clause(
                expr.orderby, ctx=sctx)

            o_stmt.offset = clauses.compile_limit_offset_clause(
                expr.offset, ctx=sctx)

            o_stmt.limit = clauses.compile_limit_offset_clause(
                expr.limit, ctx=sctx)

            stmt.result = setgen.scoped_set(o_stmt, ctx=sctx)

        result = fini_stmt(stmt, expr, ctx=ictx, parent_ctx=ctx)

    return result
示例#5
0
def compile_ForQuery(
        qlstmt: qlast.ForQuery, *, ctx: context.ContextLevel) -> irast.Base:
    with ctx.subquery() as sctx:
        stmt = irast.SelectStmt()
        init_stmt(stmt, qlstmt, ctx=sctx, parent_ctx=ctx)

        if qlstmt.offset is not None or qlstmt.limit is not None:
            # LIMIT and OFFSET are infix operators with both
            # operands being SET OF, so we need to compile
            # the body of the statement behind a fence.
            sctx.path_scope = sctx.path_scope.attach_fence()

        with sctx.newscope(fenced=True) as scopectx:
            iterator = qlstmt.iterator
            if isinstance(iterator, qlast.Set) and len(iterator.elements) == 1:
                iterator = iterator.elements[0]

            iterator_view = stmtctx.declare_view(
                iterator, qlstmt.iterator_alias, ctx=scopectx)

            stmt.iterator_stmt = setgen.new_set_from_set(
                iterator_view, ctx=scopectx)

            iterator_scope = scopectx.path_scope_map.get(iterator_view)

        pathctx.register_set_in_scope(stmt.iterator_stmt, ctx=sctx)
        node = sctx.path_scope.find_descendant(stmt.iterator_stmt.path_id)
        node.attach_subtree(iterator_scope)

        stmt.result = compile_result_clause(
            qlstmt.result,
            view_scls=ctx.view_scls,
            view_rptr=ctx.view_rptr,
            result_alias=qlstmt.result_alias,
            view_name=ctx.toplevel_result_view_name,
            forward_rptr=True,
            ctx=sctx)

        clauses.compile_where_clause(
            stmt, qlstmt.where, ctx=sctx)

        stmt.orderby = clauses.compile_orderby_clause(
            qlstmt.orderby, ctx=sctx)

        if qlstmt.offset is not None or qlstmt.limit is not None:
            sctx.path_scope = sctx.path_scope.parent

            stmt.offset = clauses.compile_limit_offset_clause(
                qlstmt.offset, ctx=sctx)

            stmt.limit = clauses.compile_limit_offset_clause(
                qlstmt.limit, ctx=sctx)

        result = fini_stmt(stmt, qlstmt, ctx=sctx, parent_ctx=ctx)

    return result
示例#6
0
def compile_SelectQuery(
        expr: qlast.SelectQuery, *, ctx: context.ContextLevel) -> irast.Set:
    if astutils.is_degenerate_select(expr) and ctx.toplevel_stmt is not None:
        # Compile implicit "SELECT Path" as "Path"
        with ctx.new() as sctx:
            process_with_block(expr, ctx=sctx, parent_ctx=ctx)
            sctx.aliased_views = ctx.aliased_views.new_child()
            sctx.modaliases = ctx.modaliases.copy()
            sctx.anchors = ctx.anchors.copy()
            result = compile_result_clause(
                expr.result,
                view_scls=ctx.view_scls,
                view_rptr=ctx.view_rptr,
                view_name=ctx.toplevel_result_view_name,
                ctx=sctx)
            result = fini_stmt(result, expr, ctx=sctx, parent_ctx=ctx)

        return result

    with ctx.subquery() as sctx:
        stmt = irast.SelectStmt()
        init_stmt(stmt, expr, ctx=sctx, parent_ctx=ctx)
        if expr.implicit:
            # Make sure path prefix does not get blown away by
            # implicit subqueries.
            sctx.partial_path_prefix = ctx.partial_path_prefix

        stmt.result = compile_result_clause(
            expr.result,
            view_scls=ctx.view_scls,
            view_rptr=ctx.view_rptr,
            result_alias=expr.result_alias,
            view_name=ctx.toplevel_result_view_name,
            ctx=sctx)

        clauses.compile_where_clause(
            stmt, expr.where, ctx=sctx)

        stmt.orderby = clauses.compile_orderby_clause(
            expr.orderby, ctx=sctx)

        stmt.offset = clauses.compile_limit_offset_clause(
            expr.offset, ctx=sctx)

        stmt.limit = clauses.compile_limit_offset_clause(
            expr.limit, ctx=sctx)

        result = fini_stmt(stmt, expr, ctx=sctx, parent_ctx=ctx)

    return result
示例#7
0
文件: stmt.py 项目: signupsi/edgedb
def compile_SelectQuery(
        expr: qlast.SelectQuery, *, ctx: context.ContextLevel) -> irast.Set:
    with ctx.subquery() as sctx:
        stmt = irast.SelectStmt()
        init_stmt(stmt, expr, ctx=sctx, parent_ctx=ctx)
        if expr.implicit:
            # Make sure path prefix does not get blown away by
            # implicit subqueries.
            sctx.partial_path_prefix = ctx.partial_path_prefix
            stmt.implicit_wrapper = True

        if (
            (ctx.expr_exposed or sctx.stmt is ctx.toplevel_stmt)
            and ctx.implicit_limit
            and expr.limit is None
            and not ctx.inhibit_implicit_limit
        ):
            expr.limit = qlast.IntegerConstant(value=str(ctx.implicit_limit))

        stmt.result = compile_result_clause(
            expr.result,
            view_scls=ctx.view_scls,
            view_rptr=ctx.view_rptr,
            result_alias=expr.result_alias,
            view_name=ctx.toplevel_result_view_name,
            ctx=sctx)

        clauses.compile_where_clause(
            stmt, expr.where, ctx=sctx)

        stmt.orderby = clauses.compile_orderby_clause(
            expr.orderby, ctx=sctx)

        stmt.offset = clauses.compile_limit_offset_clause(
            expr.offset, ctx=sctx)

        stmt.limit = clauses.compile_limit_offset_clause(
            expr.limit, ctx=sctx)

        result = fini_stmt(stmt, expr, ctx=sctx, parent_ctx=ctx)

    return result
示例#8
0
def compile_SelectQuery(
        expr: qlast.SelectQuery, *, ctx: context.ContextLevel) -> irast.Base:
    if astutils.is_degenerate_select(expr) and ctx.toplevel_stmt is not None:
        # Compile implicit "SELECT Path" as "Path"
        with ctx.new() as sctx:
            process_with_block(expr, ctx=sctx, parent_ctx=ctx)
            sctx.aliased_views = ctx.aliased_views.new_child()
            sctx.modaliases = ctx.modaliases.copy()
            sctx.anchors = ctx.anchors.copy()
            result = compile_result_clause(
                expr.result,
                view_scls=ctx.view_scls,
                view_rptr=ctx.view_rptr,
                view_name=ctx.toplevel_result_view_name,
                ctx=sctx)
            result = fini_stmt(result, expr, ctx=sctx, parent_ctx=ctx)

        return result

    with ctx.subquery() as sctx:
        stmt = irast.SelectStmt()
        init_stmt(stmt, expr, ctx=sctx, parent_ctx=ctx)
        if expr.implicit:
            # Make sure path prefix does not get blown away by
            # implicit subqueries.
            sctx.partial_path_prefix = ctx.partial_path_prefix

        compile_limit_offset = False

        if expr.offset is not None or expr.limit is not None:
            # LIMIT and OFFSET are infix operators with both
            # operands being SET OF, so we need to compile
            # the body of the statement behind a fence.
            metadata = ctx.stmt_metadata.get(expr)
            if metadata is None:
                metadata = context.StatementMetadata()
                ctx.stmt_metadata[expr] = metadata

            if not metadata.ignore_offset_limit:
                metadata.ignore_offset_limit = True
                compile_limit_offset = True

        if compile_limit_offset:
            sctx.toplevel_result_view_name = ctx.toplevel_result_view_name

            stmt.result = compile_result_clause(
                expr,
                view_scls=ctx.view_scls,
                view_rptr=ctx.view_rptr,
                ctx=sctx)

            if ctx.toplevel_result_view_name:
                result_stype = setgen.get_set_type(stmt.result, ctx=ctx)
                stmt.result.path_id = pathctx.get_expression_path_id(
                    result_stype, ctx=ctx)

            stmt.offset = clauses.compile_limit_offset_clause(
                expr.offset, ctx=sctx)

            stmt.limit = clauses.compile_limit_offset_clause(
                expr.limit, ctx=sctx)

            metadata.ignore_offset_limit = False
        else:
            stmt.result = compile_result_clause(
                expr.result,
                view_scls=ctx.view_scls,
                view_rptr=ctx.view_rptr,
                result_alias=expr.result_alias,
                view_name=ctx.toplevel_result_view_name,
                ctx=sctx)

            clauses.compile_where_clause(
                stmt, expr.where, ctx=sctx)

            stmt.orderby = clauses.compile_orderby_clause(
                expr.orderby, ctx=sctx)

        result = fini_stmt(stmt, expr, ctx=sctx, parent_ctx=ctx)

    return result
示例#9
0
def compile_DescribeStmt(
        ql: qlast.DescribeStmt, *, ctx: context.ContextLevel) -> irast.Set:
    with ctx.subquery() as ictx:
        stmt = irast.SelectStmt()
        init_stmt(stmt, ql, ctx=ictx, parent_ctx=ctx)

        if not ql.object:
            if ql.language is qltypes.DescribeLanguage.DDL:
                # DESCRIBE SCHEMA
                text = s_ddl.ddl_text_from_schema(
                    ctx.env.schema,
                )
            else:
                raise errors.QueryError(
                    f'cannot describe full schema as {ql.language}')
        else:
            modules = []
            items: List[str] = []
            referenced_classes: List[s_obj.ObjectMeta] = []

            objref = ql.object
            itemclass = objref.itemclass

            if itemclass is qltypes.SchemaObjectClass.MODULE:
                modules.append(objref.name)
            else:
                itemtype: Optional[Type[s_obj.Object]] = None
                found = False

                name: str
                if objref.module:
                    name = s_name.Name(module=objref.module, name=objref.name)
                else:
                    name = objref.name

                if itemclass is not None:
                    itemtype = (
                        s_obj.ObjectMeta.get_schema_metaclass_for_ql_class(
                            itemclass)
                    )

                if (itemclass is None or
                        itemclass is qltypes.SchemaObjectClass.FUNCTION):

                    try:
                        funcs: Tuple[s_func.Function, ...] = (
                            ictx.env.schema.get_functions(
                                name,
                                module_aliases=ictx.modaliases)
                        )
                    except errors.InvalidReferenceError:
                        pass
                    else:
                        for func in funcs:
                            items.append(func.get_name(ictx.env.schema))
                        found = True

                if not found:
                    obj = schemactx.get_schema_object(
                        objref,
                        item_type=itemtype,
                        ctx=ictx,
                    )

                    items.append(obj.get_name(ictx.env.schema))

            verbose = ql.options.get_flag('VERBOSE')

            if ql.language is qltypes.DescribeLanguage.DDL:
                method = s_ddl.ddl_text_from_schema
            elif ql.language is qltypes.DescribeLanguage.SDL:
                method = s_ddl.sdl_text_from_schema
            elif ql.language is qltypes.DescribeLanguage.TEXT:
                method = s_ddl.descriptive_text_from_schema
                if not verbose.val:
                    referenced_classes = [s_links.Link, s_lprops.Property]
            else:
                raise errors.InternalServerError(
                    f'cannot handle describe language {ql.language}'
                )

            text = method(
                ctx.env.schema,
                included_modules=modules,
                included_items=items,
                included_ref_classes=referenced_classes,
                include_module_ddl=False,
                include_std_ddl=True,
            )

        ct = typegen.type_to_typeref(
            ctx.env.get_track_schema_type('std::str'),
            env=ctx.env,
        )

        stmt.result = setgen.ensure_set(
            irast.StringConstant(value=text, typeref=ct),
            ctx=ictx,
        )

        result = fini_stmt(stmt, ql, ctx=ictx, parent_ctx=ctx)

    return result
示例#10
0
def compile_ForQuery(
        qlstmt: qlast.ForQuery, *, ctx: context.ContextLevel) -> irast.Set:
    with ctx.subquery() as sctx:
        stmt = irast.SelectStmt()
        init_stmt(stmt, qlstmt, ctx=sctx, parent_ctx=ctx)

        with sctx.newscope(fenced=True) as scopectx:
            iterator_ctx = None
            if (ctx.expr_exposed and ctx.iterator_ctx is not None
                    and ctx.iterator_ctx is not sctx):
                iterator_ctx = ctx.iterator_ctx

            if iterator_ctx is not None:
                iterator_scope_parent = iterator_ctx.path_scope
                path_id_ns = iterator_ctx.path_id_namespace
            else:
                iterator_scope_parent = sctx.path_scope
                path_id_ns = sctx.path_id_namespace

            iterator = qlstmt.iterator
            if isinstance(iterator, qlast.Set) and len(iterator.elements) == 1:
                iterator = iterator.elements[0]

            iterator_view = stmtctx.declare_view(
                iterator, qlstmt.iterator_alias,
                path_id_namespace=path_id_ns, ctx=scopectx)

            iterator_stmt = setgen.new_set_from_set(
                iterator_view, preserve_scope_ns=True, ctx=scopectx)

            if iterator_ctx is not None and iterator_ctx.stmt is not None:
                iterator_ctx.stmt.hoisted_iterators.append(iterator_stmt)

            stmt.iterator_stmt = iterator_stmt

            view_scope_info = scopectx.path_scope_map[iterator_view]
            iterator_scope = view_scope_info.path_scope

        pathctx.register_set_in_scope(
            iterator_stmt,
            path_scope=iterator_scope_parent,
            ctx=sctx,
        )
        # Iterator symbol is, by construction, outside of the scope
        # of the UNION argument, but is perfectly legal to be referenced
        # inside a factoring fence that is an immediate child of this
        # scope.
        iterator_scope_parent.factoring_whitelist.add(
            stmt.iterator_stmt.path_id)
        node = iterator_scope_parent.find_descendant(iterator_stmt.path_id)
        if node is not None:
            node.attach_subtree(iterator_scope)

        stmt.result = compile_result_clause(
            qlstmt.result,
            view_scls=ctx.view_scls,
            view_rptr=ctx.view_rptr,
            result_alias=qlstmt.result_alias,
            view_name=ctx.toplevel_result_view_name,
            forward_rptr=True,
            ctx=sctx)

        if ((ctx.expr_exposed or sctx.stmt is ctx.toplevel_stmt)
                and ctx.implicit_limit):
            stmt.limit = setgen.ensure_set(
                dispatch.compile(
                    qlast.IntegerConstant(value=str(ctx.implicit_limit)),
                    ctx=sctx,
                ),
                ctx=sctx,
            )

        result = fini_stmt(stmt, qlstmt, ctx=sctx, parent_ctx=ctx)

    return result
示例#11
0
def compile_DescribeStmt(ql: qlast.DescribeStmt, *,
                         ctx: context.ContextLevel) -> irast.Set:
    with ctx.subquery() as ictx:
        stmt = irast.SelectStmt()
        init_stmt(stmt, ql, ctx=ictx, parent_ctx=ctx)

        if ql.object == qlast.DescribeGlobal.Schema:
            if ql.language is qltypes.DescribeLanguage.DDL:
                # DESCRIBE SCHEMA
                text = s_ddl.ddl_text_from_schema(ctx.env.schema, )
            else:
                raise errors.QueryError(
                    f'cannot describe full schema as {ql.language}')

            ct = typegen.type_to_typeref(
                ctx.env.get_track_schema_type('std::str'),
                env=ctx.env,
            )

            stmt.result = setgen.ensure_set(
                irast.StringConstant(value=text, typeref=ct),
                ctx=ictx,
            )

        elif ql.object == qlast.DescribeGlobal.SystemConfig:
            if ql.language is qltypes.DescribeLanguage.DDL:
                function_call = dispatch.compile(qlast.FunctionCall(
                    func=('cfg', '_describe_system_config_as_ddl'), ),
                                                 ctx=ictx)
                assert isinstance(function_call, irast.Set), function_call
                stmt.result = function_call
            else:
                raise errors.QueryError(
                    f'cannot describe config as {ql.language}')
        elif ql.object == qlast.DescribeGlobal.Roles:
            if ql.language is qltypes.DescribeLanguage.DDL:
                function_call = dispatch.compile(qlast.FunctionCall(
                    func=('sys', '_describe_roles_as_ddl'), ),
                                                 ctx=ictx)
                assert isinstance(function_call, irast.Set), function_call
                stmt.result = function_call
            else:
                raise errors.QueryError(
                    f'cannot describe roles as {ql.language}')
        else:
            assert isinstance(ql.object, qlast.ObjectRef), ql.object
            modules = []
            items: DefaultDict[str, List[str]] = defaultdict(list)
            referenced_classes: List[s_obj.ObjectMeta] = []

            objref = ql.object
            itemclass = objref.itemclass

            if itemclass is qltypes.SchemaObjectClass.MODULE:
                modules.append(objref.name)
            else:
                itemtype: Optional[Type[s_obj.Object]] = None

                name: str
                if objref.module:
                    name = s_name.Name(module=objref.module, name=objref.name)
                else:
                    name = objref.name

                if itemclass is not None:
                    if itemclass is qltypes.SchemaObjectClass.ALIAS:
                        # Look for underlying derived type.
                        itemtype = s_types.Type
                    else:
                        itemtype = (
                            s_obj.ObjectMeta.get_schema_metaclass_for_ql_class(
                                itemclass))

                last_exc = None
                # Search in the current namespace AND in std. We do
                # this to avoid masking a `std` object/function by one
                # in a default module.
                search_ns = [ictx.modaliases]
                # Only check 'std' separately if the current
                # modaliases don't already include it.
                if ictx.modaliases.get(None, 'std') != 'std':
                    search_ns.append({None: 'std'})

                # Search in the current namespace AND in std.
                for aliases in search_ns:
                    # Use the specific modaliases instead of the
                    # context ones.
                    with ictx.subquery() as newctx:
                        newctx.modaliases = aliases
                        # Get the default module name
                        modname = aliases[None]
                        # Is the current item a function
                        is_function = (itemclass is
                                       qltypes.SchemaObjectClass.FUNCTION)

                        # We need to check functions if we're looking for them
                        # specifically or if this is a broad search. They are
                        # handled separately because they allow multiple
                        # matches for the same name.
                        if (itemclass is None or is_function):
                            try:
                                funcs: Tuple[s_func.Function, ...] = (
                                    newctx.env.schema.get_functions(
                                        name, module_aliases=aliases))
                            except errors.InvalidReferenceError:
                                pass
                            else:
                                for func in funcs:
                                    items[f'function_{modname}'].append(
                                        func.get_name(newctx.env.schema))

                        # Also find an object matching the name as long as
                        # it's not a function we're looking for specifically.
                        if not is_function:
                            try:
                                if itemclass is not \
                                        qltypes.SchemaObjectClass.ALIAS:
                                    condition = None
                                    label = None
                                else:
                                    condition = (lambda obj: obj.
                                                 get_alias_is_persistent(
                                                     ctx.env.schema))
                                    label = 'alias'
                                obj = schemactx.get_schema_object(
                                    objref,
                                    item_type=itemtype,
                                    condition=condition,
                                    label=label,
                                    ctx=newctx,
                                )
                                items[f'other_{modname}'].append(
                                    obj.get_name(newctx.env.schema))
                            except errors.InvalidReferenceError as exc:
                                # Record the exception to be possibly
                                # raised if no matches are found
                                last_exc = exc

                # If we already have some results, suppress the exception,
                # otherwise raise the recorded exception.
                if not items and last_exc:
                    raise last_exc

            verbose = ql.options.get_flag('VERBOSE')

            if ql.language is qltypes.DescribeLanguage.DDL:
                method = s_ddl.ddl_text_from_schema
            elif ql.language is qltypes.DescribeLanguage.SDL:
                method = s_ddl.sdl_text_from_schema
            elif ql.language is qltypes.DescribeLanguage.TEXT:
                method = s_ddl.descriptive_text_from_schema
                if not verbose.val:
                    referenced_classes = [s_links.Link, s_lprops.Property]
            else:
                raise errors.InternalServerError(
                    f'cannot handle describe language {ql.language}')

            # Based on the items found generate main text and a
            # potential comment about masked items.
            defmod = ictx.modaliases.get(None, 'std')
            default_items = []
            masked_items = set()
            for objtype in ['function', 'other']:
                defkey = f'{objtype}_{defmod}'
                mskkey = f'{objtype}_std'

                default_items += items.get(defkey, [])
                if defkey in items and mskkey in items:
                    # We have a match in default module and some masked.
                    masked_items.update(items.get(mskkey, []))
                else:
                    default_items += items.get(mskkey, [])

            # Throw out anything in the masked set that's already in
            # the default.
            masked_items.difference_update(default_items)

            text = method(
                ctx.env.schema,
                included_modules=modules,
                included_items=default_items,
                included_ref_classes=referenced_classes,
                include_module_ddl=False,
                include_std_ddl=True,
            )
            if masked_items:
                text += ('\n\n'
                         '# The following builtins are masked by the above:'
                         '\n\n')
                masked = method(
                    ctx.env.schema,
                    included_modules=modules,
                    included_items=masked_items,
                    included_ref_classes=referenced_classes,
                    include_module_ddl=False,
                    include_std_ddl=True,
                )
                masked = textwrap.indent(masked, '# ')
                text += masked

            ct = typegen.type_to_typeref(
                ctx.env.get_track_schema_type('std::str'),
                env=ctx.env,
            )

            stmt.result = setgen.ensure_set(
                irast.StringConstant(value=text, typeref=ct),
                ctx=ictx,
            )

        result = fini_stmt(stmt, ql, ctx=ictx, parent_ctx=ctx)

    return result
示例#12
0
文件: stmt.py 项目: signupsi/edgedb
def compile_ForQuery(
        qlstmt: qlast.ForQuery, *, ctx: context.ContextLevel) -> irast.Set:
    with ctx.subquery() as sctx:
        stmt = irast.SelectStmt(context=qlstmt.context)
        init_stmt(stmt, qlstmt, ctx=sctx, parent_ctx=ctx)

        # As an optimization, if the iterator is a singleton set, use
        # the element directly.
        iterator = qlstmt.iterator
        if isinstance(iterator, qlast.Set) and len(iterator.elements) == 1:
            iterator = iterator.elements[0]

        # Compile the iterator
        iterator_ctx = None
        if (ctx.expr_exposed and ctx.iterator_ctx is not None
                and ctx.iterator_ctx is not sctx):
            iterator_ctx = ctx.iterator_ctx

        ictx = iterator_ctx or sctx

        contains_dml = qlutils.contains_dml(qlstmt.result)
        # If the body contains DML, then we need to prohibit
        # correlation between the iterator and the enclosing
        # query, since the correlation imposes compilation issues
        # we aren't willing to tackle.
        if contains_dml:
            ictx.path_scope.factoring_allowlist.update(
                ctx.iterator_path_ids)
        iterator_view = stmtctx.declare_view(
            iterator,
            s_name.UnqualName(qlstmt.iterator_alias),
            factoring_fence=contains_dml,
            path_id_namespace=ictx.path_id_namespace,
            ctx=ictx,
        )

        iterator_stmt = setgen.new_set_from_set(
            iterator_view, preserve_scope_ns=True, ctx=sctx)
        stmt.iterator_stmt = iterator_stmt

        iterator_type = setgen.get_set_type(iterator_stmt, ctx=ctx)
        anytype = iterator_type.find_any(ctx.env.schema)
        if anytype is not None:
            raise errors.QueryError(
                'FOR statement has iterator of indeterminate type',
                context=ctx.env.type_origins.get(anytype),
            )

        if iterator_ctx is not None and iterator_ctx.stmt is not None:
            iterator_ctx.stmt.hoisted_iterators.append(iterator_stmt)

        view_scope_info = sctx.path_scope_map[iterator_view]

        pathctx.register_set_in_scope(
            iterator_stmt,
            path_scope=ictx.path_scope,
            ctx=sctx,
        )

        # Iterator symbol is, by construction, outside of the scope
        # of the UNION argument, but is perfectly legal to be referenced
        # inside a factoring fence that is an immediate child of this
        # scope.
        ictx.path_scope.factoring_allowlist.add(
            stmt.iterator_stmt.path_id)
        sctx.iterator_path_ids |= {stmt.iterator_stmt.path_id}
        node = ictx.path_scope.find_descendant(iterator_stmt.path_id)
        if node is not None:
            # See above about why we need a factoring fence.
            # We need to do this again when we move the branch so
            # as to preserve the fencing.
            # Do this by sticking the iterator subtree onto a branch
            # with a factoring fence.
            if contains_dml:
                node = node.attach_branch()
                node.factoring_fence = True
                node = node.attach_branch()

            node.attach_subtree(view_scope_info.path_scope,
                                context=iterator.context)

        # Compile the body
        with sctx.newscope(fenced=True) as bctx:
            stmt.result = setgen.scoped_set(
                compile_result_clause(
                    qlstmt.result,
                    view_scls=ctx.view_scls,
                    view_rptr=ctx.view_rptr,
                    result_alias=qlstmt.result_alias,
                    view_name=ctx.toplevel_result_view_name,
                    forward_rptr=True,
                    ctx=bctx,
                ),
                ctx=bctx,
            )

        # Inject an implicit limit if appropriate
        if ((ctx.expr_exposed or sctx.stmt is ctx.toplevel_stmt)
                and ctx.implicit_limit):
            stmt.limit = setgen.ensure_set(
                dispatch.compile(
                    qlast.IntegerConstant(value=str(ctx.implicit_limit)),
                    ctx=sctx,
                ),
                ctx=sctx,
            )

        result = fini_stmt(stmt, qlstmt, ctx=sctx, parent_ctx=ctx)

    return result