diff --git a/edgedb/datatypes/datatypes.h b/edgedb/datatypes/datatypes.h index c6a7589b..84f0adc7 100644 --- a/edgedb/datatypes/datatypes.h +++ b/edgedb/datatypes/datatypes.h @@ -122,6 +122,29 @@ PyObject * EdgeObject_GetRecordDesc(PyObject *); int EdgeObject_SetItem(PyObject *, Py_ssize_t, PyObject *); PyObject * EdgeObject_GetItem(PyObject *, Py_ssize_t); -PyObject * EdgeObject_GetID(PyObject *ob); + +/* === edgedb.Record ======================================== */ + +#define EDGE_RECORD_FREELIST_SIZE 2000 +#define EDGE_RECORD_FREELIST_MAXSAVE 20 + +extern PyTypeObject EdgeRecord_Type; + +#define EdgeRecord_Check(d) (Py_TYPE(d) == &EdgeRecord_Type) + +typedef struct { + PyObject_VAR_HEAD + PyObject *weakreflist; + PyObject *desc; + Py_hash_t cached_hash; + PyObject *ob_item[1]; +} EdgeRecord; + +PyObject * EdgeRecord_InitType(void); +PyObject * EdgeRecord_New(PyObject *); +PyObject * EdgeRecord_GetRecordDesc(PyObject *); + +int EdgeRecord_SetItem(PyObject *, Py_ssize_t, PyObject *); +PyObject * EdgeRecord_GetItem(PyObject *, Py_ssize_t); #endif diff --git a/edgedb/datatypes/datatypes.pxd b/edgedb/datatypes/datatypes.pxd index ec83bf39..f133b957 100644 --- a/edgedb/datatypes/datatypes.pxd +++ b/edgedb/datatypes/datatypes.pxd @@ -58,6 +58,10 @@ cdef extern from "datatypes.h": int EdgeObject_SetItem(object, Py_ssize_t, object) except -1 object EdgeObject_GetRecordDesc(object) + object EdgeRecord_InitType() + object EdgeRecord_New(object); + int EdgeRecord_SetItem(object, Py_ssize_t, object) except -1 + object EdgeRecord_GetRecordDesc(object) cdef record_desc_new(object names, object flags, object cards) cdef record_desc_pointer_name(object desc, Py_ssize_t pos) diff --git a/edgedb/datatypes/datatypes.pyx b/edgedb/datatypes/datatypes.pyx index e453b945..751c1ff2 100644 --- a/edgedb/datatypes/datatypes.pyx +++ b/edgedb/datatypes/datatypes.pyx @@ -30,6 +30,7 @@ _RecordDescriptor = EdgeRecordDesc_InitType() Tuple = tuple NamedTuple = EdgeNamedTuple_InitType() Object = EdgeObject_InitType() +Record = EdgeRecord_InitType() Set = list Array = list @@ -132,6 +133,11 @@ cdef namedtuple_type_new(object desc): cdef object_new(object desc): return EdgeObject_New(desc) - cdef object_set(object obj, Py_ssize_t pos, object elem): EdgeObject_SetItem(obj, pos, elem) + +cdef record_new(object desc): + return EdgeRecord_New(desc) + +cdef record_set(object obj, Py_ssize_t pos, object elem): + EdgeRecord_SetItem(obj, pos, elem) diff --git a/edgedb/datatypes/object.c b/edgedb/datatypes/object.c index 1d3029be..2e92f5b2 100644 --- a/edgedb/datatypes/object.c +++ b/edgedb/datatypes/object.c @@ -124,25 +124,6 @@ EdgeObject_GetItem(PyObject *ob, Py_ssize_t i) } -PyObject * -EdgeObject_GetID(PyObject *ob) -{ - assert(EdgeObject_Check(ob)); - EdgeObject *o = (EdgeObject *)ob; - Py_ssize_t i = EdgeRecordDesc_IDPos(o->desc); - if (i < 0) { - Py_RETURN_NONE; - } - if (i >= Py_SIZE(o)) { - PyErr_BadInternalCall(); - return NULL; - } - PyObject *el = EdgeObject_GET_ITEM(o, i); - Py_INCREF(el); - return el; -} - - static void object_dealloc(EdgeObject *o) { diff --git a/edgedb/datatypes/record.c b/edgedb/datatypes/record.c new file mode 100644 index 00000000..3a2294f9 --- /dev/null +++ b/edgedb/datatypes/record.c @@ -0,0 +1,221 @@ +#include "pythoncapi_compat.h" + +/* +* This source file is part of the EdgeDB open source project. +* +* Copyright 2016-present MagicStack Inc. and the EdgeDB authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +#include "datatypes.h" +#include "freelist.h" +#include "internal.h" + + +static int init_type_called = 0; + +EDGE_SETUP_FREELIST( + EDGE_RECORD, + EdgeRecord, + EDGE_RECORD_FREELIST_MAXSAVE, + EDGE_RECORD_FREELIST_SIZE) + + +#define EdgeRecord_GET_ITEM(op, i) \ + (((EdgeRecord *)(op))->ob_item[i]) +#define EdgeRecord_SET_ITEM(op, i, v) \ + (((EdgeRecord *)(op))->ob_item[i] = v) + + +PyObject * +EdgeRecord_New(PyObject *desc) +{ + assert(init_type_called); + + if (desc == NULL || !EdgeRecordDesc_Check(desc)) { + PyErr_BadInternalCall(); + return NULL; + } + + Py_ssize_t size = EdgeRecordDesc_GetSize(desc); + + if (size > EDGE_MAX_TUPLE_SIZE) { + PyErr_Format( + PyExc_ValueError, + "Cannot create Object with more than %d elements", + EDGE_MAX_TUPLE_SIZE); + return NULL; + } + + EdgeRecord *o = NULL; + EDGE_NEW_WITH_FREELIST(EDGE_RECORD, EdgeRecord, + &EdgeRecord_Type, o, size); + assert(o != NULL); + assert(Py_SIZE(o) == size); + assert(EdgeRecord_Check(o)); + + o->weakreflist = NULL; + + Py_INCREF(desc); + o->desc = desc; + + o->cached_hash = -1; + + PyObject_GC_Track(o); + return (PyObject *)o; +} + + +PyObject * +EdgeRecord_GetRecordDesc(PyObject *o) +{ + if (!EdgeRecord_Check(o)) { + PyErr_Format( + PyExc_TypeError, + "an instance of edgedb.Object expected"); + return NULL; + } + + PyObject *desc = ((EdgeRecord *)o)->desc; + Py_INCREF(desc); + return desc; +} + + +int +EdgeRecord_SetItem(PyObject *ob, Py_ssize_t i, PyObject *el) +{ + assert(EdgeRecord_Check(ob)); + EdgeRecord *o = (EdgeRecord *)ob; + assert(i >= 0); + assert(i < Py_SIZE(o)); + Py_INCREF(el); + EdgeRecord_SET_ITEM(o, i, el); + return 0; +} + + +PyObject * +EdgeRecord_GetItem(PyObject *ob, Py_ssize_t i) +{ + assert(EdgeRecord_Check(ob)); + EdgeRecord *o = (EdgeRecord *)ob; + if (i < 0 || i >= Py_SIZE(o)) { + PyErr_BadInternalCall(); + return NULL; + } + PyObject *el = EdgeRecord_GET_ITEM(o, i); + Py_INCREF(el); + return el; +} + + +static void +record_dealloc(EdgeRecord *o) +{ + PyObject_GC_UnTrack(o); + if (o->weakreflist != NULL) { + PyObject_ClearWeakRefs((PyObject*)o); + } + Py_CLEAR(o->desc); + o->cached_hash = -1; + Py_TRASHCAN_BEGIN(o, record_dealloc); + EDGE_DEALLOC_WITH_FREELIST(EDGE_RECORD, EdgeRecord, o); + Py_TRASHCAN_END(o); +} + + +static int +record_traverse(EdgeRecord *o, visitproc visit, void *arg) +{ + Py_VISIT(o->desc); + + Py_ssize_t i; + for (i = Py_SIZE(o); --i >= 0;) { + if (o->ob_item[i] != NULL) { + Py_VISIT(o->ob_item[i]); + } + } + return 0; +} + + +static PyObject * +record_getitem(EdgeRecord *o, PyObject *name) +{ + Py_RETURN_NONE; +} + + +static PyObject * +record_repr(EdgeRecord *o) +{ + _PyUnicodeWriter writer; + _PyUnicodeWriter_Init(&writer); + writer.overallocate = 1; + + if (_PyUnicodeWriter_WriteASCIIString(&writer, "Object{", 7) < 0) { + goto error; + } + + if (_EdgeGeneric_RenderItems(&writer, + (PyObject *)o, o->desc, + o->ob_item, Py_SIZE(o), 1, 0) < 0) + { + goto error; + } + + if (_PyUnicodeWriter_WriteChar(&writer, '}') < 0) { + goto error; + } + + return _PyUnicodeWriter_Finish(&writer); + +error: + _PyUnicodeWriter_Dealloc(&writer); + return NULL; +} + + +static PyMappingMethods record_as_mapping = { + .mp_subscript = (binaryfunc)record_getitem, +}; + + +PyTypeObject EdgeRecord_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "edgedb.Record", + .tp_basicsize = sizeof(EdgeRecord) - sizeof(PyObject *), + .tp_itemsize = sizeof(PyObject *), + .tp_dealloc = (destructor)record_dealloc, + .tp_as_mapping = &record_as_mapping, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + .tp_traverse = (traverseproc)record_traverse, + .tp_free = PyObject_GC_Del, + .tp_repr = (reprfunc)record_repr, + .tp_weaklistoffset = offsetof(EdgeRecord, weakreflist), +}; + + +PyObject * +EdgeRecord_InitType(void) +{ + if (PyType_Ready(&EdgeRecord_Type) < 0) { + return NULL; + } + + init_type_called = 1; + return (PyObject *)&EdgeRecord_Type; +} diff --git a/edgedb/protocol/codecs/codecs.pxd b/edgedb/protocol/codecs/codecs.pxd index ab11d5f5..d69391af 100644 --- a/edgedb/protocol/codecs/codecs.pxd +++ b/edgedb/protocol/codecs/codecs.pxd @@ -22,6 +22,7 @@ include "./scalar.pxd" include "./tuple.pxd" include "./namedtuple.pxd" include "./object.pxd" +include "./record.pxd" include "./array.pxd" include "./range.pxd" include "./set.pxd" @@ -35,9 +36,11 @@ cdef class CodecsRegistry: LRUMapping codecs dict base_codec_overrides - cdef BaseCodec _build_codec(self, FRBuffer *spec, list codecs_list, + cdef BaseCodec _build_codec(self, InputLanguage lang, + FRBuffer *spec, list codecs_list, protocol_version) - cdef BaseCodec build_codec(self, bytes spec, protocol_version) + cdef BaseCodec build_codec(self, InputLanguage lang, bytes spec, + protocol_version) - cdef has_codec(self, bytes type_id) - cdef BaseCodec get_codec(self, bytes type_id) + cdef has_codec(self, InputLanguage lang, bytes type_id) + cdef BaseCodec get_codec(self, InputLanguage lang, bytes type_id) diff --git a/edgedb/protocol/codecs/codecs.pyx b/edgedb/protocol/codecs/codecs.pyx index 2887320b..f076d788 100644 --- a/edgedb/protocol/codecs/codecs.pyx +++ b/edgedb/protocol/codecs/codecs.pyx @@ -36,6 +36,7 @@ include "./scalar.pyx" include "./tuple.pyx" include "./namedtuple.pyx" include "./object.pyx" +include "./record.pyx" include "./array.pyx" include "./range.pyx" include "./set.pyx" @@ -94,7 +95,8 @@ cdef class CodecsRegistry: decoder, ) - cdef BaseCodec _build_codec(self, FRBuffer *spec, list codecs_list, + cdef BaseCodec _build_codec(self, InputLanguage lang, + FRBuffer *spec, list codecs_list, protocol_version): cdef: uint32_t desc_len = 0 @@ -114,7 +116,7 @@ cdef class CodecsRegistry: t = (frb_read(spec, 1)[0]) tid = frb_read(spec, 16)[:16] - res = self.codecs.get(tid, None) + res = self.codecs.get(chr(lang) + tid, None) if res is None: res = self.codecs_build_cache.get(tid, None) if res is not None: @@ -237,9 +239,14 @@ cdef class CodecsRegistry: frb_read(spec, 2)) source_type = codecs_list[source_type_pos] - res = ObjectCodec.new( - tid, names, flags, cards, codecs, t == CTYPE_INPUT_SHAPE - ) + if lang == InputLanguage.EDGEQL: + res = ObjectCodec.new( + tid, names, flags, cards, codecs, t == CTYPE_INPUT_SHAPE + ) + else: + res = RecordCodec.new( + tid, names, flags, cards, codecs + ) elif t == CTYPE_INPUT_SHAPE: els = hton.unpack_int16(frb_read(spec, 2)) @@ -483,15 +490,17 @@ cdef class CodecsRegistry: self.codecs_build_cache[tid] = res return res - cdef has_codec(self, bytes type_id): + cdef has_codec(self, InputLanguage lang, bytes type_id): + key = chr(lang) + type_id return ( - type_id in self.codecs or + key in self.codecs or type_id in {NULL_CODEC_ID, EMPTY_TUPLE_CODEC_ID} ) - cdef BaseCodec get_codec(self, bytes type_id): + cdef BaseCodec get_codec(self, InputLanguage lang, bytes type_id): + key = chr(lang) + type_id try: - return self.codecs[type_id] + return self.codecs[key] except KeyError: pass @@ -503,7 +512,8 @@ cdef class CodecsRegistry: raise LookupError - cdef BaseCodec build_codec(self, bytes spec, protocol_version): + cdef BaseCodec build_codec(self, InputLanguage lang, bytes spec, + protocol_version): cdef: FRBuffer buf FRBuffer elem_buf @@ -521,17 +531,18 @@ cdef class CodecsRegistry: desc_len = hton.unpack_int32(frb_read(&buf, 4)) frb_slice_from(&elem_buf, &buf, desc_len) res = self._build_codec( - &elem_buf, codecs_list, protocol_version) + lang, &elem_buf, codecs_list, protocol_version) if frb_get_len(&elem_buf): raise RuntimeError( f'unexpected trailing data in type descriptor datum') else: - res = self._build_codec(&buf, codecs_list, protocol_version) + res = self._build_codec( + lang, &buf, codecs_list, protocol_version) if res is None: # An annotation; ignore. continue codecs_list.append(res) - self.codecs[res.tid] = res + self.codecs[chr(lang) + res.tid] = res if not codecs_list: raise RuntimeError(f'cannot not build codec; empty type desc') diff --git a/edgedb/protocol/codecs/record.pxd b/edgedb/protocol/codecs/record.pxd new file mode 100644 index 00000000..7d7824eb --- /dev/null +++ b/edgedb/protocol/codecs/record.pxd @@ -0,0 +1,24 @@ +# +# This source file is part of the EdgeDB open source project. +# +# Copyright 2016-present MagicStack Inc. and the EdgeDB authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + + +@cython.final +cdef class RecordCodec(BaseNamedRecordCodec): + @staticmethod + cdef BaseCodec new(bytes tid, tuple names, tuple flags, + tuple cards, tuple codecs) diff --git a/edgedb/protocol/codecs/record.pyx b/edgedb/protocol/codecs/record.pyx new file mode 100644 index 00000000..4cb81290 --- /dev/null +++ b/edgedb/protocol/codecs/record.pyx @@ -0,0 +1,83 @@ +# +# This source file is part of the EdgeDB open source project. +# +# Copyright 2016-present MagicStack Inc. and the EdgeDB authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + + +@cython.final +cdef class RecordCodec(BaseNamedRecordCodec): + + cdef encode(self, WriteBuffer buf, object obj): + raise NotImplementedError + + cdef decode(self, FRBuffer *buf): + cdef: + object result + Py_ssize_t elem_count + Py_ssize_t i + int32_t elem_len + BaseCodec elem_codec + FRBuffer elem_buf + tuple fields_codecs = (self).fields_codecs + descriptor = (self).descriptor + + if self.is_sparse: + raise NotImplementedError + + elem_count = hton.unpack_int32(frb_read(buf, 4)) + + if elem_count != len(fields_codecs): + raise RuntimeError( + f'cannot decode Record: expected {len(fields_codecs)} ' + f'elements, got {elem_count}') + + result = datatypes.record_new(descriptor) + + for i in range(elem_count): + frb_read(buf, 4) # reserved + elem_len = hton.unpack_int32(frb_read(buf, 4)) + + if elem_len == -1: + elem = None + else: + elem_codec = fields_codecs[i] + elem = elem_codec.decode( + frb_slice_from(&elem_buf, buf, elem_len)) + if frb_get_len(&elem_buf): + raise RuntimeError( + f'unexpected trailing data in buffer after ' + f'record element decoding: {frb_get_len(&elem_buf)}') + + datatypes.record_set(result, i, elem) + + return result + + @staticmethod + cdef BaseCodec new(bytes tid, tuple names, tuple flags, tuple cards, + tuple codecs): + cdef: + RecordCodec codec + + codec = RecordCodec.__new__(RecordCodec) + + codec.tid = tid + codec.name = 'Record' + codec.descriptor = datatypes.record_desc_new(names, flags, cards) + codec.descriptor.set_dataclass_fields_func(codec.get_dataclass_fields) + codec.fields_codecs = codecs + + return codec + diff --git a/edgedb/protocol/protocol.pxd b/edgedb/protocol/protocol.pxd index b6e143ae..d4373ff3 100644 --- a/edgedb/protocol/protocol.pxd +++ b/edgedb/protocol/protocol.pxd @@ -139,7 +139,7 @@ cdef class SansIOProtocol: cdef parse_command_complete_message(self) cdef parse_describe_type_message(self, ExecuteContext ctx) cdef parse_describe_state_message(self) - cdef parse_type_data(self, CodecsRegistry reg) + cdef parse_type_data(self, ExecuteContext ctx) cdef _amend_parse_error( self, exc, diff --git a/edgedb/protocol/protocol.pyx b/edgedb/protocol/protocol.pyx index e464a039..c5a295b0 100644 --- a/edgedb/protocol/protocol.pyx +++ b/edgedb/protocol/protocol.pyx @@ -936,11 +936,12 @@ cdef class SansIOProtocol: typedesc_id = buf.read_bytes(16) typedesc = buf.read_bytes(typedesc_len) - if self.internal_reg.has_codec(typedesc_id): - codec = self.internal_reg.get_codec(typedesc_id) + if self.internal_reg.has_codec(InputLanguage.EDGEQL, typedesc_id): + codec = self.internal_reg.get_codec( + InputLanguage.EDGEQL, typedesc_id) else: codec = self.internal_reg.build_codec( - typedesc, self.protocol_version) + InputLanguage.EDGEQL, typedesc, self.protocol_version) data = buf.read_len_prefixed_bytes() self.server_settings[name] = self.parse_system_config(codec, data) @@ -1021,7 +1022,7 @@ cdef class SansIOProtocol: ctx.capabilities = self.buffer.read_int64() ctx.cardinality = self.buffer.read_byte() - ctx.in_dc, ctx.out_dc = self.parse_type_data(ctx.reg) + ctx.in_dc, ctx.out_dc = self.parse_type_data(ctx) finally: self.buffer.finish_message() @@ -1034,37 +1035,44 @@ cdef class SansIOProtocol: if state_type_id != self.state_type_id: self.state_type_id = state_type_id self.state_cache = (None, None) - if self.internal_reg.has_codec(state_type_id): + if self.internal_reg.has_codec( + InputLanguage.EDGEQL, state_type_id): self.state_codec = self.internal_reg.get_codec( + InputLanguage.EDGEQL, state_type_id ) else: self.state_codec = self.internal_reg.build_codec( - state_typedesc, self.protocol_version + InputLanguage.EDGEQL, + state_typedesc, + self.protocol_version ) finally: self.buffer.finish_message() - cdef parse_type_data(self, CodecsRegistry reg): + cdef parse_type_data(self, ExecuteContext ctx): cdef: bytes type_id BaseCodec in_dc, out_dc + CodecsRegistry reg = ctx.reg type_id = self.buffer.read_bytes(16) type_data = self.buffer.read_len_prefixed_bytes() - if reg.has_codec(type_id): - in_dc = reg.get_codec(type_id) + if reg.has_codec(ctx.input_language, type_id): + in_dc = reg.get_codec(ctx.input_language, type_id) else: - in_dc = reg.build_codec(type_data, self.protocol_version) + in_dc = reg.build_codec( + ctx.input_language, type_data, self.protocol_version) type_id = self.buffer.read_bytes(16) type_data = self.buffer.read_len_prefixed_bytes() - if reg.has_codec(type_id): - out_dc = reg.get_codec(type_id) + if reg.has_codec(ctx.input_language, type_id): + out_dc = reg.get_codec(ctx.input_language, type_id) else: - out_dc = reg.build_codec(type_data, self.protocol_version) + out_dc = reg.build_codec( + ctx.input_language, type_data, self.protocol_version) return in_dc, out_dc diff --git a/edgedb/protocol/protocol_v0.pxd b/edgedb/protocol/protocol_v0.pxd index f01f5bfb..47bd07af 100644 --- a/edgedb/protocol/protocol_v0.pxd +++ b/edgedb/protocol/protocol_v0.pxd @@ -17,7 +17,7 @@ # cdef class SansIOProtocolBackwardsCompatible(SansIOProtocol): - cdef parse_legacy_describe_type_message(self, CodecsRegistry reg) + cdef parse_legacy_describe_type_message(self, ExecuteContext ctx) cdef parse_legacy_command_complete_message(self) cdef legacy_write_headers(self, WriteBuffer buf, dict headers) cdef legacy_write_execute_headers( diff --git a/edgedb/protocol/protocol_v0.pyx b/edgedb/protocol/protocol_v0.pyx index 2a4cb80b..5b6450bf 100644 --- a/edgedb/protocol/protocol_v0.pyx +++ b/edgedb/protocol/protocol_v0.pyx @@ -33,7 +33,7 @@ cdef class SansIOProtocolBackwardsCompatible(SansIOProtocol): self, query: str, *, - reg: CodecsRegistry, + ctx: ExecuteContext, output_format: OutputFormat=OutputFormat.BINARY, expect_one: bint=False, required_one: bool=False, @@ -51,6 +51,7 @@ cdef class SansIOProtocolBackwardsCompatible(SansIOProtocol): bytes in_type_id bytes out_type_id bytes cardinality + CodecsRegistry reg = ctx.reg if not self.connected: raise RuntimeError('not connected') @@ -80,7 +81,7 @@ cdef class SansIOProtocolBackwardsCompatible(SansIOProtocol): attrs = self.legacy_parse_headers() cardinality = self.buffer.read_byte() if self.protocol_version >= (0, 14): - in_dc, out_dc = self.parse_type_data(reg) + in_dc, out_dc = self.parse_type_data(ctx) else: in_type_id = self.buffer.read_bytes(16) out_type_id = self.buffer.read_bytes(16) @@ -103,10 +104,10 @@ cdef class SansIOProtocolBackwardsCompatible(SansIOProtocol): raise exc if self.protocol_version < (0, 14): - if reg.has_codec(in_type_id): - in_dc = reg.get_codec(in_type_id) - if reg.has_codec(out_type_id): - out_dc = reg.get_codec(out_type_id) + if reg.has_codec(InputLanguage.EDGEQL, in_type_id): + in_dc = reg.get_codec(InputLanguage.EDGEQL, in_type_id) + if reg.has_codec(InputLanguage.EDGEQL, out_type_id): + out_dc = reg.get_codec(InputLanguage.EDGEQL, out_type_id) if in_dc is None or out_dc is None: buf = WriteBuffer.new_message(DESCRIBE_STMT_MSG) @@ -125,7 +126,7 @@ cdef class SansIOProtocolBackwardsCompatible(SansIOProtocol): try: if mtype == STMT_DATA_DESC_MSG: cardinality, in_dc, out_dc, _ = \ - self.parse_legacy_describe_type_message(reg) + self.parse_legacy_describe_type_message(ctx) elif mtype == ERROR_RESPONSE_MSG: exc = self.parse_error_message() @@ -237,7 +238,6 @@ cdef class SansIOProtocolBackwardsCompatible(SansIOProtocol): str query = ctx.query object args = ctx.args object kwargs = ctx.kwargs - CodecsRegistry reg = ctx.reg OutputFormat output_format = ctx.output_format bint expect_one = ctx.expect_one bint required_one = ctx.required_one @@ -278,7 +278,7 @@ cdef class SansIOProtocolBackwardsCompatible(SansIOProtocol): if mtype == STMT_DATA_DESC_MSG: # our in/out type spec is out-dated new_cardinality, in_dc, out_dc, headers = \ - self.parse_legacy_describe_type_message(reg) + self.parse_legacy_describe_type_message(ctx) capabilities = headers.get(SERVER_HEADER_CAPABILITIES) if capabilities is not None: @@ -368,7 +368,7 @@ cdef class SansIOProtocolBackwardsCompatible(SansIOProtocol): if not ctx.load_from_cache(): codecs = await self._legacy_parse( query, - reg=reg, + ctx=ctx, output_format=output_format, expect_one=expect_one, required_one=required_one, @@ -483,7 +483,7 @@ cdef class SansIOProtocolBackwardsCompatible(SansIOProtocol): if exc is not None: raise exc - cdef parse_legacy_describe_type_message(self, CodecsRegistry reg): + cdef parse_legacy_describe_type_message(self, ExecuteContext ctx): assert self.buffer.get_message_type() == COMMAND_DATA_DESC_MSG cdef: @@ -494,7 +494,7 @@ cdef class SansIOProtocolBackwardsCompatible(SansIOProtocol): try: cardinality = self.buffer.read_byte() - in_dc, out_dc = self.parse_type_data(reg) + in_dc, out_dc = self.parse_type_data(ctx) finally: self.buffer.finish_message() diff --git a/setup.py b/setup.py index 293030af..1005743e 100644 --- a/setup.py +++ b/setup.py @@ -312,6 +312,7 @@ def finalize_options(self): "edgedb/datatypes/record_desc.c", "edgedb/datatypes/namedtuple.c", "edgedb/datatypes/object.c", + "edgedb/datatypes/record.c", "edgedb/datatypes/hash.c", "edgedb/datatypes/repr.c", "edgedb/datatypes/comp.c", diff --git a/tests/test_async_query.py b/tests/test_async_query.py index da731bb3..b4d62d86 100644 --- a/tests/test_async_query.py +++ b/tests/test_async_query.py @@ -1150,3 +1150,7 @@ async def test_transaction_state(self): await tx.execute(''' INSERT test::Tmp { id := $0, tmp := '' } ''', uuid.uuid4()) + + async def test_async_query_sql_01(self): + res = await self.client.query_sql("SELECT 1") + print(res)