Exemplo n.º 1
0
    async def run_ddl_command(self, ddl_plan):
        schema = await self.getschema()

        if debug.flags.delta_plan_input:
            debug.header('Delta Plan Input')
            debug.dump(ddl_plan)

        # Do a dry-run on test_schema to canonicalize
        # the schema delta-commands.
        test_schema = await self._intro_mech.readschema()
        context = sd.CommandContext()
        canonical_ddl_plan = ddl_plan.copy()
        canonical_ddl_plan.apply(test_schema, context=context)

        # Apply and adapt delta, build native delta plan, which
        # will also update the schema.
        plan = self.process_delta(canonical_ddl_plan, schema)

        context = delta_cmds.CommandContext(self.connection)

        try:
            if not isinstance(plan, (s_db.CreateDatabase, s_db.DropDatabase)):
                async with self.connection.transaction():
                    # Execute all pgsql/delta commands.
                    await plan.execute(context)
            else:
                await plan.execute(context)
        except Exception as e:
            raise RuntimeError('failed to apply delta to data backend') from e
        finally:
            # Exception or not, re-read the schema from Postgres.
            await self.invalidate_schema_cache()
            await self.getschema()
Exemplo n.º 2
0
    async def run_ddl_command(self, ddl_plan):
        schema = self.schema

        if debug.flags.delta_plan_input:
            debug.header('Delta Plan Input')
            debug.dump(ddl_plan)

        # Do a dry-run on test_schema to canonicalize
        # the schema delta-commands.
        test_schema = schema
        context = self.create_context()
        canonical_ddl_plan = ddl_plan.copy()
        canonical_ddl_plan.apply(test_schema, context=context)

        # Apply and adapt delta, build native delta plan, which
        # will also update the schema.
        schema, plan = self.process_delta(canonical_ddl_plan, schema)

        context = self.create_context(delta_cmds)

        if isinstance(plan, (s_db.CreateDatabase, s_db.DropDatabase)):
            block = dbops.SQLBlock()
        else:
            block = dbops.PLTopBlock()

        plan.generate(block)
        ql_text = block.to_string()

        await self._execute_ddl(ql_text)
        self.schema = schema
Exemplo n.º 3
0
    async def execute(self, context):
        code, vars = await self.get_code_and_vars(context)

        if code:
            extra = await self.extra(context)
            extra_before = extra_after = None

            if isinstance(extra, dict):
                extra_before = extra.get('before')
                extra_after = extra.get('after')
            else:
                extra_after = extra

            if extra_before:
                for cmd in extra_before:
                    await cmd.execute(context)

            if debug.flags.delta_execute:
                debug.header('Executing DDL')
                debug.print(repr(self))
                debug.print('CODE:', code)
                debug.print('VARS:', vars)

            stmt = await context.db.prepare(code)
            result = await stmt.fetch(*vars)

            if extra_after:
                for cmd in extra_after:
                    await cmd.execute(context)
            return result
Exemplo n.º 4
0
    def _compile_and_apply_ddl_command(self, ctx: CompileContext, cmd):
        current_tx = ctx.state.current_tx()
        schema = current_tx.get_schema()

        if debug.flags.delta_plan_input:
            debug.header('Delta Plan Input')
            debug.dump(cmd)

        # Do a dry-run on test_schema to canonicalize
        # the schema delta-commands.
        test_schema = schema
        context = self._new_delta_context(ctx)
        cmd.apply(test_schema, context=context)

        # Apply and adapt delta, build native delta plan, which
        # will also update the schema.
        schema, plan = self._process_delta(ctx, cmd, schema)

        if isinstance(plan, (s_db.CreateDatabase, s_db.DropDatabase)):
            block = pg_dbops.SQLBlock()
        else:
            block = pg_dbops.PLTopBlock()

        plan.generate(block)
        sql = block.to_string().encode('utf-8')

        current_tx.update_schema(schema)

        return dbstate.DDLQuery(sql=sql)
Exemplo n.º 5
0
    async def _load_std(self):
        schema = s_schema.Schema()

        current_block = None

        std_texts = []
        for modname in s_schema.STD_LIB + ['stdgraphql']:
            std_texts.append(s_std.get_std_module_text(modname))

        ddl_text = '\n'.join(std_texts)

        for ddl_cmd in edgeql.parse_block(ddl_text):
            delta_command = s_ddl.delta_from_ddl(
                ddl_cmd, schema=schema, modaliases={None: 'std'}, stdmode=True)

            if debug.flags.delta_plan_input:
                debug.header('Delta Plan Input')
                debug.dump(delta_command)

            # Do a dry-run on test_schema to canonicalize
            # the schema delta-commands.
            test_schema = schema
            context = self.create_context(stdmode=True)
            canonical_delta = delta_command.copy()
            canonical_delta.apply(test_schema, context=context)

            # Apply and adapt delta, build native delta plan, which
            # will also update the schema.
            schema, plan = self.process_delta(canonical_delta, schema,
                                              stdmode=True)

            if isinstance(plan, (s_db.CreateDatabase, s_db.DropDatabase)):
                if (current_block is not None and
                        not isinstance(current_block, dbops.SQLBlock)):
                    raise errors.QueryError(
                        'cannot mix DATABASE commands with regular DDL '
                        'commands in a single block')
                if current_block is None:
                    current_block = dbops.SQLBlock()

            else:
                if (current_block is not None and
                        not isinstance(current_block, dbops.PLTopBlock)):
                    raise errors.QueryError(
                        'cannot mix DATABASE commands with regular DDL '
                        'commands in a single block')
                if current_block is None:
                    current_block = dbops.PLTopBlock()

            plan.generate(current_block)

        sql_text = current_block.to_string()

        return schema, sql_text
Exemplo n.º 6
0
    async def _execute_ddl(self, sql_text):
        try:
            if debug.flags.delta_execute:
                debug.header('Delta Script')
                debug.dump_code(sql_text, lexer='sql')

            await self.connection.execute(sql_text)

        except Exception as e:
            position = getattr(e, 'position', None)
            internal_position = getattr(e, 'internal_position', None)
            context = getattr(e, 'context', '')
            if context:
                pl_func_line = re.search(
                    r'^PL/pgSQL function inline_code_block line (\d+).*',
                    context, re.M)

                if pl_func_line:
                    pl_func_line = int(pl_func_line.group(1))
            else:
                pl_func_line = None
            point = None

            if position is not None:
                position = int(position)
                point = parser_context.SourcePoint(
                    None, None, position)
                text = e.query
                if text is None:
                    # Parse errors
                    text = sql_text

            elif internal_position is not None:
                internal_position = int(internal_position)
                point = parser_context.SourcePoint(
                    None, None, internal_position)
                text = e.internal_query

            elif pl_func_line:
                point = parser_context.SourcePoint(
                    pl_func_line, None, None
                )
                text = sql_text

            if point is not None:
                context = parser_context.ParserContext(
                    'query', text, start=point, end=point)
                exceptions.replace_context(e, context)

            raise
Exemplo n.º 7
0
    def process_delta(self, delta, schema, *, stdmode=None):
        """Adapt and process the delta command."""

        if debug.flags.delta_plan:
            debug.header('Delta Plan')
            debug.dump(delta, schema=schema)

        delta = self.adapt_delta(delta)
        context = self.create_context(delta_cmds, stdmode)
        schema, _ = delta.apply(schema, context)

        if debug.flags.delta_pgsql_plan:
            debug.header('PgSQL Delta Plan')
            debug.dump(delta, schema=schema)

        return schema, delta
Exemplo n.º 8
0
    def process_delta(self, delta, schema):
        """Adapt and process the delta command."""

        if debug.flags.delta_plan:
            debug.header('Delta Plan')
            debug.dump(delta)

        delta = self.adapt_delta(delta)
        context = delta_cmds.CommandContext(self.connection)
        delta.apply(schema, context)

        if debug.flags.delta_pgsql_plan:
            debug.header('PgSQL Delta Plan')
            debug.dump(delta)

        return delta
Exemplo n.º 9
0
    def _process_delta(self, ctx: CompileContext, delta, schema):
        """Adapt and process the delta command."""

        if debug.flags.delta_plan:
            debug.header('Delta Plan')
            debug.dump(delta, schema=schema)

        delta = pg_delta.CommandMeta.adapt(delta)
        context = self._new_delta_context(ctx)
        schema, _ = delta.apply(schema, context)

        if debug.flags.delta_pgsql_plan:
            debug.header('PgSQL Delta Plan')
            debug.dump(delta, schema=schema)

        return schema, delta
Exemplo n.º 10
0
def compile_ir_to_sql(
        ir_expr: irast.Base,
        *,
        schema: s_schema.Schema,
        output_format: typing.Optional[OutputFormat] = None,
        ignore_shapes: bool = False,
        timer=None,
        use_named_params: bool = False,
        pretty: bool = True) -> typing.Tuple[str, typing.Dict[str, int]]:

    if timer is None:
        qtree = compile_ir_to_sql_tree(ir_expr,
                                       schema=schema,
                                       output_format=output_format,
                                       ignore_shapes=ignore_shapes,
                                       use_named_params=use_named_params)
    else:
        with timer.timeit('compile_ir_to_sql'):
            qtree = compile_ir_to_sql_tree(ir_expr,
                                           schema=schema,
                                           output_format=output_format,
                                           ignore_shapes=ignore_shapes,
                                           use_named_params=use_named_params)

    if debug.flags.edgeql_compile:  # pragma: no cover
        debug.header('SQL Tree')
        debug.dump(qtree, schema=schema)

    argmap = qtree.argnames

    # Generate query text
    if timer is None:
        codegen = _run_codegen(qtree, pretty=pretty)
    else:
        with timer.timeit('compile_ir_to_sql'):
            codegen = _run_codegen(qtree, pretty=pretty)

    sql_text = ''.join(codegen.result)

    if debug.flags.edgeql_compile:  # pragma: no cover
        debug.header('SQL')
        debug.dump_code(sql_text, lexer='sql')

    return sql_text, argmap
Exemplo n.º 11
0
def compile_to_ir(expr,
                  schema,
                  *,
                  anchors=None,
                  security_context=None,
                  modaliases=None,
                  implicit_id_in_shapes=False):
    """Compile given EdgeQL statement into EdgeDB IR."""

    if debug.flags.edgeql_compile:
        debug.header('EdgeQL TEXT')
        debug.print(expr)

    tree = ql_parser.parse(expr, modaliases)

    return compile_ast_to_ir(tree,
                             schema,
                             anchors=anchors,
                             security_context=security_context,
                             modaliases=modaliases,
                             implicit_id_in_shapes=implicit_id_in_shapes)
Exemplo n.º 12
0
    def send_error(self, err):
        try:
            srcctx = exceptions.get_context(err, parsing.ParserContext)
        except LookupError:
            srcctx = None

        try:
            hintctx = exceptions.get_context(
                err, exceptions.DefaultExceptionContext)
        except LookupError:
            hintctx = None

        if debug.flags.server:
            debug.header('Error')
            debug.dump(err)

        self.send_message({
            '__type__': 'error',
            'data': {
                'C':
                getattr(err, 'code', 0),
                'M':
                str(err),
                'D':
                hintctx.details if hintctx is not None else None,
                'H':
                hintctx.hint if hintctx is not None else None,
                'P': (srcctx.start.pointer if srcctx is not None
                      and srcctx.start is not None else None),
                'p': (srcctx.end.pointer if srcctx is not None
                      and srcctx.end is not None else None),
                'Q':
                markup.dumps(srcctx) if srcctx is not None else None,
                'T':
                traceback.format_tb(err.__traceback__),
            }
        })
Exemplo n.º 13
0
def compile_ast_to_ir(tree,
                      schema,
                      *,
                      anchors=None,
                      singletons=None,
                      func=None,
                      security_context=None,
                      derived_target_module=None,
                      result_view_name=None,
                      modaliases=None,
                      implicit_id_in_shapes=False,
                      schema_view_mode=False):
    """Compile given EdgeQL AST into EdgeDB IR."""

    if debug.flags.edgeql_compile:
        debug.header('EdgeQL AST')
        debug.dump(tree, schema=schema)

    ctx = stmtctx.init_context(schema=schema,
                               anchors=anchors,
                               singletons=singletons,
                               modaliases=modaliases,
                               security_context=security_context,
                               func=func,
                               derived_target_module=derived_target_module,
                               result_view_name=result_view_name,
                               implicit_id_in_shapes=implicit_id_in_shapes,
                               schema_view_mode=schema_view_mode)

    ir_set = dispatch.compile(tree, ctx=ctx)
    ir_expr = stmtctx.fini_expression(ir_set, ctx=ctx)

    if ctx.env.query_parameters:
        first_argname = next(iter(ctx.env.query_parameters))
        if first_argname.isdecimal():
            args_decnames = {int(arg) for arg in ctx.env.query_parameters}
            args_tpl = set(range(len(ctx.env.query_parameters)))
            if args_decnames != args_tpl:
                missing_args = args_tpl - args_decnames
                missing_args_repr = ', '.join(f'${a}' for a in missing_args)
                raise errors.QueryError(
                    f'missing {missing_args_repr} positional argument'
                    f'{"s" if len(missing_args) > 1 else ""}')

    if debug.flags.edgeql_compile:
        debug.header('Scope Tree')
        if ctx.path_scope is not None:
            print(ctx.path_scope.pdebugformat())
        else:
            print('N/A')
        debug.header('EdgeDB IR')
        debug.dump(ir_expr, schema=getattr(ir_expr, 'schema', None))

    return ir_expr
Exemplo n.º 14
0
def compile_ast_to_ir(tree,
                      schema,
                      *,
                      anchors=None,
                      arg_types=None,
                      security_context=None,
                      derived_target_module=None,
                      result_view_name=None,
                      modaliases=None,
                      implicit_id_in_shapes=False):
    """Compile given EdgeQL AST into EdgeDB IR."""

    if debug.flags.edgeql_compile:
        debug.header('EdgeQL AST')
        debug.dump(tree)

    ctx = stmtctx.init_context(schema=schema,
                               anchors=anchors,
                               modaliases=modaliases,
                               security_context=security_context,
                               arg_types=arg_types,
                               derived_target_module=derived_target_module,
                               result_view_name=result_view_name,
                               implicit_id_in_shapes=implicit_id_in_shapes)

    ir_set = dispatch.compile(tree, ctx=ctx)
    ir_expr = stmtctx.fini_expression(ir_set, ctx=ctx)

    if debug.flags.edgeql_compile:
        debug.header('Scope Tree')
        if ctx.path_scope is not None:
            print(ctx.path_scope.pdebugformat())
        else:
            print('N/A')
        debug.header('EdgeDB IR')
        debug.dump(ir_expr)

    return ir_expr
Exemplo n.º 15
0
def compile_func_to_ir(func,
                       schema,
                       *,
                       anchors=None,
                       security_context=None,
                       modaliases=None,
                       implicit_id_in_shapes=False):
    """Compile an EdgeQL function into EdgeDB IR."""

    if debug.flags.edgeql_compile:
        debug.header('EdgeQL Function')
        debug.print(func.get_code(schema))

    trees = ql_parser.parse_block(func.get_code(schema) + ';')
    if len(trees) != 1:
        raise errors.InvalidFunctionDefinitionError(
            'functions can only contain one statement')

    tree = trees[0]
    if modaliases:
        ql_parser.append_module_aliases(tree, modaliases)

    if anchors is None:
        anchors = {}

    anchors['__defaults_mask__'] = irast.Parameter(
        name='__defaults_mask__', stype=schema.get('std::bytes'))

    func_params = func.get_params(schema)
    pg_params = s_func.PgParams.from_params(schema, func_params)
    for pi, p in enumerate(pg_params.params):
        p_shortname = p.get_shortname(schema)
        anchors[p_shortname] = irast.Parameter(name=p_shortname,
                                               stype=p.get_type(schema))

        if p.get_default(schema) is None:
            continue

        tree.aliases.append(
            qlast.AliasedExpr(
                alias=p_shortname,
                expr=qlast.
                IfElse(condition=qlast.BinOp(left=qlast.FunctionCall(
                    func=('std', 'bytes_get_bit'),
                    args=[
                        qlast.FuncArg(arg=qlast.Path(
                            steps=[qlast.ObjectRef(
                                name='__defaults_mask__')])),
                        qlast.FuncArg(arg=qlast.IntegerConstant(value=str(pi)))
                    ]),
                                             right=qlast.IntegerConstant(
                                                 value='0'),
                                             op='='),
                       if_expr=qlast.Path(
                           steps=[qlast.ObjectRef(name=p_shortname)]),
                       else_expr=qlast._Optional(
                           expr=p.get_ql_default(schema)))))

    ir = compile_ast_to_ir(tree,
                           schema,
                           anchors=anchors,
                           func=func,
                           security_context=security_context,
                           modaliases=modaliases,
                           implicit_id_in_shapes=implicit_id_in_shapes)

    return ir
Exemplo n.º 16
0
async def _execute_block(conn, block: dbops.PLBlock) -> None:
    sql_text = block.to_string()
    if debug.flags.bootstrap:
        debug.header('Bootstrap')
        debug.dump_code(sql_text, lexer='sql')
    await _execute(conn, sql_text)