@property
def oid(self) -> int:
- return TEXT_OID
+ return 0
@classmethod
def register(
data: List[bytes] = [b"", b""] # placeholders to avoid a resize
dims: List[int] = []
hasnull = 0
- oid: Optional[int] = None
+ oid = 0
def calc_dims(L: List[Any]) -> None:
if isinstance(L, self.src):
ad = dumper.dump(item)
data.append(_struct_len.pack(len(ad)))
data.append(ad)
- if oid is None:
+ if not oid:
oid = dumper.oid
else:
hasnull = 1
dump_list(obj, 0)
- if oid is None:
+ if not oid:
oid = TEXT_OID
self._array_oid = self._get_array_oid(oid)
super().__init__(src, context)
self._encode: EncodeFunc
- if self.connection is not None:
+ if self.connection:
if self.connection.client_encoding != "SQL_ASCII":
self._encode = self.connection.codec.encode
else:
import pytest
+
+import psycopg3
from psycopg3.adapt import Transformer, Format, Dumper, Loader
from psycopg3.oids import builtins
t = Transformer()
dumper = t.get_dumper(data, format)
assert dumper.dump(data) == result
- assert dumper.oid == builtins[type].oid
+ assert dumper.oid == 0 if type == "text" else builtins[type].oid
@pytest.mark.parametrize(
pass
cur = conn.cursor()
- cur.execute("select %s, %b", [MyString("hello"), MyString("world")])
+ cur.execute(
+ "select %s::text, %b::text", [MyString("hello"), MyString("world")]
+ )
assert cur.fetchone() == ("hello", "world")
assert cur.fetchone()[0]
+@pytest.mark.parametrize("fmt_in", [Format.TEXT, Format.BINARY])
+def test_return_untyped(conn, fmt_in):
+ # Analyze and check for changes using strings in untyped/typed contexts
+ cur = conn.cursor()
+ # Currently string are passed as unknown oid to libpq. This is because
+ # unknown is more easily cast by postgres to different types (see jsonb
+ # later). However Postgres < 10 refuses to emit unknown types.
+ if conn.pgconn.server_version > 100000:
+ cur.execute("select %s, %s", ["hello", 10])
+ assert cur.fetchone() == ("hello", 10)
+ else:
+ with pytest.raises(psycopg3.errors.IndeterminateDatatype):
+ cur.execute("select %s, %s", ["hello", 10])
+ conn.rollback()
+ cur.execute("select %s::text, %s", ["hello", 10])
+ assert cur.fetchone() == ("hello", 10)
+
+ # It would be nice if above all postgres version behaved consistently.
+ # However this below shouldn't break either.
+ cur.execute("create table testjson(data jsonb)")
+ cur.execute("insert into testjson (data) values (%s)", ["{}"])
+ assert cur.execute("select data from testjson").fetchone() == ({},)
+
+
def make_dumper(suffix):
"""Create a test dumper appending a suffix to the bytes representation."""
class TestDumper(Dumper):
+ oid = TEXT_OID
+
def dump(self, s):
return (s + suffix).encode("ascii")
def test_execute_sequence(conn):
cur = conn.cursor()
- cast = "::text" if conn.pgconn.server_version < 100000 else ""
- rv = cur.execute(f"select %s, %s, %s{cast}", [1, "foo", None])
+ rv = cur.execute("select %s::int, %s::text, %s::text", [1, "foo", None])
assert rv is cur
assert len(cur._results) == 1
assert cur.pgresult.get_value(0, 0) == b"1"
def test_fetchone(conn):
cur = conn.cursor()
- cast = "::text" if conn.pgconn.server_version < 100000 else ""
- cur.execute(f"select %s, %s, %s{cast}", [1, "foo", None])
+ cur.execute("select %s::int, %s::text, %s::text", [1, "foo", None])
assert cur.pgresult.fformat(0) == 0
row = cur.fetchone()
def test_execute_binary_result(conn):
cur = conn.cursor(format=psycopg3.pq.Format.BINARY)
- cast = "::text" if conn.pgconn.server_version < 100000 else ""
- cur.execute(f"select %s, %s{cast}", ["foo", None])
+ cur.execute("select %s::text, %s::text", ["foo", None])
assert cur.pgresult.fformat(0) == 1
row = cur.fetchone()
async def test_execute_sequence(aconn):
cur = aconn.cursor()
- cast = "::text" if aconn.pgconn.server_version < 100000 else ""
- rv = await cur.execute(f"select %s, %s, %s{cast}", [1, "foo", None])
+ rv = await cur.execute(
+ "select %s::int, %s::text, %s::text", [1, "foo", None]
+ )
assert rv is cur
assert len(cur._results) == 1
assert cur.pgresult.get_value(0, 0) == b"1"
async def test_fetchone(aconn):
cur = aconn.cursor()
- cast = "::text" if aconn.pgconn.server_version < 100000 else ""
- await cur.execute(f"select %s, %s, %s{cast}", [1, "foo", None])
+ await cur.execute("select %s::int, %s::text, %s::text", [1, "foo", None])
assert cur.pgresult.fformat(0) == 0
row = await cur.fetchone()
async def test_execute_binary_result(aconn):
cur = aconn.cursor(format=psycopg3.pq.Format.BINARY)
- cast = "::text" if aconn.pgconn.server_version < 100000 else ""
- await cur.execute(f"select %s, %s{cast}", ["foo", None])
+ await cur.execute("select %s::text, %s::text", ["foo", None])
assert cur.pgresult.fformat(0) == 1
row = await cur.fetchone()
assert res == tuple(map(chr, range(1, 256)))
s = "".join(map(chr, range(1, 256)))
- res = cur.execute("select row(%s)", [s]).fetchone()[0]
+ res = cur.execute("select row(%s::text)", [s]).fetchone()[0]
assert res == (s,)
ph = "%s" if fmt_in == Format.TEXT else "%b"
s = "foo\x00bar"
with pytest.raises(psycopg3.DataError):
- cur.execute(f"select {ph}", (s,))
+ cur.execute(f"select {ph}::text", (s,))
def test_quote_zero(conn):
@pytest.mark.parametrize("fmt_in", [Format.TEXT, Format.BINARY])
-@pytest.mark.parametrize("encoding", ["utf8", "latin9"])
+@pytest.mark.parametrize("encoding", ["utf8", "latin9", "sql_ascii"])
def test_dump_enc(conn, fmt_in, encoding):
cur = conn.cursor()
ph = "%s" if fmt_in == Format.TEXT else "%b"
conn.client_encoding = encoding
- (res,) = cur.execute(f"select {ph}::bytea", (eur,)).fetchone()
- assert res == eur.encode("utf8")
-
-
-@pytest.mark.parametrize("fmt_in", [Format.TEXT, Format.BINARY])
-def test_dump_ascii(conn, fmt_in):
- cur = conn.cursor()
- ph = "%s" if fmt_in == Format.TEXT else "%b"
-
- conn.client_encoding = "sql_ascii"
(res,) = cur.execute(f"select ascii({ph})", (eur,)).fetchone()
assert res == ord(eur)