示例#1
0
    def _compile_dispatch_ql(self, ctx: CompileContext, ql: qlast.Base):

        if isinstance(ql, (qlast.Database, qlast.Delta)):
            if not (ctx.state.capability & enums.Capability.DDL):
                raise errors.ProtocolError(
                    f'cannot execute DDL commands for the current connection')
            return self._compile_ql_migration(ctx, ql)

        elif isinstance(ql, qlast.DDL):
            if not (ctx.state.capability & enums.Capability.DDL):
                raise errors.ProtocolError(
                    f'cannot execute DDL commands for the current connection')
            return self._compile_ql_ddl(ctx, ql)

        elif isinstance(ql, qlast.Transaction):
            if not (ctx.state.capability & enums.Capability.TRANSACTION):
                raise errors.ProtocolError(
                    f'cannot execute transaction control commands '
                    f'for the current connection')
            return self._compile_ql_transaction(ctx, ql)

        elif isinstance(ql, (qlast.BaseSessionSet, qlast.BaseSessionReset)):
            if not (ctx.state.capability & enums.Capability.SESSION):
                raise errors.ProtocolError(
                    f'cannot execute session control commands '
                    f'for the current connection')
            return self._compile_ql_sess_state(ctx, ql)

        elif isinstance(ql, qlast.ConfigOp):
            if not (ctx.state.capability & enums.Capability.SESSION):
                raise errors.ProtocolError(
                    f'cannot execute session control commands '
                    f'for the current connection')
            return self._compile_ql_config_op(ctx, ql)

        else:
            if not (ctx.state.capability & enums.Capability.QUERY):
                raise errors.ProtocolError(
                    f'cannot execute query/DML commands '
                    f'for the current connection')
            return self._compile_ql_query(ctx, ql)
示例#2
0
    def _compile(self, *, ctx: CompileContext,
                 eql: bytes) -> typing.List[dbstate.QueryUnit]:

        # When True it means that we're compiling for "connection.fetchall()".
        # That means that the returned QueryUnit has to have the in/out codec
        # information, correctly inferred "singleton_result" field etc.
        single_stmt_mode = ctx.stmt_mode is enums.CompileStatementMode.SINGLE
        default_cardinality = enums.ResultCardinality.NOT_APPLICABLE

        eql = eql.decode()

        statements = edgeql.parse_block(eql)
        statements_len = len(statements)

        if ctx.stmt_mode is enums.CompileStatementMode.SKIP_FIRST:
            statements = statements[1:]
            if not statements:  # pragma: no cover
                # Shouldn't ever happen as the server tracks the number
                # of statements (via the "try_compile_rollback()" method)
                # before using SKIP_FIRST.
                raise errors.ProtocolError(
                    f'no statements to compile in SKIP_FIRST mode')
        elif single_stmt_mode and statements_len != 1:
            raise errors.ProtocolError(
                f'expected one statement, got {statements_len}')

        if not len(statements):  # pragma: no cover
            raise errors.ProtocolError('nothing to compile')

        units = []
        unit = None

        for stmt in statements:
            comp: dbstate.BaseQuery = self._compile_dispatch_ql(ctx, stmt)

            if unit is not None:
                if (isinstance(comp, dbstate.TxControlQuery)
                        and comp.single_unit):
                    units.append(unit)
                    unit = None

            if unit is None:
                unit = dbstate.QueryUnit(dbver=ctx.state.dbver,
                                         sql=(),
                                         status=status.get_status(stmt),
                                         cardinality=default_cardinality)
            else:
                unit.status = status.get_status(stmt)

            if isinstance(comp, dbstate.Query):
                if single_stmt_mode:
                    unit.sql = comp.sql
                    unit.sql_hash = comp.sql_hash

                    unit.out_type_data = comp.out_type_data
                    unit.out_type_id = comp.out_type_id
                    unit.in_type_data = comp.in_type_data
                    unit.in_type_args = comp.in_type_args
                    unit.in_type_id = comp.in_type_id
                    unit.in_array_backend_tids = comp.in_array_backend_tids

                    unit.cacheable = True

                    unit.cardinality = comp.cardinality
                else:
                    unit.sql += comp.sql

            elif isinstance(comp, dbstate.SimpleQuery):
                assert not single_stmt_mode
                unit.sql += comp.sql

            elif isinstance(comp, dbstate.DDLQuery):
                unit.sql += comp.sql
                unit.has_ddl = True
                unit.new_types = comp.new_types

            elif isinstance(comp, dbstate.TxControlQuery):
                unit.sql += comp.sql
                unit.cacheable = comp.cacheable

                if comp.modaliases is not None:
                    unit.modaliases = comp.modaliases

                if comp.action == dbstate.TxAction.START:
                    if unit.tx_id is not None:
                        raise errors.InternalServerError(
                            'already in transaction')
                    unit.tx_id = ctx.state.current_tx().id
                elif comp.action == dbstate.TxAction.COMMIT:
                    unit.tx_commit = True
                elif comp.action == dbstate.TxAction.ROLLBACK:
                    unit.tx_rollback = True
                elif comp.action is dbstate.TxAction.ROLLBACK_TO_SAVEPOINT:
                    unit.tx_savepoint_rollback = True

                if comp.single_unit:
                    units.append(unit)
                    unit = None

            elif isinstance(comp, dbstate.SessionStateQuery):
                unit.sql += comp.sql

                if comp.is_system_setting:
                    if (not ctx.state.current_tx().is_implicit()
                            or statements_len > 1):
                        raise errors.QueryError(
                            'CONFIGURE SYSTEM cannot be executed in a '
                            'transaction block')

                    unit.system_config = True

                if comp.is_backend_setting:
                    unit.backend_config = True
                if comp.requires_restart:
                    unit.config_requires_restart = True

                if ctx.state.current_tx().is_implicit():
                    unit.modaliases = ctx.state.current_tx().get_modaliases()

                if comp.config_op is not None:
                    if unit.config_ops is None:
                        unit.config_ops = []
                    unit.config_ops.append(comp.config_op)

                unit.has_set = True

            else:  # pragma: no cover
                raise errors.InternalServerError('unknown compile state')

        if unit is not None:
            units.append(unit)

        if single_stmt_mode:
            if len(units) != 1:  # pragma: no cover
                raise errors.InternalServerError(
                    f'expected 1 compiled unit; got {len(units)}')

        for unit in units:  # pragma: no cover
            # Sanity checks
            na_cardinality = (unit.cardinality is
                              enums.ResultCardinality.NOT_APPLICABLE)
            if unit.cacheable and (unit.config_ops or unit.modaliases):
                raise errors.InternalServerError(
                    f'QueryUnit {unit!r} is cacheable but has config/aliases')
            if not unit.sql:
                raise errors.InternalServerError(
                    f'QueryUnit {unit!r} has no SQL commands in it')
            if not na_cardinality and (
                    len(unit.sql) > 1 or unit.tx_commit or unit.tx_rollback
                    or unit.tx_savepoint_rollback
                    or unit.out_type_id is sertypes.NULL_TYPE_ID
                    or unit.system_config or unit.config_ops or unit.modaliases
                    or unit.has_set or unit.has_ddl or not unit.sql_hash):
                raise errors.InternalServerError(
                    f'unit has invalid "cardinality": {unit!r}')

        return units
示例#3
0
    def _compile(self, *, ctx: CompileContext,
                 eql: bytes) -> typing.List[dbstate.QueryUnit]:

        eql = eql.decode()
        if ctx.graphql_mode:
            eql = graphql.translate(
                ctx.state.current_tx().get_schema(), eql, variables={}) + ';'

        statements = edgeql.parse_block(eql)

        if ctx.single_query_mode and len(statements) > 1:
            raise errors.ProtocolError(
                f'expected one statement, got {len(statements)}')

        units = []
        unit = None

        txid = None
        if not ctx.state.current_tx().is_implicit():
            txid = ctx.state.current_tx().id

        for stmt in statements:
            comp: dbstate.BaseQuery = self._compile_dispatch_ql(ctx, stmt)

            if ctx.legacy_mode and unit is not None:
                units.append(unit)
                unit = None

            if unit is None:
                unit = dbstate.QueryUnit(txid=txid, dbver=ctx.state.dbver)

            if isinstance(comp, dbstate.Query):
                if ctx.single_query_mode or ctx.legacy_mode:
                    unit.sql = comp.sql
                    unit.sql_hash = comp.sql_hash

                    unit.out_type_data = comp.out_type_data
                    unit.out_type_id = comp.out_type_id
                    unit.in_type_data = comp.in_type_data
                    unit.in_type_id = comp.in_type_id
                else:
                    unit.sql += comp.sql

            elif isinstance(comp, dbstate.SimpleQuery):
                unit.sql += comp.sql

            elif isinstance(comp, dbstate.DDLQuery):
                unit.sql += comp.sql
                unit.has_ddl = True

            elif isinstance(comp, dbstate.TxControlQuery):
                unit.sql += comp.sql

                if comp.action == dbstate.TxAction.START:
                    unit.starts_tx = True
                    unit.txid = txid = ctx.state.current_tx().id
                else:
                    if comp.action == dbstate.TxAction.COMMIT:
                        unit.commits_tx = True
                    else:
                        unit.rollbacks_tx = True

                    units.append(unit)
                    unit = None

            elif isinstance(comp, dbstate.SessionStateQuery):
                unit.config = ctx.state.current_tx().get_config()
                unit.modaliases = ctx.state.current_tx().get_modaliases()

            else:
                raise RuntimeError('unknown compile state')

        if unit is not None:
            units.append(unit)

        return units