diff options
author | Alexander Korotkov <akorotkov@postgresql.org> | 2018-09-19 01:54:10 +0300 |
---|---|---|
committer | Alexander Korotkov <akorotkov@postgresql.org> | 2018-09-19 01:54:10 +0300 |
commit | 2a6368343ff43743ddd90d0f4c2d0ac03e18aa85 (patch) | |
tree | cfe7805a40c662e0962965aa1f263ec44e6d1eff /src/backend/access/index/indexam.c | |
parent | d0cfc3d6a44af1756ca5be8cb2414da7b8bf20d5 (diff) |
Add support for nearest-neighbor (KNN) searches to SP-GiST
Currently, KNN searches were supported only by GiST. SP-GiST also capable to
support them. This commit implements that support. SP-GiST scan stack is
replaced with queue, which serves as stack if no ordering is specified. KNN
support is provided for three SP-GIST opclasses: quad_point_ops, kd_point_ops
and poly_ops (catversion is bumped). Some common parts between GiST and SP-GiST
KNNs are extracted into separate functions.
Discussion: https://postgr.es/m/570825e8-47d0-4732-2bf6-88d67d2d51c8%40postgrespro.ru
Author: Nikita Glukhov, Alexander Korotkov based on GSoC work by Vlad Sterzhanov
Review: Andrey Borodin, Alexander Korotkov
Diffstat (limited to 'src/backend/access/index/indexam.c')
-rw-r--r-- | src/backend/access/index/indexam.c | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c index 22b5cc921f8..eade540ef5d 100644 --- a/src/backend/access/index/indexam.c +++ b/src/backend/access/index/indexam.c @@ -74,6 +74,7 @@ #include "access/transam.h" #include "access/xlog.h" #include "catalog/index.h" +#include "catalog/pg_type.h" #include "pgstat.h" #include "storage/bufmgr.h" #include "storage/lmgr.h" @@ -897,3 +898,72 @@ index_getprocinfo(Relation irel, return locinfo; } + +/* ---------------- + * index_store_float8_orderby_distances + * + * Convert AM distance function's results (that can be inexact) + * to ORDER BY types and save them into xs_orderbyvals/xs_orderbynulls + * for a possible recheck. + * ---------------- + */ +void +index_store_float8_orderby_distances(IndexScanDesc scan, Oid *orderByTypes, + double *distances, bool recheckOrderBy) +{ + int i; + + scan->xs_recheckorderby = recheckOrderBy; + + if (!distances) + { + Assert(!scan->xs_recheckorderby); + + for (i = 0; i < scan->numberOfOrderBys; i++) + { + scan->xs_orderbyvals[i] = (Datum) 0; + scan->xs_orderbynulls[i] = true; + } + + return; + } + + for (i = 0; i < scan->numberOfOrderBys; i++) + { + if (orderByTypes[i] == FLOAT8OID) + { +#ifndef USE_FLOAT8_BYVAL + /* must free any old value to avoid memory leakage */ + if (!scan->xs_orderbynulls[i]) + pfree(DatumGetPointer(scan->xs_orderbyvals[i])); +#endif + scan->xs_orderbyvals[i] = Float8GetDatum(distances[i]); + scan->xs_orderbynulls[i] = false; + } + else if (orderByTypes[i] == FLOAT4OID) + { + /* convert distance function's result to ORDER BY type */ +#ifndef USE_FLOAT4_BYVAL + /* must free any old value to avoid memory leakage */ + if (!scan->xs_orderbynulls[i]) + pfree(DatumGetPointer(scan->xs_orderbyvals[i])); +#endif + scan->xs_orderbyvals[i] = Float4GetDatum((float4) distances[i]); + scan->xs_orderbynulls[i] = false; + } + else + { + /* + * If the ordering operator's return value is anything else, we + * don't know how to convert the float8 bound calculated by the + * distance function to that. The executor won't actually need + * the order by values we return here, if there are no lossy + * results, so only insist on converting if the *recheck flag is + * set. + */ + if (scan->xs_recheckorderby) + elog(ERROR, "ORDER BY operator must return float8 or float4 if the distance function is lossy"); + scan->xs_orderbynulls[i] = true; + } + } +} |