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
11 changes: 8 additions & 3 deletions parser/compositions.py
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,7 @@ def attach_compositions(idl, sql_src):


_CAST_CALL = re.compile(r"^\s*(\w+)\s*\(\s*(\w+)\s*\)\s*$")
_C_LITERAL = re.compile(r"^(?:true|false|-?\d+(?:\.\d+)?)$")


def attach_wrapper_compositions(idl, mdb_src, sql_src, meos_src):
Expand All @@ -514,7 +515,9 @@ def attach_wrapper_compositions(idl, mdb_src, sql_src, meos_src):
body cannot reach. Each signature is traced to the wrapper whose CREATE FUNCTION
states it (#_signature_wrapper of parser/boundargs.py) and each argument of the call to
the SQL argument it carries (#_caller_index); a cast is a public catalog function of
one parameter. A signature whose wrapper casts nothing stays where it is."""
one parameter. A C literal the wrapper passes, as ``true`` for the ``spheroid`` of
``edwithin_tgeo_geo``, is a value operand. A signature whose wrapper casts nothing
stays where it is."""
from parser.boundargs import (_call_args, _caller_index, _signature_wrapper,
extract_wrappers)
from parser.sqlfn import _meos_to_mdb, _wrapper_sql_sigs
Expand Down Expand Up @@ -545,13 +548,15 @@ def attach_wrapper_compositions(idl, mdb_src, sql_src, meos_src):
r"(?<![\w.>])" + re.escape(a) + r"\s*=(?!=)\s*([^;]+);", body)]
hit = _CAST_CALL.match(rhs[0]) if len(rhs) == 1 else None
cast = hit.group(1) if hit else None
if cast in public and len(public[cast].get("params") or ()) == 1:
if _C_LITERAL.match(a):
operands.append({"value": a, "param": p})
elif cast in public and len(public[cast].get("params") or ()) == 1:
operands.append({"arg": _caller_index(body, hit.group(2)),
"casts": [cast], "param": p})
cast_seen = True
else:
operands.append({"arg": _caller_index(body, a), "param": p})
if not cast_seen or any(o["arg"] is None for o in operands):
if not cast_seen or any("arg" in o and o["arg"] is None for o in operands):
operands = None
if operands is None:
keep.append(sig)
Expand Down
46 changes: 43 additions & 3 deletions tests/test_compositions.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,18 @@ def test_a_cast_no_create_cast_declares_stops_the_catalog(self):
int result = eintersects_tgeo_geo(temp, gs);
PG_RETURN_BOOL(result ? true : false);
}

Datum
Edwithin_tpose_geo(PG_FUNCTION_ARGS)
{
Temporal *temp = PG_GETARG_TEMPORAL_P(0);
GSERIALIZED *gs = PG_GETARG_GSERIALIZED_P(1);
double dist = PG_GETARG_FLOAT8(2);
Temporal *tpoint = tpose_to_tpoint(temp);
int result = edwithin_tgeo_geo(tpoint, gs, dist, true);
pfree(tpoint);
PG_RETURN_BOOL(result ? true : false);
}
'''

CAST_SQL = '''
Expand All @@ -347,6 +359,11 @@ def test_a_cast_no_create_cast_declares_stops_the_catalog(self):
AS 'MODULE_PATHNAME', 'Eintersects_tgeo_geo'
SUPPORT tspatial_supportfn
LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE FUNCTION eDwithin(tpose, geometry, float)
RETURNS boolean
AS 'MODULE_PATHNAME', 'Edwithin_tpose_geo'
SUPPORT tspatial_supportfn
LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
'''

CAST_MEOS = '''
Expand All @@ -359,6 +376,17 @@ def test_a_cast_no_create_cast_declares_stops_the_catalog(self):
{
return 0;
}

/**
* @brief Return 1 if a temporal geo is ever within a distance of a geometry
* @csqlfn #Edwithin_tpose_geo()
*/
int
edwithin_tgeo_geo(const Temporal *temp, const GSERIALIZED *gs, double dist,
bool spheroid)
{
return 0;
}
'''


Expand Down Expand Up @@ -386,20 +414,32 @@ def _attach(self):
"sqlSignatures": [{"args": ["tgeompoint", "geometry"], "ret": "boolean"},
{"args": ["tpose", "geometry"], "ret": "boolean"}]},
{"name": "tpose_to_tpoint", "api": "public", "params": [{"name": "temp"}],
"sqlSignatures": []}],
"sqlSignatures": []},
{"name": "edwithin_tgeo_geo", "api": "public", "sqlfn": "eDwithin",
"params": [{"name": "temp"}, {"name": "gs"}, {"name": "dist"},
{"name": "spheroid"}],
"sqlSignatures": [{"args": ["tpose", "geometry", "float"], "ret": "boolean"}]}],
"compositions": []}
return attach_wrapper_compositions(idl, root / "src", root / "sql", root / "meos")

def test_the_cast_wrapper_states_a_composition(self):
idl, n = self._attach()
self.assertEqual(n, 1)
self.assertEqual(idl["compositions"], [{
self.assertEqual(n, 2)
self.assertEqual(idl["compositions"][:1], [{
"sqlName": "eIntersects", "args": ["tpose", "geometry"], "required": 2,
"argDefaults": [None, None], "ret": "boolean",
"operands": [{"arg": 0, "casts": ["tpose_to_tpoint"], "param": "temp"},
{"arg": 1, "param": "gs"}],
"call": "eintersects_tgeo_geo"}])

def test_a_literal_argument_is_a_value_operand(self):
idl, _ = self._attach()
self.assertEqual(idl["compositions"][1]["operands"], [
{"arg": 0, "casts": ["tpose_to_tpoint"], "param": "temp"},
{"arg": 1, "param": "gs"}, {"arg": 2, "param": "dist"},
{"value": "true", "param": "spheroid"}])
self.assertEqual(idl["functions"][2]["sqlSignatures"], [])

def test_the_wrapper_casting_nothing_keeps_its_signature(self):
idl, _ = self._attach()
self.assertEqual([s["args"] for s in idl["functions"][0]["sqlSignatures"]],
Expand Down
Loading