def _inject_tname( insert_stmt: qlast.InsertQuery, *, ctx: context.ContextLevel) -> None: for el in insert_stmt.shape: if isinstance(el.compexpr, qlast.InsertQuery): _inject_tname(el.compexpr, ctx=ctx) assert isinstance(insert_stmt.subject.steps[0], qlast.BaseObjectRef) insert_stmt.shape.append( qlast.ShapeElement( expr=qlast.Path( steps=[qlast.Ptr(ptr=qlast.ObjectRef(name='_tname'))], ), compexpr=qlast.Path( steps=[ qlast.Introspect( type=qlast.TypeName( maintype=insert_stmt.subject.steps[0], ), ), qlast.Ptr(ptr=qlast.ObjectRef(name='name')), ], ), ), )
def visit_order(self, node): if not isinstance(node, gql_ast.ObjectValue): raise g_errors.GraphQLTranslationError( f'an object is expected for "order"') # if there is no specific ordering, then order by id if not node.fields: return [ qlast.SortExpr( path=qlast.Path( steps=[qlast.Ptr(ptr=qlast.ObjectRef(name='id'))], partial=True, ), direction=qlast.SortAsc, ) ] # Ordering is handled by specifying a list of special Ordering objects. # Validation is already handled by this point. orderby = [] for enum in node.fields: name, direction, nulls = self._visit_order_item(enum) orderby.append( qlast.SortExpr( path=qlast.Path( steps=[qlast.Ptr(ptr=qlast.ObjectRef(name=name))], partial=True, ), direction=direction, nones_order=nulls, )) return orderby
def compile_coalesce_insert(left: qlast.Expr, right: qlast.InsertQuery, ctx: context.ContextLevel) -> irast.Set: # This maybe could have been implemented with less code by # modifying compile_operator directly, but all of those approaches # seemed to require some spaghetti code or adding dead-drop state # in context. with ctx.newscope() as lctx: lir = setgen.ensure_set(dispatch.compile(left, ctx=lctx), ctx=lctx) lir = setgen.scoped_set(setgen.ensure_stmt(lir, ctx=lctx), ctx=lctx) with ctx.newscope() as rctx: rir = setgen.ensure_set(stmt.compile_InsertQuery(right, ctx=rctx, conditioned_on=lir), ctx=rctx) rir = setgen.scoped_set(setgen.ensure_stmt(rir, ctx=rctx), ctx=rctx) with ctx.new() as subctx: subctx.anchors = subctx.anchors.copy() l_alias = subctx.aliases.get('l') subctx.anchors[l_alias] = lir r_alias = subctx.aliases.get('r') subctx.anchors[r_alias] = rir rpath = qlast.Path(steps=[qlast.ObjectRef(name=r_alias)]) lpath = qlast.Path(steps=[qlast.ObjectRef(name=l_alias)]) # Only one side of the the ?? will possibly be non-empty, so # we just union them together. e = qlast.BinOp(op='UNION', left=lpath, right=rpath) return setgen.ensure_set(dispatch.compile(e, ctx=subctx), ctx=subctx)
def get_config_type_shape( schema: s_schema.Schema, stype: s_objtypes.ObjectType, path: List[qlast.Base], ) -> List[qlast.ShapeElement]: from . import objtypes as s_objtypes shape = [] seen: Set[str] = set() stypes = [stype] + list(stype.descendants(schema)) for t in stypes: t_name = t.get_name(schema) for unqual_pn, p in t.get_pointers(schema).items(schema): pn = str(unqual_pn) if pn in ('id', '__type__') or pn in seen: continue elem_path: List[qlast.Base] = [] if t != stype: elem_path.append( qlast.TypeIntersection(type=qlast.TypeName( maintype=qlast.ObjectRef( module=t_name.module, name=t_name.name, ), ), ), ) elem_path.append(qlast.Ptr(ptr=qlast.ObjectRef(name=pn))) ptype = p.get_target(schema) assert ptype is not None if isinstance(ptype, s_objtypes.ObjectType): subshape = get_config_type_shape(schema, ptype, path + elem_path) subshape.append( qlast.ShapeElement( expr=qlast.Path(steps=[ qlast.Ptr(ptr=qlast.ObjectRef(name='_tname'), ), ], ), compexpr=qlast.Path(steps=path + elem_path + [ qlast.Ptr(ptr=qlast.ObjectRef(name='__type__')), qlast.Ptr(ptr=qlast.ObjectRef(name='name')), ], ), ), ) else: subshape = [] shape.append( qlast.ShapeElement( expr=qlast.Path(steps=elem_path), elements=subshape, ), ) seen.add(pn) return shape
def extend_path(expr: qlast.Expr, field: str) -> qlast.Path: step = qlast.Ptr(ptr=qlast.ObjectRef(name=field)) if isinstance(expr, qlast.Path): return qlast.Path( steps=[*expr.steps, step], partial=expr.partial, ) else: return qlast.Path(steps=[expr, step])
def _inline_type_computable( ir_set: irast.Set, stype: s_objtypes.ObjectType, compname: str, propname: str, *, shape_ptrs: List[ShapePtr], ctx: context.ContextLevel, ) -> None: assert isinstance(stype, s_objtypes.ObjectType) ptr: Optional[s_pointers.Pointer] try: ptr = setgen.resolve_ptr(stype, compname, track_ref=None, ctx=ctx) # The pointer might exist on the base type. That doesn't count, # and we need to re-inject it. if not ptr.get_computable(ctx.env.schema): ptr = None except errors.InvalidReferenceError: ptr = None if ptr is None: ql = qlast.ShapeElement( expr=qlast.Path( steps=[qlast.Ptr( ptr=qlast.ObjectRef(name=compname), direction=s_pointers.PointerDirection.Outbound, )], ), compexpr=qlast.Path( steps=[ qlast.Source(), qlast.Ptr( ptr=qlast.ObjectRef(name='__type__'), direction=s_pointers.PointerDirection.Outbound, ), qlast.Ptr( ptr=qlast.ObjectRef(name=propname), direction=s_pointers.PointerDirection.Outbound, ) ] ) ) with ctx.newscope(fenced=True) as scopectx: scopectx.anchors = scopectx.anchors.copy() scopectx.anchors[qlast.Source().name] = ir_set ptr = _normalize_view_ptr_expr( ql, stype, path_id=ir_set.path_id, ctx=scopectx) view_shape = ctx.env.view_shapes[stype] view_shape_ptrs = {p for p, _ in view_shape} if ptr not in view_shape_ptrs: view_shape.insert(0, (ptr, qlast.ShapeOp.ASSIGN)) shape_ptrs.insert(0, (ir_set, ptr, qlast.ShapeOp.ASSIGN))
def get_config_type_shape(schema, stype, path) -> typing.List[qlast.ShapeElement]: shape = [] seen = set() stypes = [stype] + list(stype.descendants(schema)) for t in stypes: t_name = t.get_name(schema) for pn, p in t.get_pointers(schema).items(schema): if pn in ('id', '__type__') or pn in seen: continue elem_path = [] if t is not stype: elem_path.append( qlast.TypeIndirection(type=qlast.TypeName( maintype=qlast.ObjectRef( module=t_name.module, name=t_name.name, ), ), ), ) elem_path.append(qlast.Ptr(ptr=qlast.ObjectRef(name=pn))) ptype = p.get_target(schema) if ptype.is_object_type(): subshape = get_config_type_shape(schema, ptype, path + elem_path) subshape.append( qlast.ShapeElement( expr=qlast.Path(steps=[ qlast.Ptr(ptr=qlast.ObjectRef(name='_tname'), ), ], ), compexpr=qlast.Path(steps=path + elem_path + [ qlast.Ptr(ptr=qlast.ObjectRef(name='__type__')), qlast.Ptr(ptr=qlast.ObjectRef(name='name')), ], ), ), ) else: subshape = [] shape.append( qlast.ShapeElement( expr=qlast.Path(steps=elem_path), elements=subshape, ), ) seen.add(pn) return shape
def get_param_anchors_for_callable( params: s_func.ParameterLikeList, schema: s_schema.Schema, *, inlined_defaults: bool, ) -> Tuple[Dict[str, irast.Parameter], List[qlast.AliasedExpr], ]: anchors = {} aliases = [] if inlined_defaults: anchors['__defaults_mask__'] = irast.Parameter( name='__defaults_mask__', typeref=irtyputils.type_to_typeref( # note: no cache schema, cast(s_scalars.ScalarType, schema.get('std::bytes')), ), ) pg_params = s_func.PgParams.from_params(schema, params) for pi, p in enumerate(pg_params.params): p_shortname = p.get_shortname(schema) anchors[p_shortname] = irast.Parameter( name=p_shortname, typeref=irtyputils.type_to_typeref(schema, p.get_type(schema))) if p.get_default(schema) is None: continue if not inlined_defaults: continue aliases.append( qlast.AliasedExpr( alias=p_shortname, expr=qlast. IfElse(condition=qlast.BinOp(left=qlast.FunctionCall( func=('std', 'bytes_get_bit'), args=[ qlast.Path( steps=[qlast.ObjectRef(name='__defaults_mask__')]), 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))))) return anchors, aliases
def _cast_array(ir_set: irast.Set, orig_stype: s_types.Type, new_stype: s_types.Type, *, srcctx: parsing.ParserContext, ctx: context.ContextLevel) -> irast.Base: direct_cast = _find_cast(orig_stype, new_stype, srcctx=srcctx, ctx=ctx) if direct_cast is None: if not new_stype.is_array(): raise errors.QueryError( f'cannot cast {orig_stype.get_displayname(ctx.env.schema)!r} ' f'to {new_stype.get_displayname(ctx.env.schema)!r}', context=srcctx) el_type = new_stype.get_subtypes(ctx.env.schema)[0] else: el_type = new_stype orig_el_type = orig_stype.get_subtypes(ctx.env.schema)[0] el_cast = _find_cast(orig_el_type, el_type, srcctx=srcctx, ctx=ctx) if el_cast is not None and el_cast.get_from_cast(ctx.env.schema): # Simple cast return _cast_to_ir(ir_set, el_cast, orig_stype, new_stype, ctx=ctx) else: pathctx.register_set_in_scope(ir_set, ctx=ctx) with ctx.new() as subctx: subctx.anchors = subctx.anchors.copy() source_alias = subctx.aliases.get('a') subctx.anchors[source_alias] = ir_set unpacked = qlast.FunctionCall( func=('std', 'array_unpack'), args=[ qlast.Path(steps=[qlast.ObjectRef(name=source_alias)], ), ], ) elements = qlast.FunctionCall( func=('std', 'array_agg'), args=[ qlast.TypeCast( expr=unpacked, type=typegen.type_to_ql_typeref(el_type, ctx=subctx), ), ], ) array_ir = dispatch.compile(elements, ctx=subctx) if direct_cast is not None: array_stype = s_types.Array.from_subtypes( ctx.env.schema, [el_type]) return _cast_to_ir(array_ir, direct_cast, array_stype, new_stype, ctx=ctx) else: return array_ir
def reduce_Expr_PathStep(self, *kids): path = kids[0].val if not isinstance(path, qlast.Path): path = qlast.Path(steps=[path]) path.steps.append(kids[1].val) self.val = path
def new_set( *, stype: s_types.Type, ctx: context.ContextLevel, ircls: Type[irast.Set] = irast.Set, **kwargs: Any, ) -> irast.Set: """Create a new ir.Set instance with given attributes. Absolutely all ir.Set instances must be created using this constructor. """ if (stype not in ctx.type_rewrites and isinstance(stype, s_objtypes.ObjectType) and ctx.env.options.apply_query_rewrites and (filters := stype.get_access_policy_filters(ctx.env.schema))): qry = qlast.SelectQuery(result=qlast.Path( steps=[s_utils.name_to_ast_ref(stype.get_name(ctx.env.schema))]), ) for f in filters: assert isinstance(f.qlast, qlast.Expr) qry.where = astutils.extend_binop(qry.where, f.qlast) with ctx.detached() as subctx: subctx.expr_exposed = False # This is a global rewrite operation that is done once # per type, and so we don't really care if we're in a # temporary scope or not. subctx.path_scope = subctx.env.path_scope.root subctx.in_temp_scope = False # Put a placeholder to prevent recursion. subctx.type_rewrites[stype] = irast.Set() filtered_set = dispatch.compile(qry, ctx=subctx) assert isinstance(filtered_set, irast.Set) subctx.type_rewrites[stype] = filtered_set
def reduce_PathStepName(self, *kids): from edb.schema import pointers as s_pointers self.val = qlast.Path(steps=[ qlast.Ptr(ptr=kids[0].val, direction=s_pointers.PointerDirection.Outbound) ])
def reduce_NodeName_OptShape(self, *kids): self.val = qlast.Shape(expr=qlast.Path(steps=[ qlast.ObjectRef(name=kids[0].val.name, module=kids[0].val.module, context=kids[0].context) ]), elements=kids[1].val)
def _visit_query(self, node): # populate input variables with defaults, where applicable if node.variable_definitions: self.visit(node.variable_definitions) # base Query needs to be configured specially base = self._context.gqlcore.get('Query') # special treatment of the selection_set, different from inner # recursion query = qlast.SelectQuery( result=qlast.Shape( expr=qlast.Path( steps=[qlast.ObjectRef(name='Query', module='stdgraphql')] ), elements=[] ), limit=qlast.IntegerConstant(value='1') ) self._context.fields.append({}) self._context.path.append([Step(None, base)]) query.result.elements = self.visit(node.selection_set) self._context.fields.pop() self._context.path.pop() return query
def nullify_expr_field(self, schema, context, field, op): from edb.edgeql.compiler import astutils as qlastutils if field.name == 'expr': base = self.get_attribute_value('bases').first(schema) if base.is_object_type(): base_name = base.get_name(schema) ql = qlast.SelectQuery( result=qlast.Path(steps=[ qlast.ObjectRef( name=base_name.name, module=base_name.module, ), ], ), where=qlast.BooleanConstant(value='false'), ) else: ql = qlast.TypeCast( expr=qlast.Set(), type=qlastutils.type_to_ql_typeref(base, schema=schema), ) op.new_value = s_expr.Expression.compiled( s_expr.Expression.from_ast(ql, schema=schema, modaliases=context.modaliases), schema=schema, ) return True else: super().nullify_expr_field(schema, context, field, op)
def compile_ConfigInsert( expr: qlast.ConfigInsert, *, ctx: context.ContextLevel) -> irast.Set: info = _validate_op(expr, ctx=ctx) if not expr.system: raise errors.UnsupportedFeatureError( f'CONFIGURE SESSION INSERT is not supported' ) level = 'SYSTEM' if expr.system else 'SESSION' subject = ctx.env.get_track_schema_object( f'cfg::{expr.name.name}', default=None) if subject is None: raise errors.ConfigurationError( f'{expr.name.name!r} is not a valid configuration item', context=expr.context, ) insert_stmt = qlast.InsertQuery( subject=qlast.Path( steps=[ qlast.ObjectRef( name=expr.name.name, module='cfg', ) ] ), shape=expr.shape, ) for el in expr.shape: if isinstance(el.compexpr, qlast.InsertQuery): _inject_tname(el.compexpr, ctx=ctx) with ctx.newscope() as subctx: subctx.expr_exposed = True subctx.modaliases = ctx.modaliases.copy() subctx.modaliases[None] = 'cfg' subctx.special_computables_in_mutation_shape |= {'_tname'} insert_ir = dispatch.compile(insert_stmt, ctx=subctx) insert_ir_set = setgen.ensure_set(insert_ir, ctx=subctx) assert isinstance(insert_ir_set.expr, irast.InsertStmt) insert_subject = insert_ir_set.expr.subject _validate_config_object(insert_subject, level=level, ctx=subctx) return setgen.ensure_set( irast.ConfigInsert( name=info.param_name, cardinality=info.cardinality, system=expr.system, requires_restart=info.requires_restart, backend_setting=info.backend_setting, expr=insert_subject, context=expr.context, ), ctx=ctx, )
def reduce_ShapePathPtr_DOT_PathStepName(self, *kids): from edb.schema import pointers as s_pointers self.val = qlast.Path(steps=[ qlast.TypeIndirection(type=kids[0].val, ), qlast.Ptr(ptr=kids[2].val, direction=s_pointers.PointerDirection.Outbound), ])
def reduce_Expr_DOT_FCONST(self, *kids): # this is a valid link-like syntax for accessing unnamed tuples path = kids[0].val if not isinstance(path, qlast.Path): path = qlast.Path(steps=[path]) path.steps.extend(self._float_to_path(kids[2], kids[1].context)) self.val = path
def visit_TypeRef(self, node): # Bare TypeRef only appears as rhs of IS [NOT] and is always # an object type reference. mtn = node.name_hint result = qlast.Path( steps=[qlast.ObjectRef(module=mtn.module, name=mtn.name)]) return result
def graft(prefix: Optional[qlast.Path], new: qlast.Path, always_partial: bool = False) -> qlast.Path: if new.partial or always_partial: assert prefix is not None return qlast.Path(steps=prefix.steps + new.steps, partial=prefix.partial) else: return new
def update_path(prefix: Optional[qlast.Path], query: Optional[qlast.Expr]) -> Optional[qlast.Path]: if query is None: return None elif isinstance(query, qlast.ReturningMixin): if query.result_alias is not None: return qlast.Path(steps=[qlast.ObjectRef(name=query.result_alias)]) else: query = query.result while isinstance(query, qlast.Shape): query = query.expr if isinstance(query, qlast.Path): return graft(prefix, query) else: # XXX: synthesize a real prefix name? return qlast.Path(partial=True, steps=[])
def reduce_AT_ShortNodeName(self, *kids): self.val = qlast.Path( steps=[ qlast.Ptr( ptr=kids[1].val, type='property' ) ] )
def trace_GroupingAtom(node: qlast.GroupingAtom, *, ctx: TracerContext) -> None: if isinstance(node, qlast.ObjectRef): trace(qlast.Path(steps=[node]), ctx=ctx) elif isinstance(node, qlast.Path): trace(node, ctx=ctx) else: for el in node.elements: trace_GroupingAtom(el, ctx=ctx)
def compile_GlobalExpr( expr: qlast.GlobalExpr, *, ctx: context.ContextLevel) -> irast.Set: glob = ctx.env.get_track_schema_object( s_utils.ast_ref_to_name(expr.name), expr.name, modaliases=ctx.modaliases, type=s_globals.Global) assert isinstance(glob, s_globals.Global) if glob.is_computable(ctx.env.schema): obj_ref = s_utils.name_to_ast_ref( glob.get_target(ctx.env.schema).get_name(ctx.env.schema)) return dispatch.compile(qlast.Path(steps=[obj_ref]), ctx=ctx) objctx = ctx.env.options.schema_object_context if objctx in (s_constr.Constraint, s_indexes.Index): typname = objctx.get_schema_class_displayname() raise errors.SchemaDefinitionError( f'global variables cannot be referenced from {typname}', context=expr.context) default = glob.get_default(ctx.env.schema) param_set: qlast.Expr | irast.Set present_set: qlast.Expr | irast.Set | None if ctx.env.options.func_params is None: param_set, present_set = setgen.get_global_param_sets(glob, ctx=ctx) else: param_set, present_set = setgen.get_func_global_param_sets( glob, ctx=ctx) if default and not present_set: # If we have a default value and the global is required, # then we can use the param being {} as a signal to use # the default. with ctx.new() as subctx: subctx.anchors = subctx.anchors.copy() main_param = subctx.maybe_create_anchor(param_set, 'glob') param_set = func.compile_operator( expr, op_name='std::??', qlargs=[main_param, default.qlast], ctx=subctx) elif default and present_set: # ... but if {} is a valid value for the global, we need to # stick in an extra parameter to indicate whether to use # the default. with ctx.new() as subctx: subctx.anchors = subctx.anchors.copy() main_param = subctx.maybe_create_anchor(param_set, 'glob') present_param = subctx.maybe_create_anchor(present_set, 'present') param_set = func.compile_operator( expr, op_name='std::IF', qlargs=[main_param, present_param, default.qlast], ctx=subctx) elif not isinstance(param_set, irast.Set): param_set = dispatch.compile(param_set, ctx=ctx) return param_set
def visit_ObjectField(self, node): fname = node.name.value # handle boolean ops if fname == 'and': return self._visit_list_of_inputs(node.value, 'AND') elif fname == 'or': return self._visit_list_of_inputs(node.value, 'OR') elif fname == 'not': return qlast.UnaryOp(op='NOT', operand=self.visit(node.value)) # handle various scalar ops op = gt.GQL_TO_OPS_MAP.get(fname) if op: value = self.visit(node.value) return qlast.BinOp(left=self._context.filter, op=op, right=value) # we're at the beginning of a scalar op _, target = self._get_parent_and_current_type() name = self.get_path_prefix() name.append(qlast.Ptr(ptr=qlast.ObjectRef(name=fname))) name = qlast.Path(steps=name) ftype = target.get_field_type(fname) typename = ftype.name if typename not in {'std::str', 'std::uuid'}: gql_type = gt.EDB_TO_GQL_SCALARS_MAP.get(typename) if gql_type == graphql.GraphQLString: # potentially need to cast the 'name' side into a # <str>, so as to be compatible with the 'value' name = qlast.TypeCast( expr=name, type=qlast.TypeName(maintype=qlast.ObjectRef(name='str')), ) self._context.filter = name value = self.visit(node.value) # we need to cast a target string into <uuid> or enum if typename == 'std::uuid' and not isinstance(value.right, qlast.TypeCast): value.right = qlast.TypeCast( expr=value.right, type=qlast.TypeName(maintype=qlast.ObjectRef(name='uuid')), ) elif ftype.is_enum(): value.right = qlast.TypeCast( expr=value.right, type=qlast.TypeName(maintype=qlast.ObjectRef(name=ftype.name)), ) return value
def reduce_PathStepName_OptTypeIntersection(self, *kids): from edb.schema import pointers as s_pointers steps = [ qlast.Ptr(ptr=kids[0].val, direction=s_pointers.PointerDirection.Outbound), ] if kids[1].val is not None: steps.append(kids[1].val) self.val = qlast.Path(steps=steps)
def make_free_object(els: Dict[str, qlast.Expr]) -> qlast.Shape: return qlast.Shape( expr=None, elements=[ qlast.ShapeElement( expr=qlast.Path( steps=[qlast.Ptr(ptr=qlast.ObjectRef(name=name))]), compexpr=expr ) for name, expr in els.items() ], )
def _apply_field_ast( self, schema: s_schema.Schema, context: sd.CommandContext, node: qlast.DDLOperation, op: sd.AlterObjectProperty, ) -> None: objtype = self.get_referrer_context(context) if op.property == 'target' and objtype: # Due to how SDL is processed the underlying AST may be an # AlterConcreteLink, which requires different handling. if isinstance(node, qlast.CreateConcreteLink): if not node.target: expr = self.get_attribute_value('expr') if expr is not None: node.target = expr.qlast else: t = op.new_value assert isinstance(t, (so.Object, so.ObjectShell)) node.target = utils.typeref_to_ast(schema, t) else: assert isinstance(op.new_value, (so.Object, so.ObjectShell)) top_op = self.get_top_referrer_op(context) conv_expr: Optional[qlast.Expr] if (top_op is not None and (isinstance(top_op, sd.CreateObject) or (top_op.orig_cmd_type is not None and issubclass(top_op.orig_cmd_type, sd.CreateObject)))): # This op is part of CREATE TYPE, so avoid tripping up # the DDL check on SET TYPE by generating an appropriate # conversion expression: USING (.foo[IS Type]). lname = sn.shortname_from_fullname(self.classname).name conv_expr = qlast.Path( partial=True, steps=[ qlast.Ptr(ptr=qlast.ObjectRef(name=lname)), qlast.TypeIntersection(type=utils.typeref_to_ast( schema, op.new_value)) ], ) else: conv_expr = None node.commands.append( qlast.SetPointerType( value=utils.typeref_to_ast(schema, op.new_value), expr=conv_expr, )) elif op.property == 'on_target_delete': node.commands.append(qlast.OnTargetDelete(cascade=op.new_value)) else: super()._apply_field_ast(schema, context, node, op)
def generate_config_query(schema) -> str: cfg = schema.get('cfg::Config') ref = qlast.ObjectRef(name='Config', module='cfg') query = qlast.SelectQuery( result=qlast.Shape( expr=qlast.Path(steps=[ref]), elements=qlcompiler.get_config_type_shape(schema, cfg, path=[ref]), ), limit=qlast.IntegerConstant(value='1', ), ) return qlcodegen.generate_source(query)
def get_param_anchors_for_callable(params, schema): anchors = {} aliases = [] anchors['__defaults_mask__'] = irast.Parameter( name='__defaults_mask__', typeref=irtyputils.type_to_typeref(schema, schema.get('std::bytes'))) pg_params = s_func.PgParams.from_params(schema, params) for pi, p in enumerate(pg_params.params): p_shortname = p.get_shortname(schema) anchors[p_shortname] = irast.Parameter( name=p_shortname, typeref=irtyputils.type_to_typeref(schema, p.get_type(schema))) if p.get_default(schema) is None: continue aliases.append( qlast.AliasedExpr( alias=p_shortname, expr=qlast. IfElse(condition=qlast.BinOp(left=qlast.FunctionCall( func=('std', 'bytes_get_bit'), args=[ qlast.Path( steps=[qlast.ObjectRef(name='__defaults_mask__')]), 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))))) return anchors, aliases