From aa539d9da9e18e2453182c97793827569be21da2 Mon Sep 17 00:00:00 2001 From: Emre Hasegeli Date: Sun, 22 Mar 2015 17:41:26 +0100 Subject: [PATCH 5/7] box vs point operators --- src/backend/utils/adt/geo_ops.c | 115 ++++++++++++++++++++++++++++--- src/bin/initdb/initdb.c | 1 + src/include/catalog/pg_operator.h | 20 ++++++ src/include/catalog/pg_proc.h | 8 +++ src/include/utils/geo_decls.h | 8 +++ src/test/regress/expected/opr_sanity.out | 4 +- src/test/regress/sql/opr_sanity.sql | 4 +- 7 files changed, 148 insertions(+), 12 deletions(-) diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c index 39a7855..382d925 100644 --- a/src/backend/utils/adt/geo_ops.c +++ b/src/backend/utils/adt/geo_ops.c @@ -767,20 +767,125 @@ Datum box_ge(PG_FUNCTION_ARGS) { BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1); PG_RETURN_BOOL(FPge(box_ar(box1), box_ar(box2))); } /*---------------------------------------------------------- + * Relational operators for BOX vs Point + *---------------------------------------------------------*/ + +/* box_left_pt - is box strictly left of point? + */ +Datum +box_left_pt(PG_FUNCTION_ARGS) +{ + BOX *box = PG_GETARG_BOX_P(0); + Point *pt = PG_GETARG_POINT_P(1); + + PG_RETURN_BOOL(box->high.x < pt->x); +} + +/* box_overleft_pt - is the right edge of box at or left of point? + */ +Datum +box_overleft_pt(PG_FUNCTION_ARGS) +{ + BOX *box = PG_GETARG_BOX_P(0); + Point *pt = PG_GETARG_POINT_P(1); + + PG_RETURN_BOOL(box->low.x <= pt->x); +} + +/* box_right_pt - is box strictly right of point? + */ +Datum +box_right_pt(PG_FUNCTION_ARGS) +{ + BOX *box = PG_GETARG_BOX_P(0); + Point *pt = PG_GETARG_POINT_P(1); + + PG_RETURN_BOOL(box->low.x > pt->x); +} + +/* box_overright_pt - is the left edge of box at or right of point? + */ +Datum +box_overright_pt(PG_FUNCTION_ARGS) +{ + BOX *box = PG_GETARG_BOX_P(0); + Point *pt = PG_GETARG_POINT_P(1); + + PG_RETURN_BOOL(box->high.x >= pt->x); +} + +/* box_below_pt - is box strictly below point? + */ +Datum +box_below_pt(PG_FUNCTION_ARGS) +{ + BOX *box = PG_GETARG_BOX_P(0); + Point *pt = PG_GETARG_POINT_P(1); + + PG_RETURN_BOOL(box->high.y < pt->y); +} + +/* box_overbelow_pt - is the upper edge of box at or below point? + */ +Datum +box_overbelow_pt(PG_FUNCTION_ARGS) +{ + BOX *box = PG_GETARG_BOX_P(0); + Point *pt = PG_GETARG_POINT_P(1); + + PG_RETURN_BOOL(box->low.y <= pt->y); +} + +/* box_above_pt - is box strictly above point? + */ +Datum +box_above_pt(PG_FUNCTION_ARGS) +{ + BOX *box = PG_GETARG_BOX_P(0); + Point *pt = PG_GETARG_POINT_P(1); + + PG_RETURN_BOOL(box->low.y > pt->y); +} + +/* box_overabove_pt - is the lower edge of box at or above point? + */ +Datum +box_overabove_pt(PG_FUNCTION_ARGS) +{ + BOX *box = PG_GETARG_BOX_P(0); + Point *pt = PG_GETARG_POINT_P(1); + + PG_RETURN_BOOL(box->high.y >= pt->y); +} + +/* box_contain_pt - does box contain point? + */ +Datum +box_contain_pt(PG_FUNCTION_ARGS) +{ + BOX *box = PG_GETARG_BOX_P(0); + Point *pt = PG_GETARG_POINT_P(1); + + PG_RETURN_BOOL(pt->x <= box->high.x && pt->x >= box->low.x && + pt->y <= box->high.y && pt->y >= box->low.y); +} + + +/*---------------------------------------------------------- * "Arithmetic" operators on boxes. *---------------------------------------------------------*/ /* box_area - returns the area of the box. */ Datum box_area(PG_FUNCTION_ARGS) { BOX *box = PG_GETARG_BOX_P(0); @@ -3205,30 +3310,20 @@ on_ps_internal(Point *pt, LSEG *lseg) Datum on_pb(PG_FUNCTION_ARGS) { Point *pt = PG_GETARG_POINT_P(0); BOX *box = PG_GETARG_BOX_P(1); PG_RETURN_BOOL(pt->x <= box->high.x && pt->x >= box->low.x && pt->y <= box->high.y && pt->y >= box->low.y); } -Datum -box_contain_pt(PG_FUNCTION_ARGS) -{ - BOX *box = PG_GETARG_BOX_P(0); - Point *pt = PG_GETARG_POINT_P(1); - - PG_RETURN_BOOL(pt->x <= box->high.x && pt->x >= box->low.x && - pt->y <= box->high.y && pt->y >= box->low.y); -} - /* on_ppath - * Whether a point lies within (on) a polyline. * If open, we have to (groan) check each segment. * (uses same algorithm as for point intersecting segment - tgl 1997-07-09) * If closed, we use the old O(n) ray method for point-in-polygon. * The ray is horizontal, from pt out to the right. * Each segment that crosses the ray counts as an * intersection; note that an endpoint or edge may touch * but not cross. * (we can do p-in-p in lg(n), but it takes preprocessing) diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index 8694920..e60528e 100644 --- a/src/bin/initdb/initdb.c +++ b/src/bin/initdb/initdb.c @@ -1875,20 +1875,21 @@ setup_description(void) /* Create default descriptions for operator implementation functions */ PG_CMD_PUTS("WITH funcdescs AS ( " "SELECT p.oid as p_oid, oprname, " "coalesce(obj_description(o.oid, 'pg_operator'),'') as opdesc " "FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid ) " "INSERT INTO pg_description " " SELECT p_oid, 'pg_proc'::regclass, 0, " " 'implementation of ' || oprname || ' operator' " " FROM funcdescs " " WHERE opdesc NOT LIKE 'deprecated%' AND " + " opdesc NOT LIKE 'same as %' AND " " NOT EXISTS (SELECT 1 FROM pg_description " " WHERE objoid = p_oid AND classoid = 'pg_proc'::regclass);\n"); PG_CMD_CLOSE; check_ok(); } #ifdef HAVE_LOCALE_T /* diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h index e22eb27..2984242 100644 --- a/src/include/catalog/pg_operator.h +++ b/src/include/catalog/pg_operator.h @@ -252,22 +252,42 @@ DESCR("is above"); DATA(insert OID = 507 ( "<<" PGNSP PGUID b f f 600 600 16 0 0 point_left positionsel positionjoinsel )); DESCR("is left of"); DATA(insert OID = 508 ( ">>" PGNSP PGUID b f f 600 600 16 0 0 point_right positionsel positionjoinsel )); DESCR("is right of"); DATA(insert OID = 509 ( "<^" PGNSP PGUID b f f 600 600 16 0 0 point_below positionsel positionjoinsel )); DESCR("is below"); DATA(insert OID = 510 ( "~=" PGNSP PGUID b f f 600 600 16 510 713 point_eq eqsel eqjoinsel )); DESCR("same as"); DATA(insert OID = 511 ( "<@" PGNSP PGUID b f f 600 603 16 433 0 on_pb contsel contjoinsel )); DESCR("point inside box"); +DATA(insert OID = 4092 ( "<<" PGNSP PGUID b f f 603 600 16 0 0 box_left_pt positionsel positionjoinsel )); +DESCR("is left of"); +DATA(insert OID = 4093 ( "&<" PGNSP PGUID b f f 603 600 16 0 0 box_overleft_pt positionsel positionjoinsel )); +DESCR("overlaps or is left of"); +DATA(insert OID = 4094 ( ">>" PGNSP PGUID b f f 603 600 16 0 0 box_right_pt positionsel positionjoinsel )); +DESCR("is right of"); +DATA(insert OID = 4095 ( "&>" PGNSP PGUID b f f 603 600 16 0 0 box_overright_pt positionsel positionjoinsel )); +DESCR("overlaps or is right of"); +DATA(insert OID = 4096 ( "<<|" PGNSP PGUID b f f 603 600 16 0 0 box_below_pt positionsel positionjoinsel )); +DESCR("is below"); +DATA(insert OID = 4097 ( "&<|" PGNSP PGUID b f f 603 600 16 0 0 box_overbelow_pt positionsel positionjoinsel )); +DESCR("overlaps or is below"); +DATA(insert OID = 4098 ( "|>>" PGNSP PGUID b f f 603 600 16 0 0 box_above_pt positionsel positionjoinsel )); +DESCR("is above"); +DATA(insert OID = 4099 ( "|&>" PGNSP PGUID b f f 603 600 16 0 0 box_overabove_pt positionsel positionjoinsel )); +DESCR("overlaps or is above"); DATA(insert OID = 433 ( "@>" PGNSP PGUID b f f 603 600 16 511 0 box_contain_pt contsel contjoinsel )); DESCR("contains"); +DATA(insert OID = 4100 ( "&&" PGNSP PGUID b f f 603 600 16 4101 0 box_contain_pt contsel contjoinsel )); +DESCR("same as @>"); +DATA(insert OID = 4101 ( "&&" PGNSP PGUID b f f 600 603 16 4100 0 on_pb contsel contjoinsel )); +DESCR("same as <@"); DATA(insert OID = 512 ( "<@" PGNSP PGUID b f f 600 602 16 755 0 on_ppath - - )); DESCR("point within closed path, or point on open path"); DATA(insert OID = 513 ( "@@" PGNSP PGUID l f f 0 603 600 0 0 box_center - - )); DESCR("center of"); DATA(insert OID = 514 ( "*" PGNSP PGUID b f f 23 23 23 514 0 int4mul - - )); DESCR("multiply"); DATA(insert OID = 517 ( "<->" PGNSP PGUID b f f 600 600 701 517 0 point_distance - - )); DESCR("distance between"); DATA(insert OID = 518 ( "<>" PGNSP PGUID b f f 23 23 16 518 96 int4ne neqsel neqjoinsel )); DESCR("not equal"); diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index bd67d72..2c750d4 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -336,20 +336,28 @@ DATA(insert OID = 182 ( int24mi PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 23 DATA(insert OID = 183 ( int42mi PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 23 "23 21" _null_ _null_ _null_ _null_ _null_ int42mi _null_ _null_ _null_ )); DATA(insert OID = 184 ( oideq PGNSP PGUID 12 1 0 0 0 f f f t t f i 2 0 16 "26 26" _null_ _null_ _null_ _null_ _null_ oideq _null_ _null_ _null_ )); DATA(insert OID = 185 ( oidne PGNSP PGUID 12 1 0 0 0 f f f t t f i 2 0 16 "26 26" _null_ _null_ _null_ _null_ _null_ oidne _null_ _null_ _null_ )); DATA(insert OID = 186 ( box_same PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 603" _null_ _null_ _null_ _null_ _null_ box_same _null_ _null_ _null_ )); DATA(insert OID = 187 ( box_contain PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 603" _null_ _null_ _null_ _null_ _null_ box_contain _null_ _null_ _null_ )); DATA(insert OID = 188 ( box_left PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 603" _null_ _null_ _null_ _null_ _null_ box_left _null_ _null_ _null_ )); DATA(insert OID = 189 ( box_overleft PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 603" _null_ _null_ _null_ _null_ _null_ box_overleft _null_ _null_ _null_ )); DATA(insert OID = 190 ( box_overright PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 603" _null_ _null_ _null_ _null_ _null_ box_overright _null_ _null_ _null_ )); DATA(insert OID = 191 ( box_right PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 603" _null_ _null_ _null_ _null_ _null_ box_right _null_ _null_ _null_ )); DATA(insert OID = 192 ( box_contained PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 603" _null_ _null_ _null_ _null_ _null_ box_contained _null_ _null_ _null_ )); +DATA(insert OID = 4083 ( box_left_pt PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 600" _null_ _null_ _null_ _null_ _null_ box_left_pt _null_ _null_ _null_ )); +DATA(insert OID = 4084 ( box_overleft_pt PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 600" _null_ _null_ _null_ _null_ _null_ box_overleft_pt _null_ _null_ _null_ )); +DATA(insert OID = 4085 ( box_right_pt PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 600" _null_ _null_ _null_ _null_ _null_ box_right_pt _null_ _null_ _null_ )); +DATA(insert OID = 4086 ( box_overright_pt PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 600" _null_ _null_ _null_ _null_ _null_ box_overright_pt _null_ _null_ _null_ )); +DATA(insert OID = 4087 ( box_below_pt PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 600" _null_ _null_ _null_ _null_ _null_ box_below_pt _null_ _null_ _null_ )); +DATA(insert OID = 4088 ( box_overbelow_pt PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 600" _null_ _null_ _null_ _null_ _null_ box_overbelow_pt _null_ _null_ _null_ )); +DATA(insert OID = 4089 ( box_above_pt PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 600" _null_ _null_ _null_ _null_ _null_ box_above_pt _null_ _null_ _null_ )); +DATA(insert OID = 4090 ( box_overabove_pt PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 600" _null_ _null_ _null_ _null_ _null_ box_overabove_pt _null_ _null_ _null_ )); DATA(insert OID = 193 ( box_contain_pt PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 600" _null_ _null_ _null_ _null_ _null_ box_contain_pt _null_ _null_ _null_ )); DATA(insert OID = 195 ( pg_node_tree_in PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 194 "2275" _null_ _null_ _null_ _null_ _null_ pg_node_tree_in _null_ _null_ _null_ )); DESCR("I/O"); DATA(insert OID = 196 ( pg_node_tree_out PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2275 "194" _null_ _null_ _null_ _null_ _null_ pg_node_tree_out _null_ _null_ _null_ )); DESCR("I/O"); DATA(insert OID = 197 ( pg_node_tree_recv PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 194 "2281" _null_ _null_ _null_ _null_ _null_ pg_node_tree_recv _null_ _null_ _null_ )); DESCR("I/O"); DATA(insert OID = 198 ( pg_node_tree_send PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 17 "194" _null_ _null_ _null_ _null_ _null_ pg_node_tree_send _null_ _null_ _null_ )); DESCR("I/O"); diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h index 4377baa..69a78e8 100644 --- a/src/include/utils/geo_decls.h +++ b/src/include/utils/geo_decls.h @@ -275,20 +275,28 @@ extern Datum box_overlap(PG_FUNCTION_ARGS); extern Datum box_left(PG_FUNCTION_ARGS); extern Datum box_overleft(PG_FUNCTION_ARGS); extern Datum box_right(PG_FUNCTION_ARGS); extern Datum box_overright(PG_FUNCTION_ARGS); extern Datum box_below(PG_FUNCTION_ARGS); extern Datum box_overbelow(PG_FUNCTION_ARGS); extern Datum box_above(PG_FUNCTION_ARGS); extern Datum box_overabove(PG_FUNCTION_ARGS); extern Datum box_contained(PG_FUNCTION_ARGS); extern Datum box_contain(PG_FUNCTION_ARGS); +extern Datum box_left_pt(PG_FUNCTION_ARGS); +extern Datum box_overleft_pt(PG_FUNCTION_ARGS); +extern Datum box_right_pt(PG_FUNCTION_ARGS); +extern Datum box_overright_pt(PG_FUNCTION_ARGS); +extern Datum box_below_pt(PG_FUNCTION_ARGS); +extern Datum box_overbelow_pt(PG_FUNCTION_ARGS); +extern Datum box_above_pt(PG_FUNCTION_ARGS); +extern Datum box_overabove_pt(PG_FUNCTION_ARGS); extern Datum box_contain_pt(PG_FUNCTION_ARGS); extern Datum box_below_eq(PG_FUNCTION_ARGS); extern Datum box_above_eq(PG_FUNCTION_ARGS); extern Datum box_lt(PG_FUNCTION_ARGS); extern Datum box_gt(PG_FUNCTION_ARGS); extern Datum box_eq(PG_FUNCTION_ARGS); extern Datum box_le(PG_FUNCTION_ARGS); extern Datum box_ge(PG_FUNCTION_ARGS); extern Datum box_area(PG_FUNCTION_ARGS); extern Datum box_width(PG_FUNCTION_ARGS); diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out index 6b248f2..200fd58 100644 --- a/src/test/regress/expected/opr_sanity.out +++ b/src/test/regress/expected/opr_sanity.out @@ -1068,54 +1068,56 @@ FROM pg_operator as p1 LEFT JOIN pg_description as d WHERE d.classoid IS NULL AND p1.oid <= 9999; oid | oprname -----+--------- (0 rows) -- Check that operators' underlying functions have suitable comments, -- namely 'implementation of XXX operator'. (Note: it's not necessary to -- put such comments into pg_proc.h; initdb will generate them as needed.) -- In some cases involving legacy names for operators, there are multiple -- operators referencing the same pg_proc entry, so ignore operators whose --- comments say they are deprecated. +-- comments say they are deprecated or same as other operator. -- We also have a few functions that are both operator support and meant to -- be called directly; those should have comments matching their operator. WITH funcdescs AS ( SELECT p.oid as p_oid, proname, o.oid as o_oid, obj_description(p.oid, 'pg_proc') as prodesc, 'implementation of ' || oprname || ' operator' as expecteddesc, obj_description(o.oid, 'pg_operator') as oprdesc FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid WHERE o.oid <= 9999 ) SELECT * FROM funcdescs WHERE prodesc IS DISTINCT FROM expecteddesc AND oprdesc NOT LIKE 'deprecated%' + AND oprdesc NOT LIKE 'same as %' AND prodesc IS DISTINCT FROM oprdesc; p_oid | proname | o_oid | prodesc | expecteddesc | oprdesc -------+---------+-------+---------+--------------+--------- (0 rows) -- Show all the operator-implementation functions that have their own -- comments. This should happen only in cases where the function and -- operator syntaxes are both documented at the user level. -- This should be a pretty short list; it's mostly legacy cases. WITH funcdescs AS ( SELECT p.oid as p_oid, proname, o.oid as o_oid, obj_description(p.oid, 'pg_proc') as prodesc, 'implementation of ' || oprname || ' operator' as expecteddesc, obj_description(o.oid, 'pg_operator') as oprdesc FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid WHERE o.oid <= 9999 ) SELECT p_oid, proname, prodesc FROM funcdescs WHERE prodesc IS DISTINCT FROM expecteddesc AND oprdesc NOT LIKE 'deprecated%' + AND oprdesc NOT LIKE 'same as %' ORDER BY 1; p_oid | proname | prodesc -------+-------------------------+------------------------------------------------- 378 | array_append | append element onto end of array 379 | array_prepend | prepend element onto front of array 1035 | aclinsert | add/update ACL item 1036 | aclremove | remove ACL item 1037 | aclcontains | contains 3217 | jsonb_extract_path | get value from jsonb with path elements 3940 | jsonb_extract_path_text | get value from jsonb as text with path elements diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql index 7159a83..2c20763 100644 --- a/src/test/regress/sql/opr_sanity.sql +++ b/src/test/regress/sql/opr_sanity.sql @@ -628,51 +628,53 @@ WHERE p1.oprjoin = p2.oid AND SELECT p1.oid, p1.oprname FROM pg_operator as p1 LEFT JOIN pg_description as d ON p1.tableoid = d.classoid and p1.oid = d.objoid and d.objsubid = 0 WHERE d.classoid IS NULL AND p1.oid <= 9999; -- Check that operators' underlying functions have suitable comments, -- namely 'implementation of XXX operator'. (Note: it's not necessary to -- put such comments into pg_proc.h; initdb will generate them as needed.) -- In some cases involving legacy names for operators, there are multiple -- operators referencing the same pg_proc entry, so ignore operators whose --- comments say they are deprecated. +-- comments say they are deprecated or same as other operator. -- We also have a few functions that are both operator support and meant to -- be called directly; those should have comments matching their operator. WITH funcdescs AS ( SELECT p.oid as p_oid, proname, o.oid as o_oid, obj_description(p.oid, 'pg_proc') as prodesc, 'implementation of ' || oprname || ' operator' as expecteddesc, obj_description(o.oid, 'pg_operator') as oprdesc FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid WHERE o.oid <= 9999 ) SELECT * FROM funcdescs WHERE prodesc IS DISTINCT FROM expecteddesc AND oprdesc NOT LIKE 'deprecated%' + AND oprdesc NOT LIKE 'same as %' AND prodesc IS DISTINCT FROM oprdesc; -- Show all the operator-implementation functions that have their own -- comments. This should happen only in cases where the function and -- operator syntaxes are both documented at the user level. -- This should be a pretty short list; it's mostly legacy cases. WITH funcdescs AS ( SELECT p.oid as p_oid, proname, o.oid as o_oid, obj_description(p.oid, 'pg_proc') as prodesc, 'implementation of ' || oprname || ' operator' as expecteddesc, obj_description(o.oid, 'pg_operator') as oprdesc FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid WHERE o.oid <= 9999 ) SELECT p_oid, proname, prodesc FROM funcdescs WHERE prodesc IS DISTINCT FROM expecteddesc AND oprdesc NOT LIKE 'deprecated%' + AND oprdesc NOT LIKE 'same as %' ORDER BY 1; -- **************** pg_aggregate **************** -- Look for illegal values in pg_aggregate fields. SELECT ctid, aggfnoid::oid FROM pg_aggregate as p1 WHERE aggfnoid = 0 OR aggtransfn = 0 OR -- 2.3.2