def compile_SliceIndirection( expr: irast.SliceIndirection, *, ctx: context.CompilerContextLevel) -> pgast.BaseExpr: # Handle Expr[Index], where Expr may be std::str, array<T> or # std::json. For strings we translate this into substr calls. # Arrays use the native slice syntax. JSON is handled by a # combination of unnesting aggregation and array slicing. with ctx.new() as subctx: subctx.expr_exposed = False subj = dispatch.compile(expr.expr, ctx=subctx) if expr.start is None: start = pgast.NullConstant() else: start = dispatch.compile(expr.start, ctx=subctx) if expr.stop is None: stop = pgast.NullConstant() else: stop = dispatch.compile(expr.stop, ctx=subctx) result = pgast.FuncCall( name=('edgedb', '_slice'), args=[subj, start, stop] ) return result
def get_path_output_or_null( rel: pgast.Query, path_id: irast.PathId, *, aspect: str, env: context.Environment) -> \ typing.Tuple[pgast.OutputVar, bool]: path_id = map_path_id(path_id, rel.view_path_id_map) ref = maybe_get_path_output(rel, path_id, aspect=aspect, env=env) if ref is not None: return ref, False alt_aspect = get_less_specific_aspect(path_id, aspect) if alt_aspect is not None: ref = maybe_get_path_output(rel, path_id, aspect=alt_aspect, env=env) if ref is not None: _put_path_output_var(rel, path_id, aspect, ref, env=env) return ref, False alias = env.aliases.get('null') restarget = pgast.ResTarget(name=alias, val=pgast.NullConstant()) rel.target_list.append(restarget) ref = pgast.ColumnRef(name=[alias], nullable=True) _put_path_output_var(rel, path_id, aspect, ref, env=env) return ref, True
def _get_rel_object_id_output(rel: pgast.BaseRelation, path_id: irast.PathId, *, aspect: str, ptr_info: typing.Optional[ pg_types.PointerStorageInfo] = None, env: context.Environment) -> pgast.OutputVar: var = rel.path_outputs.get((path_id, aspect)) if var is not None: return var if isinstance(rel, pgast.NullRelation): name = env.aliases.get('id') val = pgast.TypeCast(arg=pgast.NullConstant(), type_name=pgast.TypeName(name=('uuid', ), )) rel.target_list.append(pgast.ResTarget(name=name, val=val)) result = pgast.ColumnRef(name=[name], nullable=True) else: result = pgast.ColumnRef(name=['id'], nullable=False) _put_path_output_var(rel, path_id, aspect, result, env=env) return result
def _compile_set_in_singleton_mode( node: irast.Set, *, ctx: context.CompilerContextLevel) -> pgast.BaseExpr: if isinstance(node, irast.EmptySet): return pgast.NullConstant() elif node.expr is not None: return dispatch.compile(node.expr, ctx=ctx) else: if node.rptr: ptrref = node.rptr.ptrref source = node.rptr.source if ptrref.parent_ptr is None and source.rptr is not None: raise RuntimeError('unexpectedly long path in simple expr') ptr_stor_info = pg_types.get_ptrref_storage_info( ptrref, resolve_type=False) colref = pgast.ColumnRef(name=[ptr_stor_info.column_name]) elif irtyputils.is_scalar(node.typeref): colref = pgast.ColumnRef( name=[common.edgedb_name_to_pg_name(str(node.typeref.id))]) else: colref = pgast.ColumnRef( name=[common.edgedb_name_to_pg_name(str(node.typeref.id))]) return colref
def named_tuple_as_json_object(expr, *, styperef, env): keyvals = [] for el_idx, el_type in enumerate(styperef.subtypes): keyvals.append(pgast.StringConstant(val=el_type.element_name)) type_sentinel = pgast.TypeCast( arg=pgast.NullConstant(), type_name=pgast.TypeName( name=pgtypes.pg_type_from_ir_typeref(el_type) ) ) val = pgast.FuncCall( name=('edgedb', 'row_getattr_by_num'), args=[ expr, pgast.NumericConstant(val=str(el_idx + 1)), type_sentinel ]) if irtyputils.is_collection(el_type): val = coll_as_json_object(val, styperef=el_type, env=env) keyvals.append(val) return pgast.FuncCall( name=_get_json_func('build_object', env=env), args=keyvals, null_safe=True, ser_safe=True, nullable=expr.nullable)
def unnamed_tuple_as_json_object(expr, *, styperef, env): has_colls = any(irtyputils.is_collection(st) for st in styperef.subtypes) if not has_colls: # No nested collections, take the fast path. return pgast.FuncCall( name=('edgedb',) + _get_json_func('row_to_array', env=env), args=[expr], null_safe=True, ser_safe=True, nullable=expr.nullable) vals = [] for el_idx, el_type in enumerate(styperef.subtypes): type_sentinel = pgast.TypeCast( arg=pgast.NullConstant(), type_name=pgast.TypeName( name=pgtypes.pg_type_from_ir_typeref(el_type) ) ) val = pgast.FuncCall( name=('edgedb', 'row_getattr_by_num'), args=[ expr, pgast.NumericConstant(val=str(el_idx + 1)), type_sentinel ]) if irtyputils.is_collection(el_type): val = coll_as_json_object(val, styperef=el_type, env=env) vals.append(val) return pgast.FuncCall( name=_get_json_func('build_array', env=env), args=vals, null_safe=True, ser_safe=True, nullable=expr.nullable)
def get_path_output_or_null( rel: pgast.Query, path_id: irast.PathId, *, disable_output_fusion: bool=False, aspect: str, env: context.Environment) -> \ Tuple[pgast.OutputVar, bool]: path_id = map_path_id(path_id, rel.view_path_id_map) ref = maybe_get_path_output( rel, path_id, disable_output_fusion=disable_output_fusion, aspect=aspect, env=env) if ref is not None: return ref, False alt_aspect = get_less_specific_aspect(path_id, aspect) if alt_aspect is not None: # If disable_output_fusion is true, we need to be careful # to not reuse an existing column if disable_output_fusion: preexisting = rel.path_outputs.pop((path_id, alt_aspect), None) ref = maybe_get_path_output( rel, path_id, disable_output_fusion=disable_output_fusion, aspect=alt_aspect, env=env) if disable_output_fusion: # Put back the path_output to whatever it was before if not preexisting: rel.path_outputs.pop((path_id, alt_aspect), None) else: rel.path_outputs[(path_id, alt_aspect)] = preexisting if ref is not None: _put_path_output_var(rel, path_id, aspect, ref, env=env) return ref, False alias = env.aliases.get('null') restarget = pgast.ResTarget( name=alias, val=pgast.NullConstant()) rel.target_list.append(restarget) ref = pgast.ColumnRef(name=[alias], nullable=True) _put_path_output_var(rel, path_id, aspect, ref, env=env) return ref, True
def _compile_set_in_singleton_mode( node: irast.Set, *, ctx: context.CompilerContextLevel) -> pgast.BaseExpr: if isinstance(node, irast.EmptySet): return pgast.NullConstant() elif node.expr is not None: return dispatch.compile(node.expr, ctx=ctx) else: if node.rptr: ptrref = node.rptr.ptrref source = node.rptr.source if isinstance(ptrref, irast.TupleIndirectionPointerRef): tuple_val = dispatch.compile(source, ctx=ctx) set_expr = astutils.tuple_getattr( tuple_val, source.typeref, ptrref.shortname.name, ) return set_expr if ptrref.source_ptr is None and source.rptr is not None: raise errors.UnsupportedFeatureError( 'unexpectedly long path in simple expr') ptr_stor_info = pg_types.get_ptrref_storage_info( ptrref, resolve_type=False) colref = pgast.ColumnRef( name=[ptr_stor_info.column_name], nullable=node.rptr.dir_cardinality.can_be_zero()) else: name = [common.edgedb_name_to_pg_name(str(node.typeref.id))] if node.path_id.is_objtype_path(): name.append('id') colref = pgast.ColumnRef(name=name) return colref
def _get_rel_path_output(rel: pgast.BaseRelation, path_id: irast.PathId, *, aspect: str, ptr_info: typing.Optional[ pg_types.PointerStorageInfo] = None, env: context.Environment) -> pgast.OutputVar: if path_id.is_objtype_path(): if aspect == 'identity': aspect = 'value' if aspect != 'value': raise LookupError( f'invalid request for non-scalar path {path_id} {aspect}') if (path_id == rel.path_id or (rel.path_id.is_type_indirection_path() and path_id == rel.path_id.src_path())): return _get_rel_object_id_output(rel, path_id, aspect=aspect, env=env) else: if aspect == 'identity': raise LookupError( f'invalid request for scalar path {path_id} {aspect}') elif aspect == 'serialized': aspect = 'value' var = rel.path_outputs.get((path_id, aspect)) if var is not None: return var ptrref = path_id.rptr() rptr_dir = path_id.rptr_dir() if (rptr_dir is not None and rptr_dir != s_pointers.PointerDirection.Outbound): raise LookupError( f'{path_id} is an inbound pointer and cannot be resolved ' f'on a base relation') if isinstance(rel, pgast.NullRelation): if ptrref is not None: target = ptrref.out_target else: target = path_id.target pg_type = pg_types.pg_type_from_ir_typeref(target) if ptr_info is not None: name = env.aliases.get(ptr_info.column_name) else: name = env.aliases.get('v') val = pgast.TypeCast(arg=pgast.NullConstant(), type_name=pgast.TypeName(name=pg_type, )) rel.target_list.append(pgast.ResTarget(name=name, val=val)) result = pgast.ColumnRef(name=[name], nullable=True) else: if ptrref is None: raise ValueError( f'could not resolve trailing pointer class for {path_id}') if ptr_info is None: ptr_info = pg_types.get_ptrref_storage_info(ptrref, resolve_type=False, link_bias=False) result = pgast.ColumnRef(name=[ptr_info.column_name], nullable=not ptrref.required) _put_path_output_var(rel, path_id, aspect, result, env=env) return result
def compile_ConfigSet(op: irast.ConfigSet, *, ctx: context.CompilerContextLevel) -> pgast.Query: val: pgast.BaseExpr with ctx.new() as subctx: if isinstance(op.expr, irast.EmptySet): # Special handling for empty sets, because we want a # singleton representation of the value and not an empty rel # in this context. if op.cardinality is qltypes.SchemaCardinality.ONE: val = pgast.NullConstant() else: val = pgast.TypeCast( arg=pgast.StringConstant(val='[]'), type_name=pgast.TypeName(name=('jsonb', ), ), ) else: val = dispatch.compile(op.expr, ctx=subctx) assert isinstance(val, pgast.SelectStmt), "expected ast.SelectStmt" pathctx.get_path_serialized_output(val, op.expr.path_id, env=ctx.env) if op.cardinality is qltypes.SchemaCardinality.MANY: val = output.aggregate_json_output(val, op.expr, env=ctx.env) result_row = pgast.RowExpr(args=[ pgast.StringConstant(val='SET'), pgast.StringConstant(val='SYSTEM' if op.system else 'SESSION'), pgast.StringConstant(val=op.name), val, ]) result = pgast.FuncCall( name=('jsonb_build_array', ), args=result_row.args, null_safe=True, ser_safe=True, ) stmt: pgast.Query if not op.system: stmt = pgast.InsertStmt( relation=pgast.RelRangeVar(relation=pgast.Relation( name='_edgecon_state', ), ), select_stmt=pgast.SelectStmt(values=[ pgast.ImplicitRowExpr(args=[ pgast.StringConstant(val=op.name, ), val, pgast.StringConstant(val='C', ), ]) ]), cols=[ pgast.ColumnRef(name=['name']), pgast.ColumnRef(name=['value']), pgast.ColumnRef(name=['type']), ], on_conflict=pgast.OnConflictClause( action='update', infer=pgast.InferClause(index_elems=[ pgast.ColumnRef(name=['name']), pgast.ColumnRef(name=['type']), ], ), target_list=[ pgast.MultiAssignRef( columns=[pgast.ColumnRef(name=['value'])], source=pgast.RowExpr(args=[ val, ], ), ), ], ), ) else: stmt = pgast.SelectStmt(target_list=[ pgast.ResTarget(val=result, ), ], ) return stmt
def compile_ConfigReset(op: irast.ConfigReset, *, ctx: context.CompilerContextLevel) -> pgast.Query: if op.selector is None: # Scalar reset result_row = pgast.RowExpr(args=[ pgast.StringConstant(val='RESET'), pgast.StringConstant(val='SYSTEM' if op.system else 'SESSION'), pgast.StringConstant(val=op.name), pgast.NullConstant(), ]) rvar = None else: selector = dispatch.compile(op.selector, ctx=ctx) assert isinstance(selector, pgast.SelectStmt), \ "expected ast.SelectStmt" target = selector.target_list[0] if not target.name: target = selector.target_list[0] = pgast.ResTarget( name=ctx.env.aliases.get('res'), val=target.val, ) rvar = relctx.rvar_for_rel(selector, ctx=ctx) result_row = pgast.RowExpr(args=[ pgast.StringConstant(val='REM'), pgast.StringConstant(val='SYSTEM' if op.system else 'SESSION'), pgast.StringConstant(val=op.name), astutils.get_column(rvar, target.name), ]) result = pgast.FuncCall( name=('jsonb_build_array', ), args=result_row.args, null_safe=True, ser_safe=True, ) stmt: pgast.Query if not op.system: stmt = pgast.DeleteStmt( relation=pgast.RelRangeVar(relation=pgast.Relation( name='_edgecon_state', ), ), where_clause=astutils.new_binop( lexpr=astutils.new_binop( lexpr=pgast.ColumnRef(name=['name']), rexpr=pgast.StringConstant(val=op.name), op='=', ), rexpr=astutils.new_binop( lexpr=pgast.ColumnRef(name=['type']), rexpr=pgast.StringConstant(val='C'), op='=', ), op='AND', )) else: stmt = pgast.SelectStmt(target_list=[ pgast.ResTarget(val=result, ), ], ) if rvar is not None: stmt.from_clause = [rvar] return stmt
def compile_ConfigSet( op: irast.ConfigSet, *, ctx: context.CompilerContextLevel, ) -> pgast.BaseExpr: val: pgast.BaseExpr with ctx.new() as subctx: if op.backend_setting: output_format = context.OutputFormat.NATIVE else: output_format = context.OutputFormat.JSONB with context.output_format(ctx, output_format): if isinstance(op.expr, irast.EmptySet): # Special handling for empty sets, because we want a # singleton representation of the value and not an empty rel # in this context. if op.cardinality is qltypes.SchemaCardinality.One: val = pgast.NullConstant() elif subctx.env.output_format is context.OutputFormat.JSONB: val = pgast.TypeCast( arg=pgast.StringConstant(val='[]'), type_name=pgast.TypeName( name=('jsonb',), ), ) else: val = pgast.TypeCast( arg=pgast.ArrayExpr(), type_name=pgast.TypeName( name=('text[]',), ), ) else: val = dispatch.compile(op.expr, ctx=subctx) assert isinstance(val, pgast.SelectStmt), "expected SelectStmt" pathctx.get_path_serialized_output( val, op.expr.path_id, env=ctx.env) if op.cardinality is qltypes.SchemaCardinality.Many: val = output.aggregate_json_output( val, op.expr, env=ctx.env) result: pgast.BaseExpr if op.scope is qltypes.ConfigScope.SYSTEM and op.backend_setting: assert isinstance(val, pgast.SelectStmt) and len(val.target_list) == 1 valval = val.target_list[0].val if isinstance(valval, pgast.TypeCast): valval = valval.arg if not isinstance(valval, pgast.BaseConstant): raise AssertionError('value is not a constant in ConfigSet') result = pgast.AlterSystem( name=op.backend_setting, value=valval, ) elif op.scope is qltypes.ConfigScope.DATABASE and op.backend_setting: fcall = pgast.FuncCall( name=('edgedb', '_alter_current_database_set'), args=[pgast.StringConstant(val=op.backend_setting), val], ) result = output.wrap_script_stmt( pgast.SelectStmt(target_list=[pgast.ResTarget(val=fcall)]), suppress_all_output=True, env=ctx.env, ) elif op.scope is qltypes.ConfigScope.SESSION and op.backend_setting: fcall = pgast.FuncCall( name=('pg_catalog', 'set_config'), args=[ pgast.StringConstant(val=op.backend_setting), pgast.TypeCast( arg=val, type_name=pgast.TypeName(name=('text',)), ), pgast.BooleanConstant(val='false'), ], ) result = output.wrap_script_stmt( pgast.SelectStmt(target_list=[pgast.ResTarget(val=fcall)]), suppress_all_output=True, env=ctx.env, ) elif op.scope is qltypes.ConfigScope.SYSTEM: result_row = pgast.RowExpr( args=[ pgast.StringConstant(val='SET'), pgast.StringConstant(val=str(op.scope)), pgast.StringConstant(val=op.name), val, ] ) result = pgast.FuncCall( name=('jsonb_build_array',), args=result_row.args, null_safe=True, ser_safe=True, ) result = pgast.SelectStmt( target_list=[ pgast.ResTarget( val=result, ), ], ) elif op.scope is qltypes.ConfigScope.SESSION: result = pgast.InsertStmt( relation=pgast.RelRangeVar( relation=pgast.Relation( name='_edgecon_state', ), ), select_stmt=pgast.SelectStmt( values=[ pgast.ImplicitRowExpr( args=[ pgast.StringConstant( val=op.name, ), val, pgast.StringConstant( val='C', ), ] ) ] ), cols=[ pgast.ColumnRef(name=['name']), pgast.ColumnRef(name=['value']), pgast.ColumnRef(name=['type']), ], on_conflict=pgast.OnConflictClause( action='update', infer=pgast.InferClause( index_elems=[ pgast.ColumnRef(name=['name']), pgast.ColumnRef(name=['type']), ], ), target_list=[ pgast.MultiAssignRef( columns=[pgast.ColumnRef(name=['value'])], source=pgast.RowExpr( args=[ val, ], ), ), ], ), ) elif op.scope is qltypes.ConfigScope.DATABASE: result = pgast.InsertStmt( relation=pgast.RelRangeVar( relation=pgast.Relation( name='_db_config', schemaname='edgedb', ), ), select_stmt=pgast.SelectStmt( values=[ pgast.ImplicitRowExpr( args=[ pgast.StringConstant( val=op.name, ), val, ] ) ] ), cols=[ pgast.ColumnRef(name=['name']), pgast.ColumnRef(name=['value']), ], on_conflict=pgast.OnConflictClause( action='update', infer=pgast.InferClause( index_elems=[ pgast.ColumnRef(name=['name']), ], ), target_list=[ pgast.MultiAssignRef( columns=[pgast.ColumnRef(name=['value'])], source=pgast.RowExpr( args=[ val, ], ), ), ], ), ) else: raise AssertionError(f'unexpected configuration scope: {op.scope}') return result
def compile_ConfigReset( op: irast.ConfigReset, *, ctx: context.CompilerContextLevel, ) -> pgast.BaseExpr: stmt: pgast.BaseExpr if op.scope is qltypes.ConfigScope.SYSTEM and op.backend_setting: stmt = pgast.AlterSystem( name=op.backend_setting, value=None, ) elif op.scope is qltypes.ConfigScope.DATABASE and op.backend_setting: fcall = pgast.FuncCall( name=('edgedb', '_alter_current_database_set'), args=[ pgast.StringConstant(val=op.backend_setting), pgast.NullConstant(), ], ) stmt = output.wrap_script_stmt( pgast.SelectStmt(target_list=[pgast.ResTarget(val=fcall)]), suppress_all_output=True, env=ctx.env, ) elif op.scope is qltypes.ConfigScope.SESSION and op.backend_setting: fcall = pgast.FuncCall( name=('pg_catalog', 'set_config'), args=[ pgast.StringConstant(val=op.backend_setting), pgast.NullConstant(), pgast.BooleanConstant(val='false'), ], ) stmt = output.wrap_script_stmt( pgast.SelectStmt(target_list=[pgast.ResTarget(val=fcall)]), suppress_all_output=True, env=ctx.env, ) elif op.scope is qltypes.ConfigScope.SYSTEM: if op.selector is None: # Scalar reset result_row = pgast.RowExpr( args=[ pgast.StringConstant(val='RESET'), pgast.StringConstant(val=str(op.scope)), pgast.StringConstant(val=op.name), pgast.NullConstant(), ] ) rvar = None else: with context.output_format(ctx, context.OutputFormat.JSONB): selector = dispatch.compile(op.selector, ctx=ctx) assert isinstance(selector, pgast.SelectStmt), \ "expected ast.SelectStmt" target = selector.target_list[0] if not target.name: target = selector.target_list[0] = pgast.ResTarget( name=ctx.env.aliases.get('res'), val=target.val, ) rvar = relctx.rvar_for_rel(selector, ctx=ctx) result_row = pgast.RowExpr( args=[ pgast.StringConstant(val='REM'), pgast.StringConstant(val=str(op.scope)), pgast.StringConstant(val=op.name), astutils.get_column(rvar, target.name), ] ) result = pgast.FuncCall( name=('jsonb_build_array',), args=result_row.args, null_safe=True, ser_safe=True, ) stmt = pgast.SelectStmt( target_list=[ pgast.ResTarget( val=result, ), ], ) if rvar is not None: stmt.from_clause = [rvar] elif op.scope is qltypes.ConfigScope.DATABASE: stmt = pgast.DeleteStmt( relation=pgast.RelRangeVar( relation=pgast.Relation( name='_db_config', schemaname='edgedb', ), ), where_clause=astutils.new_binop( lexpr=pgast.ColumnRef(name=['name']), rexpr=pgast.StringConstant(val=op.name), op='=', ), ) elif op.scope is qltypes.ConfigScope.SESSION: stmt = pgast.DeleteStmt( relation=pgast.RelRangeVar( relation=pgast.Relation( name='_edgecon_state', ), ), where_clause=astutils.new_binop( lexpr=astutils.new_binop( lexpr=pgast.ColumnRef(name=['name']), rexpr=pgast.StringConstant(val=op.name), op='=', ), rexpr=astutils.new_binop( lexpr=pgast.ColumnRef(name=['type']), rexpr=pgast.StringConstant(val='C'), op='=', ), op='AND', ) ) else: raise AssertionError(f'unexpected configuration scope: {op.scope}') return stmt
def _compile_grouping_value( stmt: irast.GroupStmt, used_args: AbstractSet[str], *, ctx: context.CompilerContextLevel) -> pgast.BaseExpr: '''Produce the value for the grouping binding saying what is grouped on''' assert stmt.grouping_binding grouprel = ctx.rel # If there is only one thing grouped on, just output the hardcoded if len(used_args) == 1: return pgast.ArrayExpr(elements=[ pgast.StringConstant( val=desugar_group.key_name(list(used_args)[0])) ]) using = {k: stmt.using[k] for k in used_args} args = [ pathctx.get_path_var(grouprel, alias_set.path_id, aspect='value', env=ctx.env) for alias_set, _ in using.values() ] # Call grouping on each element we group on to produce a bitmask grouping_alias = ctx.env.aliases.get('g') grouping_call = pgast.FuncCall(name=('grouping', ), args=args) subq = pgast.SelectStmt(target_list=[ pgast.ResTarget(name=grouping_alias, val=grouping_call), ]) q = pgast.SelectStmt(from_clause=[ pgast.RangeSubselect( subquery=subq, alias=pgast.Alias(aliasname=ctx.env.aliases.get())) ]) grouping_ref = pgast.ColumnRef(name=(grouping_alias, )) # Generate a call to ARRAY[...] with a case for each grouping # element, then array_remove out the NULLs. els: List[pgast.BaseExpr] = [] for i, name in enumerate(using): name = desugar_group.key_name(name) mask = 1 << (len(using) - i - 1) # (CASE (e & <mask>) WHEN 0 THEN '<name>' ELSE NULL END) els.append( pgast.CaseExpr( arg=pgast.Expr(kind=pgast.ExprKind.OP, name='&', lexpr=grouping_ref, rexpr=pgast.LiteralExpr(expr=str(mask))), args=[ pgast.CaseWhen(expr=pgast.LiteralExpr(expr='0'), result=pgast.StringConstant(val=name)) ], defresult=pgast.NullConstant())) val = pgast.FuncCall( name=('array_remove', ), args=[pgast.ArrayExpr(elements=els), pgast.NullConstant()]) q.target_list.append(pgast.ResTarget(val=val)) return q
def _compile_config_value( op: irast.ConfigSet, *, ctx: context.CompilerContextLevel, ) -> pgast.BaseExpr: val: pgast.BaseExpr if op.backend_setting: assert op.backend_expr is not None expr = op.backend_expr else: expr = op.expr with ctx.new() as subctx: if op.backend_setting or op.scope == qltypes.ConfigScope.GLOBAL: output_format = context.OutputFormat.NATIVE else: output_format = context.OutputFormat.JSONB with context.output_format(ctx, output_format): if isinstance(expr, irast.EmptySet): # Special handling for empty sets, because we want a # singleton representation of the value and not an empty rel # in this context. if op.cardinality is qltypes.SchemaCardinality.One: val = pgast.NullConstant() elif subctx.env.output_format is context.OutputFormat.JSONB: val = pgast.TypeCast( arg=pgast.StringConstant(val='[]'), type_name=pgast.TypeName(name=('jsonb', ), ), ) else: val = pgast.TypeCast( arg=pgast.ArrayExpr(elements=[]), type_name=pgast.TypeName(name=('text[]', ), ), ) else: val = dispatch.compile(expr, ctx=subctx) assert isinstance(val, pgast.SelectStmt), "expected SelectStmt" pathctx.get_path_serialized_output(val, expr.path_id, env=ctx.env) if op.cardinality is qltypes.SchemaCardinality.Many: val = output.aggregate_json_output(val, expr, env=ctx.env) # For globals, we need to output the binary encoding so that we # can just hand it back to the server. We abuse `record_send` to # act as a generic `_send` function if op.scope is qltypes.ConfigScope.GLOBAL: val = pgast.FuncCall( name=('substring', ), args=[ pgast.FuncCall( name=('record_send', ), args=[pgast.RowExpr(args=[val])], ), # The first twelve bytes are header, the rest is the # encoding of the actual element pgast.NumericConstant(val="13"), ], ) cast_name = s_casts.get_cast_fullname_from_names( 'std', 'std::bytes', 'std::json') val = pgast.FuncCall( name=common.get_cast_backend_name(cast_name, aspect='function'), args=[val], ) if op.backend_setting and op.scope is qltypes.ConfigScope.INSTANCE: assert isinstance(val, pgast.SelectStmt) and len(val.target_list) == 1 val = val.target_list[0].val if isinstance(val, pgast.TypeCast): val = val.arg if not isinstance(val, pgast.BaseConstant): raise AssertionError('value is not a constant in ConfigSet') return val