22 #include "../postgis_config.h"
24 #if POSTGIS_PGSQL_VERSION >= 120
29 #include "access/htup_details.h"
30 #include "access/stratnum.h"
31 #include "catalog/namespace.h"
32 #include "catalog/pg_opfamily.h"
33 #include "catalog/pg_type_d.h"
34 #include "catalog/pg_am_d.h"
35 #include "nodes/supportnodes.h"
36 #include "nodes/nodeFuncs.h"
37 #include "nodes/makefuncs.h"
38 #include "optimizer/optimizer.h"
39 #include "parser/parse_func.h"
40 #include "utils/array.h"
41 #include "utils/builtins.h"
42 #include "utils/lsyscache.h"
43 #include "utils/numeric.h"
44 #include "utils/syscache.h"
48 #include "lwgeom_pg.h"
51 Datum postgis_index_supportfn(PG_FUNCTION_ARGS);
59 ST_INTERSECTS_IDX = 0,
64 ST_3DINTERSECTS_IDX = 5,
65 ST_CONTAINSPROPERLY_IDX = 6,
70 ST_DFULLYWITHIN_IDX = 11,
71 ST_3DDWITHIN_IDX = 12,
72 ST_3DDFULLYWITHIN_IDX = 13,
73 ST_LINECROSSINGDIRECTION_IDX = 14,
74 ST_ORDERINGEQUALS_IDX = 15,
78 static const int16 GeometryStrategies[] = {
79 [ST_INTERSECTS_IDX] = RTOverlapStrategyNumber,
80 [ST_DWITHIN_IDX] = RTOverlapStrategyNumber,
81 [ST_CONTAINS_IDX] = RTContainsStrategyNumber,
82 [ST_WITHIN_IDX] = RTContainedByStrategyNumber,
83 [ST_TOUCHES_IDX] = RTOverlapStrategyNumber,
84 [ST_3DINTERSECTS_IDX] = RTOverlapStrategyNumber,
85 [ST_CONTAINSPROPERLY_IDX] = RTContainsStrategyNumber,
86 [ST_COVEREDBY_IDX] = RTContainedByStrategyNumber,
87 [ST_OVERLAPS_IDX] = RTOverlapStrategyNumber,
88 [ST_COVERS_IDX] = RTContainsStrategyNumber,
89 [ST_CROSSES_IDX] = RTOverlapStrategyNumber,
90 [ST_DFULLYWITHIN_IDX] = RTOverlapStrategyNumber,
91 [ST_3DDWITHIN_IDX] = RTOverlapStrategyNumber,
92 [ST_3DDFULLYWITHIN_IDX] = RTOverlapStrategyNumber,
93 [ST_LINECROSSINGDIRECTION_IDX] = RTOverlapStrategyNumber,
94 [ST_ORDERINGEQUALS_IDX] = RTSameStrategyNumber,
95 [ST_EQUALS_IDX] = RTSameStrategyNumber
99 static const int16 GeographyStrategies[] = {
100 [ST_INTERSECTS_IDX] = RTOverlapStrategyNumber,
101 [ST_DWITHIN_IDX] = RTOverlapStrategyNumber,
102 [ST_CONTAINS_IDX] = InvalidStrategy,
103 [ST_WITHIN_IDX] = InvalidStrategy,
104 [ST_TOUCHES_IDX] = InvalidStrategy,
105 [ST_3DINTERSECTS_IDX] = InvalidStrategy,
106 [ST_CONTAINSPROPERLY_IDX] = InvalidStrategy,
107 [ST_COVEREDBY_IDX] = RTOverlapStrategyNumber,
108 [ST_OVERLAPS_IDX] = InvalidStrategy,
109 [ST_COVERS_IDX] = RTOverlapStrategyNumber,
110 [ST_CROSSES_IDX] = InvalidStrategy,
111 [ST_DFULLYWITHIN_IDX] = InvalidStrategy,
112 [ST_3DDWITHIN_IDX] = InvalidStrategy,
113 [ST_3DDFULLYWITHIN_IDX] = InvalidStrategy,
114 [ST_LINECROSSINGDIRECTION_IDX] = InvalidStrategy,
115 [ST_ORDERINGEQUALS_IDX] = InvalidStrategy,
116 [ST_EQUALS_IDX] = InvalidStrategy
120 get_strategy_by_type(Oid first_type, uint16_t index)
122 if (first_type == postgis_oid(GEOMETRYOID))
124 return GeometryStrategies[index];
127 if (first_type == postgis_oid(GEOGRAPHYOID))
129 return GeographyStrategies[index];
132 return InvalidStrategy;
157 static const IndexableFunction IndexableFunctions[] = {
158 {
"st_intersects", ST_INTERSECTS_IDX, 2, 0},
159 {
"st_dwithin", ST_DWITHIN_IDX, 3, 3},
160 {
"st_contains", ST_CONTAINS_IDX, 2, 0},
161 {
"st_within", ST_WITHIN_IDX, 2, 0},
162 {
"st_touches", ST_TOUCHES_IDX, 2, 0},
163 {
"st_3dintersects", ST_3DINTERSECTS_IDX, 2, 0},
164 {
"st_containsproperly", ST_CONTAINSPROPERLY_IDX, 2, 0},
165 {
"st_coveredby", ST_COVEREDBY_IDX, 2, 0},
166 {
"st_overlaps", ST_OVERLAPS_IDX, 2, 0},
167 {
"st_covers", ST_COVERS_IDX, 2, 0},
168 {
"st_crosses", ST_CROSSES_IDX, 2, 0},
169 {
"st_dfullywithin", ST_DFULLYWITHIN_IDX, 3, 3},
170 {
"st_3ddwithin", ST_3DDWITHIN_IDX, 3, 3},
171 {
"st_3ddfullywithin", ST_3DDFULLYWITHIN_IDX, 3, 3},
172 {
"st_linecrossingdirection", ST_LINECROSSINGDIRECTION_IDX, 2, 0},
173 {
"st_orderingequals", ST_ORDERINGEQUALS_IDX, 2, 0},
174 {
"st_equals", ST_EQUALS_IDX, 2, 0},
186 needsSpatialIndex(Oid funcid, IndexableFunction *idxfn)
188 const IndexableFunction *idxfns = IndexableFunctions;
189 const char *fn_name = get_func_name(funcid);
193 if(strcmp(idxfns->fn_name, fn_name) == 0)
200 while (idxfns->fn_name);
212 opFamilyAmOid(Oid opfamilyoid)
214 Form_pg_opfamily familyform;
217 HeapTuple familytup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfamilyoid));
218 if (!HeapTupleIsValid(familytup))
219 elog(ERROR,
"cache lookup failed for operator family %u", opfamilyoid);
220 familyform = (Form_pg_opfamily) GETSTRUCT(familytup);
221 opfamilyam = familyform->opfmethod;
224 ReleaseSysCache(familytup);
235 expandFunctionOid(Oid geotype, Oid callingfunc)
237 const Oid radiustype = FLOAT8OID;
238 const Oid expandfn_args[2] = {geotype, radiustype};
239 const bool noError =
true;
241 char *nspname = get_namespace_name(get_func_namespace(callingfunc));
242 List *expandfn_name = list_make2(makeString(nspname), makeString(
"st_expand"));
243 Oid expandfn_oid = LookupFuncName(expandfn_name, 2, expandfn_args, noError);
244 if (expandfn_oid == InvalidOid)
252 expandfn_name = list_make2(makeString(nspname), makeString(
"_st_expand"));
253 expandfn_oid = LookupFuncName(expandfn_name, 2, expandfn_args, noError);
254 if (expandfn_oid == InvalidOid)
255 elog(ERROR,
"%s: unable to lookup 'st_expand(Oid[%u], Oid[%u])'", __func__, geotype, radiustype);
277 Datum postgis_index_supportfn(PG_FUNCTION_ARGS)
279 Node *rawreq = (Node *) PG_GETARG_POINTER(0);
286 postgis_initialize_cache(fcinfo);
288 if (IsA(rawreq, SupportRequestSelectivity))
290 SupportRequestSelectivity *req = (SupportRequestSelectivity *) rawreq;
300 POSTGIS_DEBUGF(2,
"%s: got selectivity %g", __func__, req->selectivity);
301 PG_RETURN_POINTER(req);
308 if (IsA(rawreq, SupportRequestIndexCondition))
310 SupportRequestIndexCondition *req = (SupportRequestIndexCondition *) rawreq;
312 if (is_funcclause(req->node))
314 FuncExpr *clause = (FuncExpr *) req->node;
315 Oid funcid = clause->funcid;
316 IndexableFunction idxfn = {NULL, 0, 0, 0};
317 Oid opfamilyoid = req->opfamily;
319 if (needsSpatialIndex(funcid, &idxfn))
321 int nargs = list_length(clause->args);
322 Node *leftarg, *rightarg;
323 Oid leftdatatype, rightdatatype, oproid;
324 bool swapped =
false;
333 Oid opfamilyam = opFamilyAmOid(opfamilyoid);
334 if (opfamilyam != GIST_AM_OID &&
335 opfamilyam != SPGIST_AM_OID &&
336 opfamilyam != BRIN_AM_OID)
338 PG_RETURN_POINTER((Node *)NULL);
345 if (req->indexarg > 1)
346 PG_RETURN_POINTER((Node *)NULL);
351 if (nargs < 2 || nargs < idxfn.expand_arg)
352 elog(ERROR,
"%s: associated with function with %d arguments", __func__, nargs);
364 if (req->indexarg == 0)
366 leftarg = linitial(clause->args);
367 rightarg = lsecond(clause->args);
371 rightarg = linitial(clause->args);
372 leftarg = lsecond(clause->args);
380 leftdatatype = exprType(leftarg);
381 rightdatatype = exprType(rightarg);
388 oproid = get_opfamily_member(opfamilyoid,
391 get_strategy_by_type(leftdatatype, idxfn.index));
392 if (!OidIsValid(oproid))
394 "no spatial operator found for '%s': opfamily %u type %d",
406 if (idxfn.expand_arg)
409 Node *radiusarg = (Node *) list_nth(clause->args, idxfn.expand_arg-1);
410 Oid expandfn_oid = expandFunctionOid(rightdatatype, clause->funcid);
412 FuncExpr *expandexpr = makeFuncExpr(expandfn_oid, rightdatatype,
413 list_make2(rightarg, radiusarg),
414 InvalidOid, InvalidOid, COERCE_EXPLICIT_CALL);
420 if (!is_pseudo_constant_for_index((Node*)expandexpr, req->index))
421 PG_RETURN_POINTER((Node*)NULL);
424 expr = make_opclause(oproid, BOOLOID,
false,
425 (Expr *) leftarg, (Expr *) expandexpr,
426 InvalidOid, InvalidOid);
428 ret = (Node *)(list_make1(expr));
443 if (!is_pseudo_constant_for_index(rightarg, req->index))
444 PG_RETURN_POINTER((Node*)NULL);
453 oproid = get_commutator(oproid);
454 if (!OidIsValid(oproid))
455 PG_RETURN_POINTER((Node *)NULL);
458 expr = make_opclause(oproid, BOOLOID,
false,
459 (Expr *) leftarg, (Expr *) rightarg,
460 InvalidOid, InvalidOid);
462 ret = (Node *)(list_make1(expr));
472 PG_RETURN_POINTER(ret);
476 elog(WARNING,
"support function '%s' called from unsupported spatial function", __func__);
481 PG_RETURN_POINTER(ret);
PG_FUNCTION_INFO_V1(geom2d_brin_inclusion_add_value)
float8 gserialized_joinsel_internal(PlannerInfo *root, List *args, JoinType jointype, int mode)
float8 gserialized_sel_internal(PlannerInfo *root, List *args, int varRelid, int mode)
This function should return an estimation of the number of rows returned by a query involving an over...
This library is the generic geometry handling section of PostGIS.