/*-------------------------------------------------------------------------
*
+ * Portions Copyright (c) 2017-2021, pg_bigm Development Group
+ * Portions Copyright (c) 2013-2016, NTT DATA Corporation
* Portions Copyright (c) 2007-2012, PostgreSQL Global Development Group
- * Portions Copyright (c) 2013-2015, NTT DATA Corporation
*
* Changelog:
* 2013/01/09
#include "access/gin.h"
#include "access/gin_private.h"
#include "access/itup.h"
+#if PG_VERSION_NUM >= 120000
+#include "access/relation.h"
+#endif
#include "access/skey.h"
+#if PG_VERSION_NUM < 130000
#include "access/tuptoaster.h"
+#endif
+#include "access/xlog.h"
+#if PG_VERSION_NUM > 90500
+#include "catalog/pg_am.h"
+#endif
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "mb/pg_wchar.h"
#include "tsearch/ts_locale.h"
#include "utils/array.h"
#include "utils/builtins.h"
+#include "utils/rel.h"
PG_FUNCTION_INFO_V1(gin_extract_value_bigm);
PG_FUNCTION_INFO_V1(gin_bigm_compare_partial);
PG_FUNCTION_INFO_V1(pg_gin_pending_stats);
+/* triConsistent function is available only in 9.4 or later */
+#if PG_VERSION_NUM >= 90400
+PG_FUNCTION_INFO_V1(gin_bigm_triconsistent);
+#endif
+
/*
* The function prototypes are created as a part of PG_FUNCTION_INFO_V1
* macro since 9.4, and hence the declaration of the function prototypes
if (check[i])
ntrue++;
}
-#ifdef DIVUNION
- res = (nkeys == ntrue) ? true :
- ((((((float4) ntrue) / ((float4) (nkeys - ntrue)))) >=
- (float4) bigm_similarity_limit) ? true : false);
-#else
+
+ /*--------------------
+ * If DIVUNION is defined then similarity formula is:
+ * c / (len1 + len2 - c)
+ * where c is number of common bigrams and it stands as ntrue in
+ * this code. Here we don't know value of len2 but we can assume
+ * that c (ntrue) is a lower bound of len2, so upper bound of
+ * similarity is:
+ * c / (len1 + c - c) => c / len1
+ * If DIVUNION is not defined then similarity formula is:
+ * c / max(len1, len2)
+ * And again, c (ntrue) is a lower bound of len2, but c <= len1
+ * just by definition and, consequently, upper bound of
+ * similarity is just c / len1.
+ * So, independently on DIVUNION the upper bound formula is the same.
+ */
res = (nkeys == 0) ? false :
((((((float4) ntrue) / ((float4) nkeys))) >=
(float4) bigm_similarity_limit) ? true : false);
-#endif
break;
default:
elog(ERROR, "unrecognized strategy number: %d", strategy);
PG_RETURN_BOOL(res);
}
+/* triConsistent function is available only in 9.4 or later */
+#if PG_VERSION_NUM >= 90400
+Datum
+gin_bigm_triconsistent(PG_FUNCTION_ARGS)
+{
+ GinTernaryValue *check = (GinTernaryValue *) PG_GETARG_POINTER(0);
+ StrategyNumber strategy = PG_GETARG_UINT16(1);
+
+ /* text *query = PG_GETARG_TEXT_P(2); */
+ int32 nkeys = PG_GETARG_INT32(3);
+ Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4);
+ GinTernaryValue res = GIN_MAYBE;
+ int32 i,
+ ntrue;
+
+ switch (strategy)
+ {
+ case LikeStrategyNumber:
+ /*
+ * Don't recheck the heap tuple against the query if either
+ * pg_bigm.enable_recheck is disabled or the search word is the
+ * special one so that the index can return the exact result.
+ */
+ res = (bigm_enable_recheck &&
+ (*((bool *) extra_data) || (nkeys != 1))) ?
+ GIN_MAYBE : GIN_TRUE;
+
+ /* Check if all extracted bigrams are presented. */
+ for (i = 0; i < nkeys; i++)
+ {
+ if (check[i] == GIN_FALSE)
+ {
+ res = GIN_FALSE;
+ break;
+ }
+ }
+ break;
+ case SimilarityStrategyNumber:
+ /* Count the matches */
+ ntrue = 0;
+ for (i = 0; i < nkeys; i++)
+ {
+ if (check[i] != GIN_FALSE)
+ ntrue++;
+ }
+
+ /*
+ * See comment in gin_bigm_consistent() about upper bound formula
+ */
+ res = (nkeys == 0) ? GIN_FALSE :
+ (((((float4) ntrue) / ((float4) nkeys)) >=
+ (float4) bigm_similarity_limit) ? GIN_MAYBE : GIN_FALSE);
+
+ if (res != GIN_FALSE && !bigm_enable_recheck)
+ res = GIN_TRUE;
+ break;
+ default:
+ elog(ERROR, "unrecognized strategy number: %d", strategy);
+ res = GIN_FALSE; /* keep compiler quiet */
+ break;
+ }
+
+ PG_RETURN_GIN_TERNARY_VALUE(res);
+}
+#endif /* PG_VERSION_NUM >= 90400 */
+
Datum
gin_bigm_compare_partial(PG_FUNCTION_ARGS)
{
HeapTuple tuple;
TupleDesc tupdesc;
+ indexRel = relation_open(indexOid, AccessShareLock);
+
+ if (indexRel->rd_rel->relkind != RELKIND_INDEX ||
+ indexRel->rd_rel->relam != GIN_AM_OID)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("relation \"%s\" is not a GIN index",
+ RelationGetRelationName(indexRel))));
+
+ /*
+ * Reject attempts to read non-local temporary relations; we would be
+ * likely to get wrong data since we have no visibility into the owning
+ * session's local buffers.
+ */
+ if (RELATION_IS_OTHER_TEMP(indexRel))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot access temporary indexes of other sessions")));
+
/*
* Obtain statistic information from the meta page
*/
- indexRel = index_open(indexOid, AccessShareLock);
metabuffer = ReadBuffer(indexRel, GIN_METAPAGE_BLKNO);
LockBuffer(metabuffer, GIN_SHARE);
metapage = BufferGetPage(metabuffer);
metadata = GinPageGetMeta(metapage);
- index_close(indexRel, AccessShareLock);
/*
* Construct a tuple descriptor for the result row. This must match this
* function's pg_bigm--x.x.sql entry.
*/
+ #if PG_VERSION_NUM >= 120000
+ tupdesc = CreateTemplateTupleDesc(2);
+#else
tupdesc = CreateTemplateTupleDesc(2, false);
+#endif
TupleDescInitEntry(tupdesc, (AttrNumber) 1,
"pages", INT4OID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 2,
isnull[1] = false;
UnlockReleaseBuffer(metabuffer);
+ relation_close(indexRel, AccessShareLock);
tuple = heap_form_tuple(tupdesc, values, isnull);
PG_RETURN_DATUM(HeapTupleGetDatum(tuple));