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
53 changes: 53 additions & 0 deletions parser/sqlfn.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@
_CSQLFN = re.compile(r"@csqlfn\b")
_CSQLFN_REF = re.compile(r"#(\w+)\s*\(\)")
_CSQLFN_END = re.compile(r"@\w|\*/")
# @csqlaggfn names the SQL AGGREGATE(s) a transition/combine/final function
# implements, following the standard PostgreSQL aggregate model
# (<aggregate>Transition / Combine / Final). Unlike @csqlfn — which points at a PG
# wrapper that then carries the @sqlfn (two hops) — @csqlaggfn is ONE hop: the
# #Name() reference IS the SQL aggregate-role name (#setUnionTransition()). A member
# shared by two aggregates (the spanset union finalfn) carries both, so collect all
# references (reusing _CSQLFN_REF / _CSQLFN_END, the same value grammar).
_CSQLAGGFN = re.compile(r"@csqlaggfn\b")
# After the doxygen close, the MEOS-C definition. The return type may sit on its
# own line (`bool\nleft_tpcbox_tpcbox(`) OR on the same line as the name
# (`bool tpcbox_eq(const TPCBox *box1, ...)`, the one-line predicate style). Match
Expand Down Expand Up @@ -185,6 +193,32 @@ def _meos_to_mdb(meos_src):
return out


def _meos_agg_names(meos_src):
"""MEOS-C aggregate function name -> ordered list of SQL aggregate-role names
(from @csqlaggfn). One hop: the #Name() references ARE the SQL names
(#setUnionTransition()), so there is no wrapper indirection to resolve — unlike
_meos_to_mdb, whose #Wrapper() references need a second _mdb_to_sql hop. A member
shared by two aggregates (spanset_union_finalfn) carries several names."""
out = {}
for cf in Path(meos_src).rglob("*.c"):
text = cf.read_text(errors="ignore")
for m in _CSQLAGGFN.finditer(text):
tail = text[m.end():]
end = _CSQLFN_END.search(tail)
value = tail[:end.start()] if end else tail
names = _CSQLFN_REF.findall(value)
if not names:
continue
fm = _FNDEF.search(text, m.end())
if not fm:
continue
lst = out.setdefault(fm.group(1), [])
for nm in names:
if nm not in lst:
lst.append(nm)
return out


def _mdb_to_sql(mdb_src):
"""MobilityDB-C wrapper name -> ordered list of (sqlfn, sqlop).

Expand Down Expand Up @@ -284,6 +318,25 @@ def attach_sqlfn_map(idl, meos_src, mdb_src, sql_src=None):
return idl, n, multi


def attach_aggfn_map(idl, meos_src):
"""Attach `sqlAgg` — the SQL aggregate-role name(s) each aggregate function
implements, read faithfully from @csqlaggfn in meos/src. This gives an
aggregate member its own catalog identity (setUnionTransition, spanUnionFinal)
distinct from the identically named binary set/span union FUNCTION, and lets a
binding reconstruct the standard PostgreSQL aggregate model (a <aggregate> with
its Transition / Combine / Final members) instead of guessing from name
suffixes. A member shared by two aggregates (spanset_union_finalfn) carries a
list. Faithful reader: the name is recorded verbatim, no derivation."""
a2n = _meos_agg_names(meos_src)
n = 0
for f in idl["functions"]:
names = a2n.get(f["name"])
if names:
f["sqlAgg"] = names
n += 1
return idl, n


# MEOS-C ever/always spatial-relationship functions are named <e|a><verb>_...; their
# @csqlfn must point at the matching <E|A><verb>_... wrapper. A copy-paste @csqlfn in
# meos/src (e.g. eintersects_tgeo_geo tagged #Aintersects_tgeo_geo) silently flips the
Expand Down
10 changes: 8 additions & 2 deletions run.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
from parser.nullable import merge_nullable
from parser.outparam import merge_outparams
from parser.enrich import enrich_idl
from parser.sqlfn import (attach_sqlfn_map, lint_ea_sqlfn, lint_positional_sqlfn,
lint_sqlfn_case_collisions)
from parser.sqlfn import (attach_sqlfn_map, attach_aggfn_map, lint_ea_sqlfn,
lint_positional_sqlfn, lint_sqlfn_case_collisions)
from parser.doxygroup import attach_groups
from parser.extractors import find_unlisted_foreign_structs
from parser.object_model import attach_object_model, find_mobilitydb_src
Expand Down Expand Up @@ -132,6 +132,12 @@ def main():
if MEOS_SRC.exists() and MDB_SRC.exists():
idl, nsql, sqlfn_multi = attach_sqlfn_map(idl, MEOS_SRC, MDB_SRC, SQL_SRC)
print(f"[4/4] Attached {nsql} @sqlfn SQL names", file=sys.stderr)
# Aggregate identity: @csqlaggfn names the SQL aggregate (setUnion /
# spanUnion / spansetUnion) each transition/combine/final function
# implements, so an aggregate member is distinguishable from the identically
# named binary set/span union function. One-hop, faithful to the source tag.
idl, nagg = attach_aggfn_map(idl, MEOS_SRC)
print(f" Attached {nagg} @csqlaggfn aggregate names", file=sys.stderr)
# Guard: a copy-paste @csqlfn in meos/src can point an ever/always function at
# the opposite-prefix wrapper (eintersects_* tagged #Aintersects_*), flipping its
# SQL name and breaking the binding overload dispatch. The parser is faithful, so
Expand Down
Loading