Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion parser/boundargs.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@
definition of each function it calls is read, and a function whose parameter names equal
a member's is the generic that member wraps: its literals bind to the member by parameter
name.

A function MEOS takes from PostgreSQL is public under PostgreSQL's name only in MEOS, where
it calls its ``pg_`` twin, which takes the same parameters in the same order; the extension,
which links PostgreSQL's own function of that name, calls the twin:
``Jsonb_path_exists_common`` calls ``pg_jsonb_path_exists(jb, jp, vars, silent, tz)``
for ``jsonb_path_exists``. A call to the twin is read as a call to the member.
"""
from __future__ import annotations

Expand Down Expand Up @@ -310,7 +316,7 @@ def _wrapper_bound(body: str, func: dict, drift: list,
array length (``@param[in] count``), an aggregate state (``@param[in,out] state``) —
never a hard-coded literal, so it is skipped systematically. Only a bare identifier
for an UNDOCUMENTED parameter is reported as drift (the exceptional manual gap)."""
args = _call_args(body, func["name"])
args = _call_args(body, func["name"]) or _call_args(body, "pg_" + func["name"])
if not args:
return {}
subst = subst or {}
Expand Down
79 changes: 79 additions & 0 deletions tests/test_boundargs.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,85 @@ def test_caller_read_args_stay_out(self):
self.assertNotIn("key", bound)


PG_TWIN = """
static Datum
Jsonb_path_exists_common(FunctionCallInfo fcinfo, bool tz)
{
Jsonb *jb = PG_GETARG_JSONB_P(0);
JsonPath *jp = PG_GETARG_JSONPATH_P(1);
Jsonb *vars = PG_GETARG_JSONB_P(2);
bool silent = PG_GETARG_BOOL(3);
int result = pg_jsonb_path_exists(jb, jp, vars, silent, tz);
PG_RETURN_BOOL(result == 1);
}

PGDLLEXPORT Datum Jsonb_path_exists(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(Jsonb_path_exists);
Datum
Jsonb_path_exists(PG_FUNCTION_ARGS)
{
return Jsonb_path_exists_common(fcinfo, false);
}

PGDLLEXPORT Datum Jsonb_path_exists_tz(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(Jsonb_path_exists_tz);
Datum
Jsonb_path_exists_tz(PG_FUNCTION_ARGS)
{
return Jsonb_path_exists_common(fcinfo, true);
}

static Datum
Jsonb_path_match_common(FunctionCallInfo fcinfo, bool tz)
{
Jsonb *jb = PG_GETARG_JSONB_P(0);
JsonPath *jp = PG_GETARG_JSONPATH_P(1);
bool result = path_match_other(jb, jp, tz);
PG_RETURN_BOOL(result);
}

PGDLLEXPORT Datum Jsonb_path_match(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(Jsonb_path_match);
Datum
Jsonb_path_match(PG_FUNCTION_ARGS)
{
return Jsonb_path_match_common(fcinfo, false);
}
"""


class PgTwinTests(unittest.TestCase):
"""A wrapper reaching a function MEOS takes from PostgreSQL through its pg_ twin, the
delegation #DelegatingWrapperTests reads, whose helper calls the twin."""

def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
src = Path(self.tmp.name) / "src"
src.mkdir()
(src / "twin.c").write_text(PG_TWIN)

def tearDown(self):
self.tmp.cleanup()

def _idl(self, name, wrapper):
return {"functions": [
{"name": name, "mdbC": wrapper,
"params": [{"name": "jb"}, {"name": "jp"}, {"name": "vars"},
{"name": "silent"}, {"name": "tz"}]}]}

def test_the_twin_binds_the_literal_of_each_wrapper(self):
for wrapper, tz in (("Jsonb_path_exists", "false"), ("Jsonb_path_exists_tz", "true")):
idl, _, drift = merge_boundargs(self._idl("jsonb_path_exists", wrapper),
self.tmp.name)
self.assertEqual(idl["functions"][0]["shape"]["boundArgs"], {"tz": tz})
self.assertEqual(drift, [])

def test_a_callee_that_is_not_the_twin_binds_nothing(self):
idl, _, _ = merge_boundargs(self._idl("jsonb_path_match", "Jsonb_path_match"),
self.tmp.name)
self.assertNotIn("boundArgs", idl["functions"][0].get("shape") or {})


class BoundArgsTests(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
Expand Down
Loading