def compile_Tuple(expr: irast.Base, *, ctx: context.CompilerContextLevel) -> pgast.Base: ttype = _infer_type(expr, ctx=ctx) ttypes = ttype.element_types telems = list(ttypes) path_id = irast.PathId(ttype) elements = [] for i, e in enumerate(expr.elements): telem = telems[i] ttype = ttypes[telem] el_path_id = irutils.tuple_indirection_path_id(path_id, telem, ttype) val = dispatch.compile(e.val, ctx=ctx) elements.append(pgast.TupleElement(path_id=el_path_id, val=val)) result = pgast.TupleVar(elements=elements) return output.output_as_value(result, env=ctx.env)
def get_rvar_fieldref( rvar: typing.Optional[pgast.BaseRangeVar], colname: typing.Union[str, pgast.TupleVar], *, optional: bool=False, nullable: bool=None) \ -> typing.Union[pgast.ColumnRef, pgast.TupleVar]: if isinstance(colname, pgast.TupleVar): elements = [] for el in colname.elements: val = get_rvar_fieldref(rvar, el.name) elements.append( pgast.TupleElement(path_id=el.path_id, name=el.name, val=val)) fieldref = pgast.TupleVar(elements, named=colname.named) else: fieldref = get_column(rvar, colname, optional=optional, nullable=nullable) return fieldref
def process_insert_body(ir_stmt: irast.MutatingStmt, wrapper: pgast.Query, insert_cte: pgast.CommonTableExpr, insert_rvar: pgast.BaseRangeVar, *, ctx: context.CompilerContextLevel) -> None: """Generate SQL DML CTEs from an InsertStmt IR. :param ir_stmt: IR of the statement. :param wrapper: Top-level SQL query. :param insert_cte: CTE representing the SQL INSERT to the main relation of the Object. """ cols = [pgast.ColumnRef(name=['std::__type__'])] select = pgast.SelectStmt(target_list=[]) values = select.target_list # The main INSERT query of this statement will always be # present to insert at least the std::id and std::__type__ # links. insert_stmt = insert_cte.query insert_stmt.cols = cols insert_stmt.select_stmt = select if ir_stmt.parent_stmt is not None: iterator_set = ir_stmt.parent_stmt.iterator_stmt else: iterator_set = None if iterator_set is not None: with ctx.substmt() as ictx: ictx.path_scope = ictx.path_scope.new_child() ictx.path_scope[iterator_set.path_id] = ictx.rel clauses.compile_iterator_expr(ictx.rel, iterator_set, ctx=ictx) ictx.rel.path_id = iterator_set.path_id pathctx.put_path_bond(ictx.rel, iterator_set.path_id) iterator_cte = pgast.CommonTableExpr( query=ictx.rel, name=ctx.env.aliases.get('iter')) ictx.toplevel_stmt.ctes.append(iterator_cte) iterator_rvar = dbobj.rvar_for_rel(iterator_cte, env=ctx.env) relctx.include_rvar(select, iterator_rvar, path_id=ictx.rel.path_id, ctx=ctx) iterator_id = pathctx.get_path_identity_var(select, iterator_set.path_id, env=ctx.env) else: iterator_cte = None iterator_id = None values.append( pgast.ResTarget(val=pgast.SelectStmt( target_list=[pgast.ResTarget(val=pgast.ColumnRef(name=['id']))], from_clause=[ pgast.RangeVar(relation=pgast.Relation(name='objecttype', schemaname='edgedb')) ], where_clause=astutils.new_binop( op=ast.ops.EQ, lexpr=pgast.ColumnRef(name=['name']), rexpr=pgast.Constant(val=ir_stmt.subject.scls.shortname))))) external_inserts = [] tuple_elements = [] parent_link_props = [] with ctx.newrel() as subctx: subctx.rel = select subctx.rel_hierarchy[select] = insert_stmt subctx.expr_exposed = False subctx.shape_format = context.ShapeFormat.FLAT if iterator_cte is not None: subctx.path_scope = ctx.path_scope.new_child() subctx.path_scope[iterator_cte.query.path_id] = select # Process the Insert IR and separate links that go # into the main table from links that are inserted into # a separate link table. for shape_el in ir_stmt.subject.shape: rptr = shape_el.rptr ptrcls = rptr.ptrcls.material_type() if (ptrcls.is_link_property() and rptr.source.path_id != ir_stmt.subject.path_id): parent_link_props.append(shape_el) continue ptr_info = pg_types.get_pointer_storage_info( ptrcls, schema=subctx.env.schema, resolve_type=True, link_bias=False) props_only = False # First, process all local link inserts. if ptr_info.table_type == 'ObjectType': props_only = True field = pgast.ColumnRef(name=[ptr_info.column_name]) cols.append(field) insvalue = insert_value_for_shape_element(insert_stmt, wrapper, ir_stmt, shape_el, iterator_id, ptr_info=ptr_info, ctx=subctx) tuple_el = astutils.tuple_element_for_shape_el(shape_el, field) tuple_elements.append(tuple_el) values.append(pgast.ResTarget(val=insvalue)) ptr_info = pg_types.get_pointer_storage_info(ptrcls, resolve_type=False, link_bias=True) if ptr_info and ptr_info.table_type == 'link': external_inserts.append((shape_el, props_only)) if iterator_cte is not None: cols.append(pgast.ColumnRef(name=['__edb_token'])) values.append(pgast.ResTarget(val=iterator_id)) pathctx.put_path_identity_var(insert_stmt, iterator_set.path_id, cols[-1], force=True, env=subctx.env) pathctx.put_path_bond(insert_stmt, iterator_set.path_id) toplevel = ctx.toplevel_stmt toplevel.ctes.append(insert_cte) # Process necessary updates to the link tables. for shape_el, props_only in external_inserts: process_link_update(ir_stmt, shape_el, props_only, wrapper, insert_cte, iterator_cte, ctx=ctx) if parent_link_props: prop_elements = [] with ctx.newscope() as scopectx: scopectx.rel = wrapper for shape_el in parent_link_props: rptr = shape_el.rptr scopectx.path_scope[rptr.source.path_id] = wrapper pathctx.put_path_rvar_if_not_exists(wrapper, rptr.source.path_id, insert_rvar, aspect='value', env=scopectx.env) dispatch.compile(shape_el, ctx=scopectx) tuple_el = astutils.tuple_element_for_shape_el(shape_el, None) prop_elements.append(tuple_el) valtuple = pgast.TupleVar(elements=prop_elements, named=True) pathctx.put_path_value_var(wrapper, ir_stmt.subject.path_id, valtuple, force=True, env=ctx.env)
def _compile_shape(ir_set: irast.Set, shape: typing.List[irast.Set], *, ctx: context.CompilerContextLevel) -> pgast.TupleVar: elements = [] with ctx.newscope() as shapectx: shapectx.disable_semi_join.add(ir_set.path_id) shapectx.unique_paths.add(ir_set.path_id) for el in shape: rptr = el.rptr ptrcls = rptr.ptrcls ptrdir = rptr.direction or s_pointers.PointerDirection.Outbound is_singleton = ptrcls.singular(ptrdir) if (irutils.is_subquery_set(el) or isinstance(el.scls, s_objtypes.ObjectType) or not is_singleton or not ptrcls.required): wrapper = relgen.set_as_subquery(el, as_value=True, ctx=shapectx) if not is_singleton: value = relgen.set_to_array(ir_set=el, query=wrapper, ctx=shapectx) else: value = wrapper else: value = dispatch.compile(el, ctx=shapectx) elements.append(astutils.tuple_element_for_shape_el(el, value)) result = pgast.TupleVar(elements=elements, named=True) pathctx.put_path_value_var(ctx.rel, ir_set.path_id, result, force=True, env=ctx.env) for element in elements: # The ref might have already been added by the nested shape # processing, so add it conditionally. pathctx.put_path_value_var_if_not_exists(ctx.rel, element.path_id, element.val, env=ctx.env) if output.in_serialization_ctx(ctx): ser_elements = [] for el in elements: ser_val = pathctx.get_path_serialized_or_value_var(ctx.rel, el.path_id, env=ctx.env) ser_elements.append( pgast.TupleElement(path_id=el.path_id, name=el.name, val=ser_val)) ser_result = pgast.TupleVar(elements=ser_elements, named=True) sval = output.serialize_expr(ser_result, env=ctx.env) pathctx.put_path_serialized_var(ctx.rel, ir_set.path_id, sval, force=True, env=ctx.env) return result
def get_path_output(rel: pgast.BaseRelation, path_id: irast.PathId, *, aspect: str, ptr_info: typing.Optional[ pg_types.PointerStorageInfo] = None, env: context.Environment) -> pgast.OutputVar: view_path_id_map = getattr(rel, 'view_path_id_map', None) if view_path_id_map: path_id = map_path_id(path_id, view_path_id_map) result = rel.path_outputs.get((path_id, aspect)) if result is not None: return result if isinstance(rel, pgast.Relation): return _get_rel_path_output(rel, path_id, aspect=aspect, ptr_info=ptr_info, env=env) else: ref = get_path_var(rel, path_id, aspect=aspect, env=env) other_output = find_path_output(rel, path_id, ref, env=env) if other_output is not None: rel.path_outputs[path_id, aspect] = other_output return other_output if isinstance(ref, pgast.TupleVar): elements = [] for el in ref.elements: el_path_id = reverse_map_path_id(el.path_id, rel.view_path_id_map) element = get_path_output(rel, el_path_id, aspect=aspect, env=env) elements.append( pgast.TupleElement(path_id=el_path_id, name=element)) result = pgast.TupleVar(elements=elements, named=ref.named) else: if astutils.is_set_op_query(rel): assert isinstance(ref, pgast.ColumnRef) result = dbobj.get_column(None, ref) else: alias = get_path_output_alias(path_id, aspect, env=env) restarget = pgast.ResTarget(name=alias, val=ref) if hasattr(rel, 'returning_list'): rel.returning_list.append(restarget) else: rel.target_list.append(restarget) if isinstance(ref, pgast.ColumnRef): nullable = ref.nullable optional = ref.optional else: nullable = rel.nullable optional = None result = pgast.ColumnRef(name=[alias], nullable=nullable, optional=optional) rel.path_outputs[path_id, aspect] = result return result