return skip_crdb(*args, reason="time precision")
+def crdb_scs_off(*args):
+ return skip_crdb(*args, reason="standard_conforming_strings=off")
+
+
# mapping from reason description to ticket number
_crdb_reasons = {
"2-phase commit": 22329,
"cast adds tz": 51692,
"cidr": 18846,
"composite": 27792,
- "copy": 41608,
"copy canceled": 81559,
+ "copy": 41608,
"cursor with hold": 77101,
"deferrable": 48307,
"do": 17511,
"infinity date": 41564,
"interval style": 35807,
"large objects": 243,
- "server-side cursor": 41412,
"negative interval": 81577,
"nested array": 32552,
"notify": 41522,
"password_encryption": 42519,
"pg_terminate_backend": 35897,
"range": 41282,
+ "severity_nonlocalized": 81794,
"scroll cursor": 77102,
+ "server-side cursor": 41412,
"stored procedure": 1751,
}
-import pytest
from select import select
+
+import pytest
+
import psycopg
from psycopg import pq
from psycopg.generators import execute
# Long query to make sure we have to wait on send
pgconn.send_query(
- b"/* %s */ select pg_sleep(0.01); select 1 as foo;" % (b"x" * 1_000_000)
+ b"/* %s */ select 'x' as f from pg_sleep(0.01); select 1 as foo;"
+ % (b"x" * 1_000_000)
)
# send loop
assert len(results) == 2
assert results[0].nfields == 1
- assert results[0].fname(0) == b"pg_sleep"
- assert results[0].get_value(0, 0) == b""
+ assert results[0].fname(0) == b"f"
+ assert results[0].get_value(0, 0) == b"x"
assert results[1].nfields == 1
assert results[1].fname(0) == b"foo"
assert results[1].get_value(0, 0) == b"1"
def test_send_query_compact_test(pgconn):
# Like the above test but use psycopg facilities for compactness
pgconn.send_query(
- b"/* %s */ select pg_sleep(0.01); select 1 as foo;" % (b"x" * 1_000_000)
+ b"/* %s */ select 'x' as f from pg_sleep(0.01); select 1 as foo;"
+ % (b"x" * 1_000_000)
)
results = execute_wait(pgconn)
assert len(results) == 2
assert results[0].nfields == 1
- assert results[0].fname(0) == b"pg_sleep"
- assert results[0].get_value(0, 0) == b""
+ assert results[0].fname(0) == b"f"
+ assert results[0].get_value(0, 0) == b"x"
assert results[1].nfields == 1
assert results[1].fname(0) == b"foo"
assert results[1].get_value(0, 0) == b"1"
def test_send_describe_prepared(pgconn):
- pgconn.send_prepare(b"prep", b"select $1::int + $2::int as fld")
+ pgconn.send_prepare(b"prep", b"select $1::int8 + $2::int8 as fld")
(res,) = execute_wait(pgconn)
assert res.status == pq.ExecStatus.COMMAND_OK, res.error_message
assert res.nfields == 1
assert res.ntuples == 0
assert res.fname(0) == b"fld"
- assert res.ftype(0) == 23
+ assert res.ftype(0) == 20
pgconn.finish()
with pytest.raises(psycopg.OperationalError):
pgconn.send_describe_prepared(b"prep")
+@pytest.mark.crdb("skip", reason="server-side cursor")
def test_send_describe_portal(pgconn):
res = pgconn.exec_(
b"""
import psycopg
from psycopg import pq
+pytestmark = pytest.mark.crdb("skip", reason="copy")
+
sample_values = "values (10::int, 20::int, 'hello'::text), (40, NULL, 'world')"
sample_tabledef = "col1 int primary key, col2 int, data text"
import psycopg
from psycopg import pq
+from ..fix_crdb import crdb_scs_off
+
@pytest.mark.parametrize(
"data, want",
assert out == want
-@pytest.mark.parametrize("scs", ["on", "off"])
+@pytest.mark.parametrize("scs", ["on", crdb_scs_off("off")])
def test_escape_literal_1char(pgconn, scs):
res = pgconn.exec_(f"set standard_conforming_strings to {scs}".encode("ascii"))
assert res.status == pq.ExecStatus.COMMAND_OK
assert out == want
-@pytest.mark.parametrize("scs", ["on", "off"])
+@pytest.mark.parametrize("scs", ["on", crdb_scs_off("off")])
def test_escape_identifier_1char(pgconn, scs):
res = pgconn.exec_(f"set standard_conforming_strings to {scs}".encode("ascii"))
assert res.status == pq.ExecStatus.COMMAND_OK
assert out == want
-@pytest.mark.parametrize("scs", ["on", "off"])
+@pytest.mark.parametrize("scs", ["on", crdb_scs_off("off")])
def test_escape_string_1char(pgconn, scs):
esc = pq.Escaping(pgconn)
res = pgconn.exec_(f"set standard_conforming_strings to {scs}".encode("ascii"))
assert res.get_value(0, 0) == out
+@pytest.mark.crdb("skip", reason="server-side cursor")
def test_describe_portal(pgconn):
res = pgconn.exec_(
b"""
assert "NULL" in pq.error_message(pgconn)
+@pytest.mark.crdb("skip", reason="encoding")
def test_error_message_encoding(pgconn):
res = pgconn.exec_(b"set client_encoding to latin9")
assert res.status == pq.ExecStatus.COMMAND_OK
conn.connect_poll()
+@pytest.mark.crdb("skip", reason="connects to any db name")
def test_connect_async_bad(dsn):
parsed_dsn = {e.keyword: e.val for e in pq.Conninfo.parse(dsn.encode()) if e.val}
parsed_dsn[b"dbname"] = b"psycopg_test_not_for_real"
pgconn.info
+@pytest.mark.crdb("skip", reason="pg_terminate_backend")
def test_reset(pgconn):
assert pgconn.status == pq.ConnStatus.OK
pgconn.exec_(b"select pg_terminate_backend(pg_backend_pid())")
assert pgconn.status == pq.ConnStatus.BAD
+@pytest.mark.crdb("skip", reason="pg_terminate_backend")
def test_reset_async(pgconn):
assert pgconn.status == pq.ConnStatus.OK
pgconn.exec_(b"select pg_terminate_backend(pg_backend_pid())")
pgconn.parameter_status(b"application_name")
+@pytest.mark.crdb("skip", reason="encoding")
def test_encoding(pgconn):
res = pgconn.exec_(b"set client_encoding to latin1")
assert res.status == pq.ExecStatus.COMMAND_OK
cancel.free()
+@pytest.mark.crdb("skip", reason="notify")
def test_notify(pgconn):
assert pgconn.notifies() is None
assert pgconn.notifies() is None
+@pytest.mark.crdb("skip", reason="do")
def test_notice_nohandler(pgconn):
pgconn.exec_(b"set client_min_messages to notice")
res = pgconn.exec_(
assert res.status == pq.ExecStatus.COMMAND_OK
+@pytest.mark.crdb("skip", reason="do")
def test_notice(pgconn):
msgs = []
assert msgs and msgs[0] == b"hello notice"
+@pytest.mark.crdb("skip", reason="do")
def test_notice_error(pgconn, caplog):
caplog.set_level(logging.WARNING, logger="psycopg")
with tracef.open("w") as f:
pgconn.trace(f.fileno())
pgconn.set_trace_flags(pq.Trace.SUPPRESS_TIMESTAMPS | pq.Trace.REGRESS_MODE)
- pgconn.exec_(b"select 1")
+ pgconn.exec_(b"select 1::int4 as foo")
pgconn.untrace()
- pgconn.exec_(b"select 2")
+ pgconn.exec_(b"select 2::int4 as foo")
traces = [line.split("\t") for line in tracef.read_text().splitlines()]
assert traces == [
- ["F", "13", "Query", ' "select 1"'],
- ["B", "33", "RowDescription", ' 1 "?column?" NNNN 0 NNNN 4 -1 0'],
+ ["F", "26", "Query", ' "select 1::int4 as foo"'],
+ ["B", "28", "RowDescription", ' 1 "foo" NNNN 0 NNNN 4 -1 0'],
["B", "11", "DataRow", " 1 1 '1'"],
["B", "13", "CommandComplete", ' "SELECT 1"'],
["B", "5", "ReadyForQuery", " I"],
@pytest.mark.libpq(">= 10")
+@pytest.mark.crdb("skip", reason="password_encryption")
def test_encrypt_password_query(pgconn):
res = pgconn.exec_(b"set password_encryption to 'md5'")
- assert res.status == pq.ExecStatus.COMMAND_OK
+ assert res.status == pq.ExecStatus.COMMAND_OK, pgconn.error_message.decode()
enc = pgconn.encrypt_password(b"psycopg2", b"ashesh")
assert enc == b"md594839d658c28a357126f105b9cb14cfc"
def test_error_field(pgconn):
res = pgconn.exec_(b"select wat")
- assert res.error_field(pq.DiagnosticField.SEVERITY_NONLOCALIZED) == b"ERROR"
+ # https://github.com/cockroachdb/cockroach/issues/81794
+ assert (
+ res.error_field(pq.DiagnosticField.SEVERITY_NONLOCALIZED)
+ or res.error_field(pq.DiagnosticField.SEVERITY)
+ ) == b"ERROR"
assert res.error_field(pq.DiagnosticField.SQLSTATE) == b"42703"
assert b"wat" in res.error_field(pq.DiagnosticField.MESSAGE_PRIMARY)
res.clear()
assert res.fname(0) is None
+@pytest.mark.crdb("skip", reason="ftable")
def test_ftable_and_col(pgconn):
res = pgconn.exec_(
b"""
def test_ftype(pgconn):
- res = pgconn.exec_(b"select 1::int, 1::numeric, 1::text")
+ res = pgconn.exec_(b"select 1::int4, 1::numeric, 1::text")
assert res.status == pq.ExecStatus.TUPLES_OK, res.error_message
assert res.ftype(0) == 23
assert res.ftype(1) == 1700
def test_fsize(pgconn):
- res = pgconn.exec_(b"select 1::int, 1::bigint, 1::text")
+ res = pgconn.exec_(b"select 1::int4, 1::bigint, 1::text")
assert res.status == pq.ExecStatus.TUPLES_OK, res.error_message
assert res.fsize(0) == 4
assert res.fsize(1) == 8
def test_nparams_types(pgconn):
- res = pgconn.prepare(b"", b"select $1::int, $2::text")
+ res = pgconn.prepare(b"", b"select $1::int4, $2::text")
assert res.status == pq.ExecStatus.COMMAND_OK, res.error_message
res = pgconn.describe_prepared(b"")
def test_command_status(pgconn):
res = pgconn.exec_(b"select 1")
assert res.command_status == b"SELECT 1"
- res = pgconn.exec_(b"set timezone to utf8")
+ res = pgconn.exec_(b"set timezone to utc")
assert res.command_status == b"SET"
res.clear()
assert res.command_status is None
from psycopg.types.string import StrDumper
from .utils import eur
-from .fix_crdb import crdb_encoding
-
-crdb_skip_scs = pytest.mark.crdb("skip", reason="standard_conforming_strings=off")
+from .fix_crdb import crdb_encoding, crdb_scs_off
@pytest.mark.parametrize(
assert sql.quote(obj) == quoted
-@pytest.mark.parametrize("scs", ["on", pytest.param("off", marks=crdb_skip_scs)])
+@pytest.mark.parametrize("scs", ["on", crdb_scs_off("off")])
def test_quote_roundtrip(conn, scs):
messages = []
conn.add_notice_handler(lambda msg: messages.append(msg.message_primary))
assert not messages, f"error with {want!r}"
-@crdb_skip_scs
-def test_quote_stable_despite_deranged_libpq(conn):
+@pytest.mark.parametrize("dummy", [crdb_scs_off("off")])
+def test_quote_stable_despite_deranged_libpq(conn, dummy):
# Verify the libpq behaviour of PQescapeString using the last setting seen.
# Check that we are not affected by it.
good_str = " E'\\\\'"