Exemplo n.º 1
0
def _compile_set_in_singleton_mode(
        node: irast.Set, *, ctx: context.CompilerContextLevel) -> pgast.Base:
    if isinstance(node, irast.EmptySet):
        return pgast.Constant(value=None)
    elif node.expr is not None:
        return dispatch.compile(node.expr, ctx=ctx)
    else:
        if node.rptr:
            ptrcls = node.rptr.ptrcls
            source = node.rptr.source

            if not ptrcls.is_link_property():
                if source.rptr:
                    raise RuntimeError('unexpectedly long path in simple expr')

            colref = pgast.ColumnRef(
                name=[common.edgedb_name_to_pg_name(ptrcls.shortname)])
        elif isinstance(node.scls, s_scalars.ScalarType):
            colref = pgast.ColumnRef(
                name=[common.edgedb_name_to_pg_name(node.scls.name)])
        else:
            colref = pgast.ColumnRef(
                name=[common.edgedb_name_to_pg_name(node.scls.name)])

        return colref
Exemplo n.º 2
0
    def create_constr_trigger(self, table_name, constraint, proc_name):
        cmds = []

        cname = constraint.raw_constraint_name()

        ins_trigger_name = common.edgedb_name_to_pg_name(cname + '_instrigger')
        ins_trigger = dbops.Trigger(
            name=ins_trigger_name, table_name=table_name, events=('insert', ),
            procedure=proc_name, is_constraint=True, inherit=True)
        cr_ins_trigger = dbops.CreateTrigger(ins_trigger)
        cmds.append(cr_ins_trigger)

        disable_ins_trigger = dbops.DisableTrigger(ins_trigger, self_only=True)
        cmds.append(disable_ins_trigger)

        upd_trigger_name = common.edgedb_name_to_pg_name(cname + '_updtrigger')
        condition = constraint.get_trigger_condition()

        upd_trigger = dbops.Trigger(
            name=upd_trigger_name, table_name=table_name, events=('update', ),
            procedure=proc_name, condition=condition, is_constraint=True,
            inherit=True)
        cr_upd_trigger = dbops.CreateTrigger(upd_trigger)
        cmds.append(cr_upd_trigger)

        disable_upd_trigger = dbops.DisableTrigger(upd_trigger, self_only=True)
        cmds.append(disable_upd_trigger)

        return cmds
Exemplo n.º 3
0
    def create_constr_trigger(self, table_name, constraint, proc_name):
        cmds = []

        cname = constraint.raw_constraint_name()

        ins_trigger_name = common.edgedb_name_to_pg_name(cname + '_instrigger')
        ins_trigger = dbops.Trigger(name=ins_trigger_name,
                                    table_name=table_name,
                                    events=('insert', ),
                                    procedure=proc_name,
                                    is_constraint=True,
                                    inherit=True)
        cr_ins_trigger = dbops.CreateTrigger(ins_trigger)
        cmds.append(cr_ins_trigger)

        disable_ins_trigger = dbops.DisableTrigger(ins_trigger, self_only=True)
        cmds.append(disable_ins_trigger)

        upd_trigger_name = common.edgedb_name_to_pg_name(cname + '_updtrigger')
        condition = constraint.get_trigger_condition()

        upd_trigger = dbops.Trigger(name=upd_trigger_name,
                                    table_name=table_name,
                                    events=('update', ),
                                    procedure=proc_name,
                                    condition=condition,
                                    is_constraint=True,
                                    inherit=True)
        cr_upd_trigger = dbops.CreateTrigger(upd_trigger)
        cmds.append(cr_upd_trigger)

        disable_upd_trigger = dbops.DisableTrigger(upd_trigger, self_only=True)
        cmds.append(disable_upd_trigger)

        return cmds
Exemplo n.º 4
0
    def rename_constr_trigger(self, table_name):
        constraint = self._constraint
        new_constr = self._new_constraint

        cname = constraint.raw_constraint_name()
        ncname = new_constr.raw_constraint_name()

        ins_trigger_name = common.edgedb_name_to_pg_name(cname + '_instrigger')
        new_ins_trg_name = common.edgedb_name_to_pg_name(
            ncname + '_instrigger')

        ins_trigger = dbops.Trigger(
            name=ins_trigger_name, table_name=table_name, events=('insert', ),
            procedure='null', is_constraint=True, inherit=True)

        rn_ins_trigger = dbops.AlterTriggerRenameTo(
            ins_trigger, new_name=new_ins_trg_name)

        upd_trigger_name = common.edgedb_name_to_pg_name(cname + '_updtrigger')
        new_upd_trg_name = common.edgedb_name_to_pg_name(
            ncname + '_updtrigger')

        upd_trigger = dbops.Trigger(
            name=upd_trigger_name, table_name=table_name, events=('update', ),
            procedure='null', is_constraint=True, inherit=True)

        rn_upd_trigger = dbops.AlterTriggerRenameTo(
            upd_trigger, new_name=new_upd_trg_name)

        return (rn_ins_trigger, rn_upd_trigger)
Exemplo n.º 5
0
def _new_mapped_pointer_rvar(
        ir_ptr: irast.Pointer, nullable: bool=False, *,
        ctx: context.CompilerContextLevel) -> pgast.BaseRangeVar:
    ptrcls = ir_ptr.ptrcls
    ptr_rvar = dbobj.range_for_pointer(ir_ptr, env=ctx.env)
    ptr_rvar.nullable = nullable
    # Set up references according to the link direction.
    if isinstance(ptrcls, s_links.Link):
        # XXX: fix this once Properties are Sources
        src_ptr_info = pg_types.get_pointer_storage_info(
            ptrcls.getptr(ctx.env.schema, 'std::source'), resolve_type=False)
        src_col = src_ptr_info.column_name
    else:
        src_col = common.edgedb_name_to_pg_name('std::source')

    source_ref = dbobj.get_column(None, src_col)

    if isinstance(ptrcls, s_links.Link):
        # XXX: fix this once Properties are Sources
        tgt_ptr_info = pg_types.get_pointer_storage_info(
            ptrcls.getptr(ctx.env.schema, 'std::target'), resolve_type=False)
        tgt_col = tgt_ptr_info.column_name
    else:
        tgt_col = common.edgedb_name_to_pg_name('std::target')

    target_ref = dbobj.get_column(None, tgt_col)

    if ir_ptr.direction == s_pointers.PointerDirection.Inbound:
        near_ref = target_ref
        far_ref = source_ref
    else:
        near_ref = source_ref
        far_ref = target_ref

    ptr_rvar.query.path_id = ir_ptr.target.path_id.ptr_path()
    ptr_rvar.path_scope.add(ptr_rvar.query.path_id)

    src_pid = ir_ptr.source.path_id
    ptr_rvar.path_scope.add(src_pid)
    pathctx.put_rvar_path_output(ptr_rvar, src_pid, aspect='identity',
                                 var=near_ref, env=ctx.env)

    tgt_pid = ir_ptr.target.path_id
    if tgt_pid.is_objtype_path():
        ptr_rvar.path_scope.add(tgt_pid)
        pathctx.put_rvar_path_output(ptr_rvar, tgt_pid, aspect='identity',
                                     var=far_ref, env=ctx.env)
    else:
        pathctx.put_rvar_path_output(ptr_rvar, tgt_pid, aspect='value',
                                     var=far_ref, env=ctx.env)

    return ptr_rvar
Exemplo n.º 6
0
    def get_id(self):
        raw_name = self.constraint.raw_constraint_name()
        name = common.edgedb_name_to_pg_name('{}#{}'.format(
            raw_name, self.index))
        name = common.quote_ident(name)

        return '{} ON {} {}'.format(name, self.constraint.get_subject_type(),
                                    self.constraint.get_subject_name())
Exemplo n.º 7
0
    def drop_constr_trigger(self, table_name, constraint):
        cname = constraint.raw_constraint_name()

        ins_trigger_name = common.edgedb_name_to_pg_name(cname + '_instrigger')
        ins_trigger = dbops.Trigger(
            name=ins_trigger_name, table_name=table_name, events=('insert', ),
            procedure='null', is_constraint=True, inherit=True)

        drop_ins_trigger = dbops.DropTrigger(ins_trigger)

        upd_trigger_name = common.edgedb_name_to_pg_name(cname + '_updtrigger')
        upd_trigger = dbops.Trigger(
            name=upd_trigger_name, table_name=table_name, events=('update', ),
            procedure='null', is_constraint=True, inherit=True)

        drop_upd_trigger = dbops.DropTrigger(upd_trigger)

        return [drop_ins_trigger, drop_upd_trigger]
Exemplo n.º 8
0
    def get_id(self):
        raw_name = self.constraint.raw_constraint_name()
        name = common.edgedb_name_to_pg_name(
            '{}#{}'.format(raw_name, self.index))
        name = common.quote_ident(name)

        return '{} ON {} {}'.format(
            name, self.constraint.get_subject_type(),
            self.constraint.get_subject_name())
Exemplo n.º 9
0
    def __init__(self, *, scls, field, expr,
                 conditions=None, neg_conditions=None, priority=0):
        super().__init__(
            conditions=conditions, neg_conditions=neg_conditions,
            priority=priority)

        self.name = scls.name
        self.table = metaschema.get_metaclass_table(scls.__class__)
        self.field = common.edgedb_name_to_pg_name(field)
        self.expr = expr
Exemplo n.º 10
0
def new_static_class_rvar(
        ir_set: irast.Set, *,
        lateral: bool=True,
        ctx: context.CompilerContextLevel) -> pgast.BaseRangeVar:
    set_rvar = new_root_rvar(ir_set, ctx=ctx)
    clsname = pgast.Constant(val=ir_set.rptr.source.scls.material_type().name)
    nameref = dbobj.get_column(
        set_rvar, common.edgedb_name_to_pg_name('schema::name'))
    condition = astutils.new_binop(nameref, clsname, op='=')
    substmt = pgast.SelectStmt()
    include_rvar(substmt, set_rvar, ir_set.path_id, aspect='value', ctx=ctx)
    substmt.where_clause = astutils.extend_binop(
        substmt.where_clause, condition)
    return new_rel_rvar(ir_set, substmt, ctx=ctx)
Exemplo n.º 11
0
    def rename_constr_trigger(self, table_name):
        constraint = self._constraint
        new_constr = self._new_constraint

        cname = constraint.raw_constraint_name()
        ncname = new_constr.raw_constraint_name()

        ins_trigger_name = common.edgedb_name_to_pg_name(cname + '_instrigger')
        new_ins_trg_name = common.edgedb_name_to_pg_name(ncname +
                                                         '_instrigger')

        ins_trigger = dbops.Trigger(name=ins_trigger_name,
                                    table_name=table_name,
                                    events=('insert', ),
                                    procedure='null',
                                    is_constraint=True,
                                    inherit=True)

        rn_ins_trigger = dbops.AlterTriggerRenameTo(ins_trigger,
                                                    new_name=new_ins_trg_name)

        upd_trigger_name = common.edgedb_name_to_pg_name(cname + '_updtrigger')
        new_upd_trg_name = common.edgedb_name_to_pg_name(ncname +
                                                         '_updtrigger')

        upd_trigger = dbops.Trigger(name=upd_trigger_name,
                                    table_name=table_name,
                                    events=('update', ),
                                    procedure='null',
                                    is_constraint=True,
                                    inherit=True)

        rn_upd_trigger = dbops.AlterTriggerRenameTo(upd_trigger,
                                                    new_name=new_upd_trg_name)

        return (rn_ins_trigger, rn_upd_trigger)
Exemplo n.º 12
0
    def drop_constr_trigger(self, table_name, constraint):
        cname = constraint.raw_constraint_name()

        ins_trigger_name = common.edgedb_name_to_pg_name(cname + '_instrigger')
        ins_trigger = dbops.Trigger(name=ins_trigger_name,
                                    table_name=table_name,
                                    events=('insert', ),
                                    procedure='null',
                                    is_constraint=True,
                                    inherit=True)

        drop_ins_trigger = dbops.DropTrigger(ins_trigger)

        upd_trigger_name = common.edgedb_name_to_pg_name(cname + '_updtrigger')
        upd_trigger = dbops.Trigger(name=upd_trigger_name,
                                    table_name=table_name,
                                    events=('update', ),
                                    procedure='null',
                                    is_constraint=True,
                                    inherit=True)

        drop_upd_trigger = dbops.DropTrigger(upd_trigger)

        return [drop_ins_trigger, drop_upd_trigger]
Exemplo n.º 13
0
def new_static_class_rvar(
        ir_set: irast.Set,
        *,
        lateral: bool = True,
        ctx: context.CompilerContextLevel) -> pgast.BaseRangeVar:
    set_rvar = new_root_rvar(ir_set, ctx=ctx)
    clsname = pgast.Constant(val=ir_set.rptr.source.scls.material_type().name)
    nameref = dbobj.get_column(set_rvar,
                               common.edgedb_name_to_pg_name('schema::name'))
    condition = astutils.new_binop(nameref, clsname, op='=')
    substmt = pgast.SelectStmt()
    include_rvar(substmt, set_rvar, ir_set.path_id, aspect='value', ctx=ctx)
    substmt.where_clause = astutils.extend_binop(substmt.where_clause,
                                                 condition)
    return new_rel_rvar(ir_set, substmt, ctx=ctx)
Exemplo n.º 14
0
    def __init__(self,
                 *,
                 scls,
                 field,
                 expr,
                 conditions=None,
                 neg_conditions=None,
                 priority=0):
        super().__init__(conditions=conditions,
                         neg_conditions=neg_conditions,
                         priority=priority)

        self.name = scls.name
        self.table = metaschema.get_metaclass_table(scls.__class__)
        self.field = common.edgedb_name_to_pg_name(field)
        self.expr = expr
Exemplo n.º 15
0
    def drop_constraint(self, constraint):
        if not constraint.is_natively_inherited():
            self.add_commands(self.drop_constr_trigger(self.name, constraint))

            # Drop trigger function
            #
            proc_name = constraint.raw_constraint_name() + '_trigproc'
            proc_name = self.name[0], common.edgedb_name_to_pg_name(proc_name)

            self.add_commands(self.drop_constr_trigger_function(proc_name))

        # Drop the constraint normally from our table
        #
        my_alter = dbops.AlterTable(self.name)

        drop_constr = AlterTableDropMultiConstraint(constraint=constraint)
        my_alter.add_command(drop_constr)

        self.add_command(my_alter)
Exemplo n.º 16
0
    def drop_constraint(self, constraint):
        if not constraint.is_natively_inherited():
            self.add_commands(self.drop_constr_trigger(self.name, constraint))

            # Drop trigger function
            #
            proc_name = constraint.raw_constraint_name() + '_trigproc'
            proc_name = self.name[0], common.edgedb_name_to_pg_name(proc_name)

            self.add_commands(self.drop_constr_trigger_function(proc_name))

        # Drop the constraint normally from our table
        #
        my_alter = dbops.AlterTable(self.name)

        drop_constr = AlterTableDropMultiConstraint(constraint=constraint)
        my_alter.add_command(drop_constr)

        self.add_command(my_alter)
Exemplo n.º 17
0
    async def creation_code(self, context):
        link_map = await context.get_class_map()

        ids = tuple(sorted(list(link_map[n] for n in self.link_names)))
        id_str = '_'.join(str(i) for i in ids)

        name = '%s_%s_%s_cardinality_idx' % (self.name_prefix, id_str,
                                             self.cardinality)
        name = common.edgedb_name_to_pg_name(name)
        predicate = 'ptr_item_id IN (%s)' % ', '.join(str(id) for id in ids)

        code = '''
            CREATE {unique} INDEX {name} ON {table}s ({cols}) {predicate}
        '''.format(unique='UNIQUE',
                   name=common.qname(name),
                   table=common.qname(*self.table_name),
                   cols=', '.join(common.quote_ident(c) for c in self.columns),
                   predicate=('WHERE {}'.format(predicate)))

        return code
Exemplo n.º 18
0
    async def creation_code(self, context):
        link_map = await context.get_class_map()

        ids = tuple(sorted(list(link_map[n] for n in self.link_names)))
        id_str = '_'.join(str(i) for i in ids)

        name = '%s_%s_%s_cardinality_idx' % (
            self.name_prefix, id_str, self.cardinality)
        name = common.edgedb_name_to_pg_name(name)
        predicate = 'ptr_item_id IN (%s)' % ', '.join(str(id) for id in ids)

        code = '''
            CREATE {unique} INDEX {name} ON {table}s ({cols}) {predicate}
        '''.format(unique='UNIQUE',
                   name=common.qname(name),
                   table=common.qname(*self.table_name),
                   cols=', '.join(common.quote_ident(c) for c in self.columns),
                   predicate=('WHERE {}'.format(predicate)))

        return code
Exemplo n.º 19
0
def compile_FunctionCall(expr: irast.Base, *,
                         ctx: context.CompilerContextLevel) -> pgast.Base:
    funcobj = expr.func

    if funcobj.aggregate:
        raise RuntimeError(
            'aggregate functions are not supported in simple expressions')

    if funcobj.set_returning:
        raise RuntimeError(
            'set returning functions are not supported in simple expressions')

    args = [dispatch.compile(a, ctx=ctx) for a in expr.args]

    if funcobj.from_function:
        name = (funcobj.from_function, )
    else:
        name = (common.edgedb_module_name_to_schema_name(
            funcobj.shortname.module),
                common.edgedb_name_to_pg_name(funcobj.shortname.name))

    result = pgast.FuncCall(name=name, args=args)

    return result
Exemplo n.º 20
0
Arquivo: dml.py Projeto: virajs/edgedb
def init_dml_stmt(
        ir_stmt: irast.MutatingStmt, dml_stmt: pgast.DML, *,
        ctx: context.CompilerContextLevel,
        parent_ctx: context.CompilerContextLevel) \
        -> typing.Tuple[pgast.Query, pgast.CommonTableExpr,
                        pgast.CommonTableExpr]:
    """Prepare the common structure of the query representing a DML stmt.

    :param ir_stmt:
        IR of the statement.
    :param dml_stmt:
        SQL DML node instance.

    :return:
        A (*wrapper*, *dml_cte*, *range_cte*) tuple, where *wrapper* the
        the wrapping SQL statement, *dml_cte* is the CTE representing the
        SQL DML operation in the main relation of the Object, and
        *range_cte* is the CTE for the subset affected by the statement.
        *range_cte* is None for INSERT statmenets.
    """
    wrapper = ctx.rel

    clauses.init_stmt(ir_stmt, ctx, parent_ctx)

    target_ir_set = ir_stmt.subject

    dml_stmt.relation = dbobj.range_for_set(
        ir_stmt.subject, include_overlays=False, env=ctx.env)
    pathctx.put_path_value_rvar(
        dml_stmt, target_ir_set.path_id, dml_stmt.relation, env=ctx.env)
    dml_stmt.path_scope.add(target_ir_set.path_id)

    dml_cte = pgast.CommonTableExpr(
        query=dml_stmt,
        name=ctx.env.aliases.get(hint='m')
    )

    if isinstance(ir_stmt, (irast.UpdateStmt, irast.DeleteStmt)):
        # UPDATE and DELETE operate over a range, so generate
        # the corresponding CTE and connect it to the DML query.
        range_cte = get_dml_range(ir_stmt, dml_stmt, ctx=ctx)

        range_rvar = pgast.RangeVar(
            relation=range_cte,
            alias=pgast.Alias(
                aliasname=ctx.env.aliases.get(hint='range')
            )
        )

        relctx.pull_path_namespace(
            target=dml_stmt, source=range_rvar, ctx=ctx)

        # Auxillary relations are always joined via the WHERE
        # clause due to the structure of the UPDATE/DELETE SQL statments.
        id_col = common.edgedb_name_to_pg_name('std::id')
        dml_stmt.where_clause = astutils.new_binop(
            lexpr=pgast.ColumnRef(name=[
                dml_stmt.relation.alias.aliasname,
                id_col
            ]),
            op=ast.ops.EQ,
            rexpr=pathctx.get_rvar_path_identity_var(
                range_rvar, target_ir_set.path_id, env=ctx.env)
        )

        # UPDATE has "FROM", while DELETE has "USING".
        if hasattr(dml_stmt, 'from_clause'):
            dml_stmt.from_clause.append(range_rvar)
        else:
            dml_stmt.using_clause.append(range_rvar)

    else:
        range_cte = None

    # Due to the fact that DML statements are structured
    # as a flat list of CTEs instead of nested range vars,
    # the top level path scope must be empty.  The necessary
    # range vars will be injected explicitly in all rels that
    # need them.
    ctx.path_scope.clear()

    pathctx.put_path_value_rvar(
        dml_stmt, ir_stmt.subject.path_id, dml_stmt.relation, env=ctx.env)

    dml_rvar = pgast.RangeVar(
        relation=dml_cte,
        alias=pgast.Alias(aliasname=parent_ctx.env.aliases.get('d'))
    )

    relctx.include_rvar(wrapper, dml_rvar, ir_stmt.subject.path_id,
                        aspect='value', ctx=ctx)

    pathctx.put_path_bond(wrapper, ir_stmt.subject.path_id)

    return wrapper, dml_cte, dml_rvar, range_cte
Exemplo n.º 21
0
 def numbered_constraint_name(self, i, quote=True):
     raw_name = self.raw_constraint_name()
     name = common.edgedb_name_to_pg_name('{}#{}'.format(raw_name, i))
     return common.quote_ident(name) if quote else name
Exemplo n.º 22
0
 def get_trigger_procname(self):
     schema = common.edgedb_module_name_to_schema_name(
         self.schema_constraint_name().module)
     proc_name = common.edgedb_name_to_pg_name(
         self.raw_constraint_name() + '_trigproc')
     return schema, proc_name
Exemplo n.º 23
0
 def get_trigger_procname(self):
     schema = common.edgedb_module_name_to_schema_name(
         self.schema_constraint_name().module)
     proc_name = common.edgedb_name_to_pg_name(self.raw_constraint_name() +
                                               '_trigproc')
     return schema, proc_name
Exemplo n.º 24
0
 def numbered_constraint_name(self, i, quote=True):
     raw_name = self.raw_constraint_name()
     name = common.edgedb_name_to_pg_name('{}#{}'.format(raw_name, i))
     return common.quote_ident(name) if quote else name
Exemplo n.º 25
0
 def constraint_name(self, quote=True):
     name = self.raw_constraint_name()
     name = common.edgedb_name_to_pg_name(name)
     return common.quote_ident(name) if quote else name
Exemplo n.º 26
0
 def get(self, hint=None):
     alias = super().get(hint)
     return common.edgedb_name_to_pg_name(alias)
Exemplo n.º 27
0
def _new_mapped_pointer_rvar(
        ir_ptr: irast.Pointer,
        nullable: bool = False,
        *,
        ctx: context.CompilerContextLevel) -> pgast.BaseRangeVar:
    ptrcls = ir_ptr.ptrcls
    ptr_rvar = dbobj.range_for_pointer(ir_ptr, env=ctx.env)
    ptr_rvar.nullable = nullable
    # Set up references according to the link direction.
    if isinstance(ptrcls, s_links.Link):
        # XXX: fix this once Properties are Sources
        src_ptr_info = pg_types.get_pointer_storage_info(ptrcls.getptr(
            ctx.env.schema, 'std::source'),
                                                         resolve_type=False)
        src_col = src_ptr_info.column_name
    else:
        src_col = common.edgedb_name_to_pg_name('std::source')

    source_ref = dbobj.get_column(None, src_col)

    if isinstance(ptrcls, s_links.Link):
        # XXX: fix this once Properties are Sources
        tgt_ptr_info = pg_types.get_pointer_storage_info(ptrcls.getptr(
            ctx.env.schema, 'std::target'),
                                                         resolve_type=False)
        tgt_col = tgt_ptr_info.column_name
    else:
        tgt_col = common.edgedb_name_to_pg_name('std::target')

    target_ref = dbobj.get_column(None, tgt_col)

    if ir_ptr.direction == s_pointers.PointerDirection.Inbound:
        near_ref = target_ref
        far_ref = source_ref
    else:
        near_ref = source_ref
        far_ref = target_ref

    ptr_rvar.query.path_id = ir_ptr.target.path_id.ptr_path()
    ptr_rvar.path_scope.add(ptr_rvar.query.path_id)

    src_pid = ir_ptr.source.path_id
    ptr_rvar.path_scope.add(src_pid)
    pathctx.put_rvar_path_output(ptr_rvar,
                                 src_pid,
                                 aspect='identity',
                                 var=near_ref,
                                 env=ctx.env)

    tgt_pid = ir_ptr.target.path_id
    if tgt_pid.is_objtype_path():
        ptr_rvar.path_scope.add(tgt_pid)
        pathctx.put_rvar_path_output(ptr_rvar,
                                     tgt_pid,
                                     aspect='identity',
                                     var=far_ref,
                                     env=ctx.env)
    else:
        pathctx.put_rvar_path_output(ptr_rvar,
                                     tgt_pid,
                                     aspect='value',
                                     var=far_ref,
                                     env=ctx.env)

    return ptr_rvar
Exemplo n.º 28
0
Arquivo: dml.py Projeto: virajs/edgedb
def process_linkprop_update(ir_stmt: irast.MutatingStmt, ir_expr: irast.Base,
                            wrapper: pgast.Query,
                            dml_cte: pgast.CommonTableExpr, *,
                            ctx: context.CompilerContextLevel) -> None:
    """Perform link property updates to a link relation.

    :param ir_stmt:
        IR of the statement.
    :param ir_expr:
        IR of the UPDATE body element.
    :param wrapper:
        Top-level SQL query.
    :param dml_cte:
        CTE representing the SQL UPDATE to the main relation of the Object.
    """
    toplevel = ctx.toplevel_stmt

    rptr = ir_expr.rptr
    ptrcls = rptr.ptrcls
    target_is_scalar = isinstance(rptr.target, s_scalars.ScalarType)

    target_tab = dbobj.range_for_ptrcls(ptrcls,
                                        '>',
                                        include_overlays=False,
                                        env=ctx.env)

    if target_is_scalar:
        target_tab_name = (target_tab.schema, target_tab.name)
    else:
        target_tab_name = common.link_name_to_table_name(ptrcls.shortname,
                                                         catenate=False)

    tab_cols = \
        ctx.env.backend._type_mech.get_cached_table_columns(target_tab_name)

    assert tab_cols, "could not get cols for {!r}".format(target_tab_name)

    dml_cte_rvar = pgast.RangeVar(
        relation=dml_cte,
        alias=pgast.Alias(aliasname=ctx.env.aliases.get('m')))

    cond = astutils.new_binop(
        pathctx.get_rvar_path_identity_var(dml_cte_rvar,
                                           ir_stmt.subject.path_id,
                                           env=ctx.env),
        dbobj.get_column(target_tab, 'std::source'), ast.ops.EQ)

    targets = []
    for prop_el in ir_expr.shape:
        ptrname = prop_el.rptr.ptrcls.shortname
        with ctx.new() as input_rel_ctx:
            input_rel_ctx.expr_exposed = False
            input_rel = dispatch.compile(prop_el.expr, ctx=input_rel_ctx)
            targets.append(
                pgast.UpdateTarget(name=common.edgedb_name_to_pg_name(ptrname),
                                   val=input_rel))

    updstmt = pgast.UpdateStmt(relation=target_tab,
                               where_clause=cond,
                               targets=targets,
                               from_clause=[dml_cte_rvar])

    updcte = pgast.CommonTableExpr(query=updstmt,
                                   name=ctx.env.aliases.get(
                                       ptrcls.shortname.name))

    toplevel.ctes.append(updcte)
Exemplo n.º 29
0
 def constraint_name(self, quote=True):
     name = self.raw_constraint_name()
     name = common.edgedb_name_to_pg_name(name)
     return common.quote_ident(name) if quote else name
Exemplo n.º 30
0
 def get(self, hint=None):
     alias = super().get(hint)
     return common.edgedb_name_to_pg_name(alias)
Exemplo n.º 31
0
Arquivo: dml.py Projeto: virajs/edgedb
def init_dml_stmt(
        ir_stmt: irast.MutatingStmt, dml_stmt: pgast.DML, *,
        ctx: context.CompilerContextLevel,
        parent_ctx: context.CompilerContextLevel) \
        -> typing.Tuple[pgast.Query, pgast.CommonTableExpr,
                        pgast.CommonTableExpr]:
    """Prepare the common structure of the query representing a DML stmt.

    :param ir_stmt:
        IR of the statement.
    :param dml_stmt:
        SQL DML node instance.

    :return:
        A (*wrapper*, *dml_cte*, *range_cte*) tuple, where *wrapper* the
        the wrapping SQL statement, *dml_cte* is the CTE representing the
        SQL DML operation in the main relation of the Object, and
        *range_cte* is the CTE for the subset affected by the statement.
        *range_cte* is None for INSERT statmenets.
    """
    wrapper = ctx.rel

    clauses.init_stmt(ir_stmt, ctx, parent_ctx)

    target_ir_set = ir_stmt.subject

    dml_stmt.relation = dbobj.range_for_set(ir_stmt.subject,
                                            include_overlays=False,
                                            env=ctx.env)
    pathctx.put_path_value_rvar(dml_stmt,
                                target_ir_set.path_id,
                                dml_stmt.relation,
                                env=ctx.env)
    dml_stmt.path_scope.add(target_ir_set.path_id)

    dml_cte = pgast.CommonTableExpr(query=dml_stmt,
                                    name=ctx.env.aliases.get(hint='m'))

    if isinstance(ir_stmt, (irast.UpdateStmt, irast.DeleteStmt)):
        # UPDATE and DELETE operate over a range, so generate
        # the corresponding CTE and connect it to the DML query.
        range_cte = get_dml_range(ir_stmt, dml_stmt, ctx=ctx)

        range_rvar = pgast.RangeVar(
            relation=range_cte,
            alias=pgast.Alias(aliasname=ctx.env.aliases.get(hint='range')))

        relctx.pull_path_namespace(target=dml_stmt, source=range_rvar, ctx=ctx)

        # Auxillary relations are always joined via the WHERE
        # clause due to the structure of the UPDATE/DELETE SQL statments.
        id_col = common.edgedb_name_to_pg_name('std::id')
        dml_stmt.where_clause = astutils.new_binop(
            lexpr=pgast.ColumnRef(
                name=[dml_stmt.relation.alias.aliasname, id_col]),
            op=ast.ops.EQ,
            rexpr=pathctx.get_rvar_path_identity_var(range_rvar,
                                                     target_ir_set.path_id,
                                                     env=ctx.env))

        # UPDATE has "FROM", while DELETE has "USING".
        if hasattr(dml_stmt, 'from_clause'):
            dml_stmt.from_clause.append(range_rvar)
        else:
            dml_stmt.using_clause.append(range_rvar)

    else:
        range_cte = None

    # Due to the fact that DML statements are structured
    # as a flat list of CTEs instead of nested range vars,
    # the top level path scope must be empty.  The necessary
    # range vars will be injected explicitly in all rels that
    # need them.
    ctx.path_scope.clear()

    pathctx.put_path_value_rvar(dml_stmt,
                                ir_stmt.subject.path_id,
                                dml_stmt.relation,
                                env=ctx.env)

    dml_rvar = pgast.RangeVar(
        relation=dml_cte,
        alias=pgast.Alias(aliasname=parent_ctx.env.aliases.get('d')))

    relctx.include_rvar(wrapper,
                        dml_rvar,
                        ir_stmt.subject.path_id,
                        aspect='value',
                        ctx=ctx)

    pathctx.put_path_bond(wrapper, ir_stmt.subject.path_id)

    return wrapper, dml_cte, dml_rvar, range_cte
Exemplo n.º 32
0
Arquivo: dml.py Projeto: virajs/edgedb
def process_linkprop_update(
        ir_stmt: irast.MutatingStmt, ir_expr: irast.Base,
        wrapper: pgast.Query, dml_cte: pgast.CommonTableExpr, *,
        ctx: context.CompilerContextLevel) -> None:
    """Perform link property updates to a link relation.

    :param ir_stmt:
        IR of the statement.
    :param ir_expr:
        IR of the UPDATE body element.
    :param wrapper:
        Top-level SQL query.
    :param dml_cte:
        CTE representing the SQL UPDATE to the main relation of the Object.
    """
    toplevel = ctx.toplevel_stmt

    rptr = ir_expr.rptr
    ptrcls = rptr.ptrcls
    target_is_scalar = isinstance(rptr.target, s_scalars.ScalarType)

    target_tab = dbobj.range_for_ptrcls(
        ptrcls, '>', include_overlays=False, env=ctx.env)

    if target_is_scalar:
        target_tab_name = (target_tab.schema, target_tab.name)
    else:
        target_tab_name = common.link_name_to_table_name(
            ptrcls.shortname, catenate=False)

    tab_cols = \
        ctx.env.backend._type_mech.get_cached_table_columns(target_tab_name)

    assert tab_cols, "could not get cols for {!r}".format(target_tab_name)

    dml_cte_rvar = pgast.RangeVar(
        relation=dml_cte,
        alias=pgast.Alias(
            aliasname=ctx.env.aliases.get('m')
        )
    )

    cond = astutils.new_binop(
        pathctx.get_rvar_path_identity_var(
            dml_cte_rvar, ir_stmt.subject.path_id, env=ctx.env),
        dbobj.get_column(target_tab, 'std::source'),
        ast.ops.EQ
    )

    targets = []
    for prop_el in ir_expr.shape:
        ptrname = prop_el.rptr.ptrcls.shortname
        with ctx.new() as input_rel_ctx:
            input_rel_ctx.expr_exposed = False
            input_rel = dispatch.compile(prop_el.expr, ctx=input_rel_ctx)
            targets.append(
                pgast.UpdateTarget(
                    name=common.edgedb_name_to_pg_name(ptrname),
                    val=input_rel
                )
            )

    updstmt = pgast.UpdateStmt(
        relation=target_tab,
        where_clause=cond,
        targets=targets,
        from_clause=[dml_cte_rvar]
    )

    updcte = pgast.CommonTableExpr(
        query=updstmt,
        name=ctx.env.aliases.get(ptrcls.shortname.name)
    )

    toplevel.ctes.append(updcte)
Exemplo n.º 33
0
Arquivo: dml.py Projeto: virajs/edgedb
def process_link_values(ir_stmt,
                        ir_expr,
                        target_tab,
                        tab_cols,
                        col_data,
                        dml_rvar,
                        sources,
                        props_only,
                        target_is_scalar,
                        iterator_cte,
                        *,
                        ctx=context.CompilerContext) -> pgast.CommonTableExpr:
    """Unpack data from an update expression into a series of selects.

    :param ir_expr:
        IR of the INSERT/UPDATE body element.
    :param target_tab:
        The link table being updated.
    :param tab_cols:
        A sequence of columns in the table being updated.
    :param col_data:
        Expressions used to populate well-known columns of the link
        table such as std::source and std::__type__.
    :param sources:
        A list of relations which must be joined into the data query
        to resolve expressions in *col_data*.
    :param props_only:
        Whether this link update only touches link properties.
    :param target_is_scalar:
        Whether the link target is an ScalarType.
    :param iterator_cte:
        CTE representing the iterator range in the FOR clause of the
        EdgeQL DML statement.
    """
    with ctx.newscope() as newscope, newscope.newrel() as subrelctx:
        row_query = subrelctx.rel

        relctx.include_rvar(row_query, dml_rvar, ctx=subrelctx)
        subrelctx.path_scope[ir_stmt.subject.path_id] = row_query

        if iterator_cte is not None:
            iterator_rvar = dbobj.rvar_for_rel(iterator_cte,
                                               lateral=True,
                                               env=subrelctx.env)
            relctx.include_rvar(row_query,
                                iterator_rvar,
                                iterator_cte.query.path_id,
                                aspect='value',
                                ctx=subrelctx)

        with subrelctx.newscope() as sctx, sctx.subrel() as input_rel_ctx:
            input_rel = input_rel_ctx.rel
            if iterator_cte is not None:
                input_rel_ctx.path_scope[iterator_cte.query.path_id] = \
                    row_query
            input_rel_ctx.expr_exposed = False
            input_rel_ctx.shape_format = context.ShapeFormat.FLAT
            input_rel_ctx.volatility_ref = pathctx.get_path_identity_var(
                row_query, ir_stmt.subject.path_id, env=input_rel_ctx.env)
            dispatch.compile(ir_expr, ctx=input_rel_ctx)

    input_stmt = input_rel

    input_rvar = pgast.RangeSubselect(
        subquery=input_rel,
        lateral=True,
        alias=pgast.Alias(aliasname=ctx.env.aliases.get('val')))

    row = pgast.ImplicitRowExpr()

    source_data = {}

    if input_stmt.op is not None:
        # UNION
        input_stmt = input_stmt.rarg

    path_id = ir_expr.path_id

    output = pathctx.get_path_value_output(input_stmt, path_id, env=ctx.env)

    if isinstance(output, pgast.TupleVar):
        for element in output.elements:
            name = element.path_id.rptr_name()
            if name is None:
                name = element.path_id[-1].name
            colname = common.edgedb_name_to_pg_name(name)
            source_data.setdefault(colname,
                                   dbobj.get_column(input_rvar, element.name))
    else:
        if target_is_scalar:
            target_ref = pathctx.get_rvar_path_value_var(input_rvar,
                                                         path_id,
                                                         env=ctx.env)
        else:
            target_ref = pathctx.get_rvar_path_identity_var(input_rvar,
                                                            path_id,
                                                            env=ctx.env)

        source_data['std::target'] = target_ref

    if not target_is_scalar and 'std::target' not in source_data:
        target_ref = pathctx.get_rvar_path_identity_var(input_rvar,
                                                        path_id,
                                                        env=ctx.env)
        source_data['std::target'] = target_ref

    for col in tab_cols:
        expr = col_data.get(col)
        if expr is None:
            expr = source_data.get(col)

        if expr is None:
            if tab_cols[col]['column_default'] is not None:
                expr = pgast.LiteralExpr(expr=tab_cols[col]['column_default'])
            else:
                expr = pgast.Constant(val=None)

        row.args.append(expr)

    row_query.target_list = [
        pgast.ResTarget(val=pgast.Indirection(arg=pgast.TypeCast(
            arg=row, type_name=pgast.TypeName(name=target_tab)),
                                              indirection=[pgast.Star()]))
    ]

    row_query.from_clause += list(sources) + [input_rvar]

    link_rows = pgast.CommonTableExpr(query=row_query,
                                      name=ctx.env.aliases.get(hint='r'))

    return link_rows
Exemplo n.º 34
0
Arquivo: dml.py Projeto: virajs/edgedb
def process_link_values(
        ir_stmt, ir_expr, target_tab, tab_cols, col_data,
        dml_rvar, sources, props_only, target_is_scalar, iterator_cte, *,
        ctx=context.CompilerContext) -> pgast.CommonTableExpr:
    """Unpack data from an update expression into a series of selects.

    :param ir_expr:
        IR of the INSERT/UPDATE body element.
    :param target_tab:
        The link table being updated.
    :param tab_cols:
        A sequence of columns in the table being updated.
    :param col_data:
        Expressions used to populate well-known columns of the link
        table such as std::source and std::__type__.
    :param sources:
        A list of relations which must be joined into the data query
        to resolve expressions in *col_data*.
    :param props_only:
        Whether this link update only touches link properties.
    :param target_is_scalar:
        Whether the link target is an ScalarType.
    :param iterator_cte:
        CTE representing the iterator range in the FOR clause of the
        EdgeQL DML statement.
    """
    with ctx.newscope() as newscope, newscope.newrel() as subrelctx:
        row_query = subrelctx.rel

        relctx.include_rvar(row_query, dml_rvar, ctx=subrelctx)
        subrelctx.path_scope[ir_stmt.subject.path_id] = row_query

        if iterator_cte is not None:
            iterator_rvar = dbobj.rvar_for_rel(
                iterator_cte, lateral=True, env=subrelctx.env)
            relctx.include_rvar(row_query, iterator_rvar,
                                iterator_cte.query.path_id,
                                aspect='value', ctx=subrelctx)

        with subrelctx.newscope() as sctx, sctx.subrel() as input_rel_ctx:
            input_rel = input_rel_ctx.rel
            if iterator_cte is not None:
                input_rel_ctx.path_scope[iterator_cte.query.path_id] = \
                    row_query
            input_rel_ctx.expr_exposed = False
            input_rel_ctx.shape_format = context.ShapeFormat.FLAT
            input_rel_ctx.volatility_ref = pathctx.get_path_identity_var(
                row_query, ir_stmt.subject.path_id, env=input_rel_ctx.env)
            dispatch.compile(ir_expr, ctx=input_rel_ctx)

    input_stmt = input_rel

    input_rvar = pgast.RangeSubselect(
        subquery=input_rel,
        lateral=True,
        alias=pgast.Alias(
            aliasname=ctx.env.aliases.get('val')
        )
    )

    row = pgast.ImplicitRowExpr()

    source_data = {}

    if input_stmt.op is not None:
        # UNION
        input_stmt = input_stmt.rarg

    path_id = ir_expr.path_id

    output = pathctx.get_path_value_output(
        input_stmt, path_id, env=ctx.env)

    if isinstance(output, pgast.TupleVar):
        for element in output.elements:
            name = element.path_id.rptr_name()
            if name is None:
                name = element.path_id[-1].name
            colname = common.edgedb_name_to_pg_name(name)
            source_data.setdefault(
                colname, dbobj.get_column(input_rvar, element.name))
    else:
        if target_is_scalar:
            target_ref = pathctx.get_rvar_path_value_var(
                input_rvar, path_id, env=ctx.env)
        else:
            target_ref = pathctx.get_rvar_path_identity_var(
                input_rvar, path_id, env=ctx.env)

        source_data['std::target'] = target_ref

    if not target_is_scalar and 'std::target' not in source_data:
        target_ref = pathctx.get_rvar_path_identity_var(
            input_rvar, path_id, env=ctx.env)
        source_data['std::target'] = target_ref

    for col in tab_cols:
        expr = col_data.get(col)
        if expr is None:
            expr = source_data.get(col)

        if expr is None:
            if tab_cols[col]['column_default'] is not None:
                expr = pgast.LiteralExpr(
                    expr=tab_cols[col]['column_default'])
            else:
                expr = pgast.Constant(val=None)

        row.args.append(expr)

    row_query.target_list = [
        pgast.ResTarget(
            val=pgast.Indirection(
                arg=pgast.TypeCast(
                    arg=row,
                    type_name=pgast.TypeName(
                        name=target_tab
                    )
                ),
                indirection=[pgast.Star()]
            )
        )
    ]

    row_query.from_clause += list(sources) + [input_rvar]

    link_rows = pgast.CommonTableExpr(
        query=row_query,
        name=ctx.env.aliases.get(hint='r')
    )

    return link_rows