Allow opclasses to provide tri-valued GIN consistent functions.
With the GIN "fast scan" feature, GIN can skip items without fetching all the keys for them, if it can prove that they don't match regardless of those keys. So far, it has done the proving by calling the boolean consistent function with all combinations of TRUE/FALSE for the unfetched keys, but since that's O(n^2), it becomes unfeasible with more than a few keys. We can avoid calling consistent with all the combinations, if we can tell the operator class implementation directly which keys are unknown. This commit includes a triConsistent function for the built-in array and tsvector opclasses. Alexander Korotkov, with some changes by me.
This commit is contained in:
parent
fecfc2b913
commit
c5608ea26a
@ -74,15 +74,15 @@
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
All it takes to get a <acronym>GIN</acronym> access method working is to
|
All it takes to get a <acronym>GIN</acronym> access method working is to
|
||||||
implement four (or five) user-defined methods, which define the behavior of
|
implement a few user-defined methods, which define the behavior of
|
||||||
keys in the tree and the relationships between keys, indexed items,
|
keys in the tree and the relationships between keys, indexed items,
|
||||||
and indexable queries. In short, <acronym>GIN</acronym> combines
|
and indexable queries. In short, <acronym>GIN</acronym> combines
|
||||||
extensibility with generality, code reuse, and a clean interface.
|
extensibility with generality, code reuse, and a clean interface.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The four methods that an operator class for
|
There are three methods that an operator class for
|
||||||
<acronym>GIN</acronym> must provide are:
|
<acronym>GIN</acronym> must provide:
|
||||||
|
|
||||||
<variablelist>
|
<variablelist>
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
@ -190,7 +190,18 @@
|
|||||||
|
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
</variablelist>
|
||||||
|
|
||||||
|
An operator class must also provide a function to check if an indexed item
|
||||||
|
matches the query. It comes in two flavors, a boolean <function>consistent</>
|
||||||
|
function, and a ternary <function>triConsistent</> function.
|
||||||
|
<function>triConsistent</> covers the functionality of both, so providing
|
||||||
|
triConsistent alone is sufficient. However, if the boolean variant is
|
||||||
|
significantly cheaper to calculate, it can be advantegous to provide both.
|
||||||
|
If only the boolean variant is provided, some optimizations that depend on
|
||||||
|
refuting index items before fetching all the keys are disabled.
|
||||||
|
|
||||||
|
<variablelist>
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><function>bool consistent(bool check[], StrategyNumber n, Datum query,
|
<term><function>bool consistent(bool check[], StrategyNumber n, Datum query,
|
||||||
int32 nkeys, Pointer extra_data[], bool *recheck,
|
int32 nkeys, Pointer extra_data[], bool *recheck,
|
||||||
@ -241,10 +252,38 @@
|
|||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><function>GinLogicValue triConsistent(GinLogicValue check[], StrategyNumber n, Datum query,
|
||||||
|
int32 nkeys, Pointer extra_data[],
|
||||||
|
Datum queryKeys[], bool nullFlags[])</></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<function>triConsistent</> is similar to <function>consistent</>,
|
||||||
|
but instead of a boolean <literal>check[]</>, there are three possible
|
||||||
|
values for each key: <literal>GIN_TRUE</>, <literal>GIN_FALSE</> and
|
||||||
|
<literal>GIN_MAYBE</>. <literal>GIN_FALSE</> and <literal>GIN_TRUE</>
|
||||||
|
have the same meaning as regular boolean values.
|
||||||
|
<literal>GIN_MAYBE</> means that the presence of that key is not known.
|
||||||
|
When <literal>GIN_MAYBE</> values are present, the function should only
|
||||||
|
return GIN_TRUE if the item matches whether or not the index item
|
||||||
|
contains the corresponding query keys. Likewise, the function must
|
||||||
|
return GIN_FALSE only if the item does not match, whether or not it
|
||||||
|
contains the GIN_MAYBE keys. If the result depends on the GIN_MAYBE
|
||||||
|
entries, ie. the match cannot be confirmed or refuted based on the
|
||||||
|
known query keys, the function must return GIN_MAYBE.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
When there are no GIN_MAYBE values in the <literal>check</> vector,
|
||||||
|
<literal>GIN_MAYBE</> return value is equivalent of setting
|
||||||
|
<literal>recheck</> flag in the boolean <function>consistent</> function.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
Optionally, an operator class for
|
Optionally, an operator class for <acronym>GIN</acronym> can supply the
|
||||||
<acronym>GIN</acronym> can supply a fifth method:
|
following method:
|
||||||
|
|
||||||
<variablelist>
|
<variablelist>
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
@ -282,8 +321,9 @@
|
|||||||
above vary depending on the operator class. The item values passed to
|
above vary depending on the operator class. The item values passed to
|
||||||
<function>extractValue</> are always of the operator class's input type, and
|
<function>extractValue</> are always of the operator class's input type, and
|
||||||
all key values must be of the class's <literal>STORAGE</> type. The type of
|
all key values must be of the class's <literal>STORAGE</> type. The type of
|
||||||
the <literal>query</> argument passed to <function>extractQuery</> and
|
the <literal>query</> argument passed to <function>extractQuery</>,
|
||||||
<function>consistent</> is whatever is specified as the right-hand input
|
<function>consistent</> and <function>triConsistent</> is whatever is
|
||||||
|
specified as the right-hand input
|
||||||
type of the class member operator identified by the strategy number.
|
type of the class member operator identified by the strategy number.
|
||||||
This need not be the same as the item type, so long as key values of the
|
This need not be the same as the item type, so long as key values of the
|
||||||
correct type can be extracted from it.
|
correct type can be extracted from it.
|
||||||
|
@ -567,7 +567,10 @@
|
|||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry><function>consistent</></entry>
|
<entry><function>consistent</></entry>
|
||||||
<entry>determine whether value matches query condition</entry>
|
<entry>
|
||||||
|
determine whether value matches query condition (boolean variant)
|
||||||
|
(optional if support function 6 is present)
|
||||||
|
</entry>
|
||||||
<entry>4</entry>
|
<entry>4</entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
@ -580,6 +583,14 @@
|
|||||||
</entry>
|
</entry>
|
||||||
<entry>5</entry>
|
<entry>5</entry>
|
||||||
</row>
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry><function>triConsistent</></entry>
|
||||||
|
<entry>
|
||||||
|
determine whether value matches query condition (ternary variant)
|
||||||
|
(optional if support function 4 is present)
|
||||||
|
</entry>
|
||||||
|
<entry>6</entry>
|
||||||
|
</row>
|
||||||
</tbody>
|
</tbody>
|
||||||
</tgroup>
|
</tgroup>
|
||||||
</table>
|
</table>
|
||||||
|
@ -218,3 +218,87 @@ ginarrayconsistent(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
PG_RETURN_BOOL(res);
|
PG_RETURN_BOOL(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* triconsistent support function
|
||||||
|
*/
|
||||||
|
Datum
|
||||||
|
ginarraytriconsistent(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
GinLogicValue *check = (GinLogicValue *) PG_GETARG_POINTER(0);
|
||||||
|
StrategyNumber strategy = PG_GETARG_UINT16(1);
|
||||||
|
|
||||||
|
/* ArrayType *query = PG_GETARG_ARRAYTYPE_P(2); */
|
||||||
|
int32 nkeys = PG_GETARG_INT32(3);
|
||||||
|
|
||||||
|
/* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
|
||||||
|
/* Datum *queryKeys = (Datum *) PG_GETARG_POINTER(5); */
|
||||||
|
bool *nullFlags = (bool *) PG_GETARG_POINTER(6);
|
||||||
|
GinLogicValue res;
|
||||||
|
int32 i;
|
||||||
|
|
||||||
|
switch (strategy)
|
||||||
|
{
|
||||||
|
case GinOverlapStrategy:
|
||||||
|
/* must have a match for at least one non-null element */
|
||||||
|
res = GIN_FALSE;
|
||||||
|
for (i = 0; i < nkeys; i++)
|
||||||
|
{
|
||||||
|
if (!nullFlags[i])
|
||||||
|
{
|
||||||
|
if (check[i] == GIN_TRUE)
|
||||||
|
{
|
||||||
|
res = GIN_TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (check[i] == GIN_MAYBE && res == GIN_FALSE)
|
||||||
|
{
|
||||||
|
res = GIN_MAYBE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GinContainsStrategy:
|
||||||
|
/* must have all elements in check[] true, and no nulls */
|
||||||
|
res = GIN_TRUE;
|
||||||
|
for (i = 0; i < nkeys; i++)
|
||||||
|
{
|
||||||
|
if (check[i] == GIN_FALSE || nullFlags[i])
|
||||||
|
{
|
||||||
|
res = GIN_FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (check[i] == GIN_MAYBE)
|
||||||
|
{
|
||||||
|
res = GIN_MAYBE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GinContainedStrategy:
|
||||||
|
/* can't do anything else useful here */
|
||||||
|
res = GIN_MAYBE;
|
||||||
|
break;
|
||||||
|
case GinEqualStrategy:
|
||||||
|
/*
|
||||||
|
* Must have all elements in check[] true; no discrimination
|
||||||
|
* against nulls here. This is because array_contain_compare and
|
||||||
|
* array_eq handle nulls differently ...
|
||||||
|
*/
|
||||||
|
res = GIN_MAYBE;
|
||||||
|
for (i = 0; i < nkeys; i++)
|
||||||
|
{
|
||||||
|
if (check[i] == GIN_FALSE)
|
||||||
|
{
|
||||||
|
res = GIN_FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
elog(ERROR, "ginarrayconsistent: unknown strategy number: %d",
|
||||||
|
strategy);
|
||||||
|
res = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PG_RETURN_GIN_LOGIC_VALUE(res);
|
||||||
|
}
|
||||||
|
@ -61,7 +61,7 @@ trueTriConsistentFn(GinScanKey key)
|
|||||||
* A helper function for calling a regular, binary logic, consistent function.
|
* A helper function for calling a regular, binary logic, consistent function.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
normalBoolConsistentFn(GinScanKey key)
|
directBoolConsistentFn(GinScanKey key)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Initialize recheckCurItem in case the consistentFn doesn't know it
|
* Initialize recheckCurItem in case the consistentFn doesn't know it
|
||||||
@ -81,6 +81,53 @@ normalBoolConsistentFn(GinScanKey key)
|
|||||||
PointerGetDatum(key->queryCategories)));
|
PointerGetDatum(key->queryCategories)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A helper function for calling a native ternary logic consistent function.
|
||||||
|
*/
|
||||||
|
static GinLogicValue
|
||||||
|
directTriConsistentFn(GinScanKey key)
|
||||||
|
{
|
||||||
|
return DatumGetGinLogicValue(FunctionCall7Coll(key->triConsistentFmgrInfo,
|
||||||
|
key->collation,
|
||||||
|
PointerGetDatum(key->entryRes),
|
||||||
|
UInt16GetDatum(key->strategy),
|
||||||
|
key->query,
|
||||||
|
UInt32GetDatum(key->nuserentries),
|
||||||
|
PointerGetDatum(key->extra_data),
|
||||||
|
PointerGetDatum(key->queryValues),
|
||||||
|
PointerGetDatum(key->queryCategories)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function implements a binary logic consistency check, using a ternary
|
||||||
|
* logic consistent function provided by the opclass. GIN_MAYBE return value
|
||||||
|
* is interpreted as true with recheck flag.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
shimBoolConsistentFn(GinScanKey key)
|
||||||
|
{
|
||||||
|
GinLogicValue result;
|
||||||
|
result = DatumGetGinLogicValue(FunctionCall7Coll(key->triConsistentFmgrInfo,
|
||||||
|
key->collation,
|
||||||
|
PointerGetDatum(key->entryRes),
|
||||||
|
UInt16GetDatum(key->strategy),
|
||||||
|
key->query,
|
||||||
|
UInt32GetDatum(key->nuserentries),
|
||||||
|
PointerGetDatum(key->extra_data),
|
||||||
|
PointerGetDatum(key->queryValues),
|
||||||
|
PointerGetDatum(key->queryCategories)));
|
||||||
|
if (result == GIN_MAYBE)
|
||||||
|
{
|
||||||
|
key->recheckCurItem = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
key->recheckCurItem = false;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function implements a tri-state consistency check, using a boolean
|
* This function implements a tri-state consistency check, using a boolean
|
||||||
* consistent function provided by the opclass.
|
* consistent function provided by the opclass.
|
||||||
@ -124,12 +171,12 @@ shimTriConsistentFn(GinScanKey key)
|
|||||||
* function as is.
|
* function as is.
|
||||||
*/
|
*/
|
||||||
if (nmaybe == 0)
|
if (nmaybe == 0)
|
||||||
return normalBoolConsistentFn(key);
|
return directBoolConsistentFn(key);
|
||||||
|
|
||||||
/* First call consistent function with all the maybe-inputs set FALSE */
|
/* First call consistent function with all the maybe-inputs set FALSE */
|
||||||
for (i = 0; i < nmaybe; i++)
|
for (i = 0; i < nmaybe; i++)
|
||||||
key->entryRes[maybeEntries[i]] = GIN_FALSE;
|
key->entryRes[maybeEntries[i]] = GIN_FALSE;
|
||||||
curResult = normalBoolConsistentFn(key);
|
curResult = directBoolConsistentFn(key);
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@ -147,7 +194,7 @@ shimTriConsistentFn(GinScanKey key)
|
|||||||
if (i == nmaybe)
|
if (i == nmaybe)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
boolResult = normalBoolConsistentFn(key);
|
boolResult = directBoolConsistentFn(key);
|
||||||
recheck |= key->recheckCurItem;
|
recheck |= key->recheckCurItem;
|
||||||
|
|
||||||
if (curResult != boolResult)
|
if (curResult != boolResult)
|
||||||
@ -175,8 +222,17 @@ ginInitConsistentFunction(GinState *ginstate, GinScanKey key)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
key->consistentFmgrInfo = &ginstate->consistentFn[key->attnum - 1];
|
key->consistentFmgrInfo = &ginstate->consistentFn[key->attnum - 1];
|
||||||
|
key->triConsistentFmgrInfo = &ginstate->triConsistentFn[key->attnum - 1];
|
||||||
key->collation = ginstate->supportCollation[key->attnum - 1];
|
key->collation = ginstate->supportCollation[key->attnum - 1];
|
||||||
key->boolConsistentFn = normalBoolConsistentFn;
|
|
||||||
|
if (OidIsValid(ginstate->consistentFn[key->attnum - 1].fn_oid))
|
||||||
|
key->boolConsistentFn = directBoolConsistentFn;
|
||||||
|
else
|
||||||
|
key->boolConsistentFn = shimBoolConsistentFn;
|
||||||
|
|
||||||
|
if (OidIsValid(ginstate->triConsistentFn[key->attnum - 1].fn_oid))
|
||||||
|
key->triConsistentFn = directTriConsistentFn;
|
||||||
|
else
|
||||||
key->triConsistentFn = shimTriConsistentFn;
|
key->triConsistentFn = shimTriConsistentFn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,9 +67,31 @@ initGinState(GinState *state, Relation index)
|
|||||||
fmgr_info_copy(&(state->extractQueryFn[i]),
|
fmgr_info_copy(&(state->extractQueryFn[i]),
|
||||||
index_getprocinfo(index, i + 1, GIN_EXTRACTQUERY_PROC),
|
index_getprocinfo(index, i + 1, GIN_EXTRACTQUERY_PROC),
|
||||||
CurrentMemoryContext);
|
CurrentMemoryContext);
|
||||||
|
/*
|
||||||
|
* Check opclass capability to do tri-state or binary logic consistent
|
||||||
|
* check.
|
||||||
|
*/
|
||||||
|
if (index_getprocid(index, i + 1, GIN_TRICONSISTENT_PROC) != InvalidOid)
|
||||||
|
{
|
||||||
|
fmgr_info_copy(&(state->triConsistentFn[i]),
|
||||||
|
index_getprocinfo(index, i + 1, GIN_TRICONSISTENT_PROC),
|
||||||
|
CurrentMemoryContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index_getprocid(index, i + 1, GIN_CONSISTENT_PROC) != InvalidOid)
|
||||||
|
{
|
||||||
fmgr_info_copy(&(state->consistentFn[i]),
|
fmgr_info_copy(&(state->consistentFn[i]),
|
||||||
index_getprocinfo(index, i + 1, GIN_CONSISTENT_PROC),
|
index_getprocinfo(index, i + 1, GIN_CONSISTENT_PROC),
|
||||||
CurrentMemoryContext);
|
CurrentMemoryContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->consistentFn[i].fn_oid == InvalidOid &&
|
||||||
|
state->triConsistentFn[i].fn_oid == InvalidOid)
|
||||||
|
{
|
||||||
|
elog(ERROR, "missing GIN support function (%d or %d) for attribute %d of index \"%s\"",
|
||||||
|
GIN_CONSISTENT_PROC, GIN_TRICONSISTENT_PROC,
|
||||||
|
i + 1, RelationGetRelationName(index));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check opclass capability to do partial match.
|
* Check opclass capability to do partial match.
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include "access/gin.h"
|
#include "access/gin.h"
|
||||||
#include "access/skey.h"
|
#include "access/skey.h"
|
||||||
|
#include "miscadmin.h"
|
||||||
#include "tsearch/ts_type.h"
|
#include "tsearch/ts_type.h"
|
||||||
#include "tsearch/ts_utils.h"
|
#include "tsearch/ts_utils.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
@ -172,12 +173,12 @@ gin_extract_tsquery(PG_FUNCTION_ARGS)
|
|||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
QueryItem *first_item;
|
QueryItem *first_item;
|
||||||
bool *check;
|
GinLogicValue *check;
|
||||||
int *map_item_operand;
|
int *map_item_operand;
|
||||||
bool *need_recheck;
|
bool *need_recheck;
|
||||||
} GinChkVal;
|
} GinChkVal;
|
||||||
|
|
||||||
static bool
|
static GinLogicValue
|
||||||
checkcondition_gin(void *checkval, QueryOperand *val)
|
checkcondition_gin(void *checkval, QueryOperand *val)
|
||||||
{
|
{
|
||||||
GinChkVal *gcv = (GinChkVal *) checkval;
|
GinChkVal *gcv = (GinChkVal *) checkval;
|
||||||
@ -194,6 +195,66 @@ checkcondition_gin(void *checkval, QueryOperand *val)
|
|||||||
return gcv->check[j];
|
return gcv->check[j];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Evaluate tsquery boolean expression using ternary logic.
|
||||||
|
*
|
||||||
|
* chkcond is a callback function used to evaluate each VAL node in the query.
|
||||||
|
* checkval can be used to pass information to the callback. TS_execute doesn't
|
||||||
|
* do anything with it.
|
||||||
|
*/
|
||||||
|
static GinLogicValue
|
||||||
|
TS_execute_ternary(QueryItem *curitem, void *checkval,
|
||||||
|
GinLogicValue (*chkcond) (void *checkval, QueryOperand *val))
|
||||||
|
{
|
||||||
|
GinLogicValue val1, val2, result;
|
||||||
|
/* since this function recurses, it could be driven to stack overflow */
|
||||||
|
check_stack_depth();
|
||||||
|
|
||||||
|
if (curitem->type == QI_VAL)
|
||||||
|
return chkcond(checkval, (QueryOperand *) curitem);
|
||||||
|
|
||||||
|
switch (curitem->qoperator.oper)
|
||||||
|
{
|
||||||
|
case OP_NOT:
|
||||||
|
result = TS_execute_ternary(curitem + 1, checkval, chkcond);
|
||||||
|
if (result == GIN_MAYBE)
|
||||||
|
return result;
|
||||||
|
return !result;
|
||||||
|
|
||||||
|
case OP_AND:
|
||||||
|
val1 = TS_execute_ternary(curitem + curitem->qoperator.left,
|
||||||
|
checkval, chkcond);
|
||||||
|
if (val1 == GIN_FALSE)
|
||||||
|
return GIN_FALSE;
|
||||||
|
val2 = TS_execute_ternary(curitem + 1, checkval, chkcond);
|
||||||
|
if (val2 == GIN_FALSE)
|
||||||
|
return GIN_FALSE;
|
||||||
|
if (val1 == GIN_TRUE && val2 == GIN_TRUE)
|
||||||
|
return GIN_TRUE;
|
||||||
|
else
|
||||||
|
return GIN_MAYBE;
|
||||||
|
|
||||||
|
case OP_OR:
|
||||||
|
val1 = TS_execute_ternary(curitem + curitem->qoperator.left,
|
||||||
|
checkval, chkcond);
|
||||||
|
if (val1 == GIN_TRUE)
|
||||||
|
return GIN_TRUE;
|
||||||
|
val2 = TS_execute_ternary(curitem + 1, checkval, chkcond);
|
||||||
|
if (val2 == GIN_TRUE)
|
||||||
|
return GIN_TRUE;
|
||||||
|
if (val1 == GIN_FALSE && val2 == GIN_FALSE)
|
||||||
|
return GIN_FALSE;
|
||||||
|
else
|
||||||
|
return GIN_MAYBE;
|
||||||
|
|
||||||
|
default:
|
||||||
|
elog(ERROR, "unrecognized operator: %d", curitem->qoperator.oper);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* not reachable, but keep compiler quiet */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
gin_tsquery_consistent(PG_FUNCTION_ARGS)
|
gin_tsquery_consistent(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
@ -233,6 +294,45 @@ gin_tsquery_consistent(PG_FUNCTION_ARGS)
|
|||||||
PG_RETURN_BOOL(res);
|
PG_RETURN_BOOL(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Datum
|
||||||
|
gin_tsquery_triconsistent(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
GinLogicValue *check = (GinLogicValue *) PG_GETARG_POINTER(0);
|
||||||
|
|
||||||
|
/* StrategyNumber strategy = PG_GETARG_UINT16(1); */
|
||||||
|
TSQuery query = PG_GETARG_TSQUERY(2);
|
||||||
|
|
||||||
|
/* int32 nkeys = PG_GETARG_INT32(3); */
|
||||||
|
Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4);
|
||||||
|
GinLogicValue res = GIN_FALSE;
|
||||||
|
bool recheck;
|
||||||
|
|
||||||
|
/* The query requires recheck only if it involves weights */
|
||||||
|
if (query->size > 0)
|
||||||
|
{
|
||||||
|
QueryItem *item;
|
||||||
|
GinChkVal gcv;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check-parameter array has one entry for each value (operand) in the
|
||||||
|
* query.
|
||||||
|
*/
|
||||||
|
gcv.first_item = item = GETQUERY(query);
|
||||||
|
gcv.check = check;
|
||||||
|
gcv.map_item_operand = (int *) (extra_data[0]);
|
||||||
|
gcv.need_recheck = &recheck;
|
||||||
|
|
||||||
|
res = TS_execute_ternary(GETQUERY(query),
|
||||||
|
&gcv,
|
||||||
|
checkcondition_gin);
|
||||||
|
|
||||||
|
if (res == GIN_TRUE && recheck)
|
||||||
|
res = GIN_MAYBE;
|
||||||
|
}
|
||||||
|
|
||||||
|
PG_RETURN_GIN_LOGIC_VALUE(res);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Formerly, gin_extract_tsvector had only two arguments. Now it has three,
|
* Formerly, gin_extract_tsvector had only two arguments. Now it has three,
|
||||||
* but we still need a pg_proc entry with two args to support reloading
|
* but we still need a pg_proc entry with two args to support reloading
|
||||||
|
@ -23,7 +23,8 @@
|
|||||||
#define GIN_EXTRACTQUERY_PROC 3
|
#define GIN_EXTRACTQUERY_PROC 3
|
||||||
#define GIN_CONSISTENT_PROC 4
|
#define GIN_CONSISTENT_PROC 4
|
||||||
#define GIN_COMPARE_PARTIAL_PROC 5
|
#define GIN_COMPARE_PARTIAL_PROC 5
|
||||||
#define GINNProcs 5
|
#define GIN_TRICONSISTENT_PROC 6
|
||||||
|
#define GINNProcs 6
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* searchMode settings for extractQueryFn.
|
* searchMode settings for extractQueryFn.
|
||||||
@ -46,6 +47,21 @@ typedef struct GinStatsData
|
|||||||
int32 ginVersion;
|
int32 ginVersion;
|
||||||
} GinStatsData;
|
} GinStatsData;
|
||||||
|
|
||||||
|
/* ginlogic.c */
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
GIN_FALSE = 0, /* item is present / matches */
|
||||||
|
GIN_TRUE = 1, /* item is not present / does not match */
|
||||||
|
GIN_MAYBE = 2 /* don't know if item is present / don't know if
|
||||||
|
* matches */
|
||||||
|
} GinLogicValueEnum;
|
||||||
|
|
||||||
|
typedef char GinLogicValue;
|
||||||
|
|
||||||
|
#define DatumGetGinLogicValue(X) ((GinLogicValue)(X))
|
||||||
|
#define GinLogicValueGetDatum(X) ((Datum)(X))
|
||||||
|
#define PG_RETURN_GIN_LOGIC_VALUE(x) return GinLogicValueGetDatum(x)
|
||||||
|
|
||||||
/* GUC parameter */
|
/* GUC parameter */
|
||||||
extern PGDLLIMPORT int GinFuzzySearchLimit;
|
extern PGDLLIMPORT int GinFuzzySearchLimit;
|
||||||
|
|
||||||
|
@ -348,6 +348,7 @@ typedef struct GinState
|
|||||||
FmgrInfo extractValueFn[INDEX_MAX_KEYS];
|
FmgrInfo extractValueFn[INDEX_MAX_KEYS];
|
||||||
FmgrInfo extractQueryFn[INDEX_MAX_KEYS];
|
FmgrInfo extractQueryFn[INDEX_MAX_KEYS];
|
||||||
FmgrInfo consistentFn[INDEX_MAX_KEYS];
|
FmgrInfo consistentFn[INDEX_MAX_KEYS];
|
||||||
|
FmgrInfo triConsistentFn[INDEX_MAX_KEYS];
|
||||||
FmgrInfo comparePartialFn[INDEX_MAX_KEYS]; /* optional method */
|
FmgrInfo comparePartialFn[INDEX_MAX_KEYS]; /* optional method */
|
||||||
/* canPartialMatch[i] is true if comparePartialFn[i] is valid */
|
/* canPartialMatch[i] is true if comparePartialFn[i] is valid */
|
||||||
bool canPartialMatch[INDEX_MAX_KEYS];
|
bool canPartialMatch[INDEX_MAX_KEYS];
|
||||||
@ -762,8 +763,9 @@ typedef struct GinScanKeyData
|
|||||||
/* array of check flags, reported to consistentFn */
|
/* array of check flags, reported to consistentFn */
|
||||||
bool *entryRes;
|
bool *entryRes;
|
||||||
bool (*boolConsistentFn) (GinScanKey key);
|
bool (*boolConsistentFn) (GinScanKey key);
|
||||||
bool (*triConsistentFn) (GinScanKey key);
|
GinLogicValue (*triConsistentFn) (GinScanKey key);
|
||||||
FmgrInfo *consistentFmgrInfo;
|
FmgrInfo *consistentFmgrInfo;
|
||||||
|
FmgrInfo *triConsistentFmgrInfo;
|
||||||
Oid collation;
|
Oid collation;
|
||||||
|
|
||||||
/* other data needed for calling consistentFn */
|
/* other data needed for calling consistentFn */
|
||||||
@ -850,17 +852,6 @@ extern void ginNewScanKey(IndexScanDesc scan);
|
|||||||
extern Datum gingetbitmap(PG_FUNCTION_ARGS);
|
extern Datum gingetbitmap(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
/* ginlogic.c */
|
/* ginlogic.c */
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
GIN_FALSE = 0, /* item is present / matches */
|
|
||||||
GIN_TRUE = 1, /* item is not present / does not match */
|
|
||||||
GIN_MAYBE = 2 /* don't know if item is present / don't know if
|
|
||||||
* matches */
|
|
||||||
} GinLogicValueEnum;
|
|
||||||
|
|
||||||
typedef char GinLogicValue;
|
|
||||||
|
|
||||||
extern void ginInitConsistentFunction(GinState *ginstate, GinScanKey key);
|
extern void ginInitConsistentFunction(GinState *ginstate, GinScanKey key);
|
||||||
|
|
||||||
/* ginvacuum.c */
|
/* ginvacuum.c */
|
||||||
|
@ -53,6 +53,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 201403041
|
#define CATALOG_VERSION_NO 201403121
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -126,7 +126,7 @@ DESCR("hash index access method");
|
|||||||
DATA(insert OID = 783 ( gist 0 8 f t f f t t f t t t f 0 gistinsert gistbeginscan gistgettuple gistgetbitmap gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbuildempty gistbulkdelete gistvacuumcleanup - gistcostestimate gistoptions ));
|
DATA(insert OID = 783 ( gist 0 8 f t f f t t f t t t f 0 gistinsert gistbeginscan gistgettuple gistgetbitmap gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbuildempty gistbulkdelete gistvacuumcleanup - gistcostestimate gistoptions ));
|
||||||
DESCR("GiST index access method");
|
DESCR("GiST index access method");
|
||||||
#define GIST_AM_OID 783
|
#define GIST_AM_OID 783
|
||||||
DATA(insert OID = 2742 ( gin 0 5 f f f f t t f f t f f 0 gininsert ginbeginscan - gingetbitmap ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbuildempty ginbulkdelete ginvacuumcleanup - gincostestimate ginoptions ));
|
DATA(insert OID = 2742 ( gin 0 6 f f f f t t f f t f f 0 gininsert ginbeginscan - gingetbitmap ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbuildempty ginbulkdelete ginvacuumcleanup - gincostestimate ginoptions ));
|
||||||
DESCR("GIN index access method");
|
DESCR("GIN index access method");
|
||||||
#define GIN_AM_OID 2742
|
#define GIN_AM_OID 2742
|
||||||
DATA(insert OID = 4000 ( spgist 0 5 f f f f f t f t f f f 0 spginsert spgbeginscan spggettuple spggetbitmap spgrescan spgendscan spgmarkpos spgrestrpos spgbuild spgbuildempty spgbulkdelete spgvacuumcleanup spgcanreturn spgcostestimate spgoptions ));
|
DATA(insert OID = 4000 ( spgist 0 5 f f f f f t f t f f f 0 spginsert spgbeginscan spggettuple spggetbitmap spgrescan spgendscan spgmarkpos spgrestrpos spgbuild spgbuildempty spgbulkdelete spgvacuumcleanup spgcanreturn spgcostestimate spgoptions ));
|
||||||
|
@ -235,127 +235,158 @@ DATA(insert ( 2745 1007 1007 1 351 ));
|
|||||||
DATA(insert ( 2745 1007 1007 2 2743 ));
|
DATA(insert ( 2745 1007 1007 2 2743 ));
|
||||||
DATA(insert ( 2745 1007 1007 3 2774 ));
|
DATA(insert ( 2745 1007 1007 3 2774 ));
|
||||||
DATA(insert ( 2745 1007 1007 4 2744 ));
|
DATA(insert ( 2745 1007 1007 4 2744 ));
|
||||||
|
DATA(insert ( 2745 1007 1007 6 3920 ));
|
||||||
DATA(insert ( 2745 1009 1009 1 360 ));
|
DATA(insert ( 2745 1009 1009 1 360 ));
|
||||||
DATA(insert ( 2745 1009 1009 2 2743 ));
|
DATA(insert ( 2745 1009 1009 2 2743 ));
|
||||||
DATA(insert ( 2745 1009 1009 3 2774 ));
|
DATA(insert ( 2745 1009 1009 3 2774 ));
|
||||||
DATA(insert ( 2745 1009 1009 4 2744 ));
|
DATA(insert ( 2745 1009 1009 4 2744 ));
|
||||||
|
DATA(insert ( 2745 1009 1009 6 3920 ));
|
||||||
DATA(insert ( 2745 1015 1015 1 360 ));
|
DATA(insert ( 2745 1015 1015 1 360 ));
|
||||||
DATA(insert ( 2745 1015 1015 2 2743 ));
|
DATA(insert ( 2745 1015 1015 2 2743 ));
|
||||||
DATA(insert ( 2745 1015 1015 3 2774 ));
|
DATA(insert ( 2745 1015 1015 3 2774 ));
|
||||||
DATA(insert ( 2745 1015 1015 4 2744 ));
|
DATA(insert ( 2745 1015 1015 4 2744 ));
|
||||||
|
DATA(insert ( 2745 1015 1015 6 3920 ));
|
||||||
DATA(insert ( 2745 1023 1023 1 357 ));
|
DATA(insert ( 2745 1023 1023 1 357 ));
|
||||||
DATA(insert ( 2745 1023 1023 2 2743 ));
|
DATA(insert ( 2745 1023 1023 2 2743 ));
|
||||||
DATA(insert ( 2745 1023 1023 3 2774 ));
|
DATA(insert ( 2745 1023 1023 3 2774 ));
|
||||||
DATA(insert ( 2745 1023 1023 4 2744 ));
|
DATA(insert ( 2745 1023 1023 4 2744 ));
|
||||||
|
DATA(insert ( 2745 1023 1023 6 3920 ));
|
||||||
DATA(insert ( 2745 1561 1561 1 1596 ));
|
DATA(insert ( 2745 1561 1561 1 1596 ));
|
||||||
DATA(insert ( 2745 1561 1561 2 2743 ));
|
DATA(insert ( 2745 1561 1561 2 2743 ));
|
||||||
DATA(insert ( 2745 1561 1561 3 2774 ));
|
DATA(insert ( 2745 1561 1561 3 2774 ));
|
||||||
DATA(insert ( 2745 1561 1561 4 2744 ));
|
DATA(insert ( 2745 1561 1561 4 2744 ));
|
||||||
|
DATA(insert ( 2745 1561 1561 6 3920 ));
|
||||||
DATA(insert ( 2745 1000 1000 1 1693 ));
|
DATA(insert ( 2745 1000 1000 1 1693 ));
|
||||||
DATA(insert ( 2745 1000 1000 2 2743 ));
|
DATA(insert ( 2745 1000 1000 2 2743 ));
|
||||||
DATA(insert ( 2745 1000 1000 3 2774 ));
|
DATA(insert ( 2745 1000 1000 3 2774 ));
|
||||||
DATA(insert ( 2745 1000 1000 4 2744 ));
|
DATA(insert ( 2745 1000 1000 4 2744 ));
|
||||||
|
DATA(insert ( 2745 1000 1000 6 3920 ));
|
||||||
DATA(insert ( 2745 1014 1014 1 1078 ));
|
DATA(insert ( 2745 1014 1014 1 1078 ));
|
||||||
DATA(insert ( 2745 1014 1014 2 2743 ));
|
DATA(insert ( 2745 1014 1014 2 2743 ));
|
||||||
DATA(insert ( 2745 1014 1014 3 2774 ));
|
DATA(insert ( 2745 1014 1014 3 2774 ));
|
||||||
DATA(insert ( 2745 1014 1014 4 2744 ));
|
DATA(insert ( 2745 1014 1014 4 2744 ));
|
||||||
|
DATA(insert ( 2745 1014 1014 6 3920 ));
|
||||||
DATA(insert ( 2745 1001 1001 1 1954 ));
|
DATA(insert ( 2745 1001 1001 1 1954 ));
|
||||||
DATA(insert ( 2745 1001 1001 2 2743 ));
|
DATA(insert ( 2745 1001 1001 2 2743 ));
|
||||||
DATA(insert ( 2745 1001 1001 3 2774 ));
|
DATA(insert ( 2745 1001 1001 3 2774 ));
|
||||||
DATA(insert ( 2745 1001 1001 4 2744 ));
|
DATA(insert ( 2745 1001 1001 4 2744 ));
|
||||||
|
DATA(insert ( 2745 1001 1001 6 3920 ));
|
||||||
DATA(insert ( 2745 1002 1002 1 358 ));
|
DATA(insert ( 2745 1002 1002 1 358 ));
|
||||||
DATA(insert ( 2745 1002 1002 2 2743 ));
|
DATA(insert ( 2745 1002 1002 2 2743 ));
|
||||||
DATA(insert ( 2745 1002 1002 3 2774 ));
|
DATA(insert ( 2745 1002 1002 3 2774 ));
|
||||||
DATA(insert ( 2745 1002 1002 4 2744 ));
|
DATA(insert ( 2745 1002 1002 4 2744 ));
|
||||||
|
DATA(insert ( 2745 1002 1002 6 3920 ));
|
||||||
DATA(insert ( 2745 1182 1182 1 1092 ));
|
DATA(insert ( 2745 1182 1182 1 1092 ));
|
||||||
DATA(insert ( 2745 1182 1182 2 2743 ));
|
DATA(insert ( 2745 1182 1182 2 2743 ));
|
||||||
DATA(insert ( 2745 1182 1182 3 2774 ));
|
DATA(insert ( 2745 1182 1182 3 2774 ));
|
||||||
DATA(insert ( 2745 1182 1182 4 2744 ));
|
DATA(insert ( 2745 1182 1182 4 2744 ));
|
||||||
|
DATA(insert ( 2745 1182 1182 6 3920 ));
|
||||||
DATA(insert ( 2745 1021 1021 1 354 ));
|
DATA(insert ( 2745 1021 1021 1 354 ));
|
||||||
DATA(insert ( 2745 1021 1021 2 2743 ));
|
DATA(insert ( 2745 1021 1021 2 2743 ));
|
||||||
DATA(insert ( 2745 1021 1021 3 2774 ));
|
DATA(insert ( 2745 1021 1021 3 2774 ));
|
||||||
DATA(insert ( 2745 1021 1021 4 2744 ));
|
DATA(insert ( 2745 1021 1021 4 2744 ));
|
||||||
|
DATA(insert ( 2745 1021 1021 6 3920 ));
|
||||||
DATA(insert ( 2745 1022 1022 1 355 ));
|
DATA(insert ( 2745 1022 1022 1 355 ));
|
||||||
DATA(insert ( 2745 1022 1022 2 2743 ));
|
DATA(insert ( 2745 1022 1022 2 2743 ));
|
||||||
DATA(insert ( 2745 1022 1022 3 2774 ));
|
DATA(insert ( 2745 1022 1022 3 2774 ));
|
||||||
DATA(insert ( 2745 1022 1022 4 2744 ));
|
DATA(insert ( 2745 1022 1022 4 2744 ));
|
||||||
|
DATA(insert ( 2745 1022 1022 6 3920 ));
|
||||||
DATA(insert ( 2745 1041 1041 1 926 ));
|
DATA(insert ( 2745 1041 1041 1 926 ));
|
||||||
DATA(insert ( 2745 1041 1041 2 2743 ));
|
DATA(insert ( 2745 1041 1041 2 2743 ));
|
||||||
DATA(insert ( 2745 1041 1041 3 2774 ));
|
DATA(insert ( 2745 1041 1041 3 2774 ));
|
||||||
DATA(insert ( 2745 1041 1041 4 2744 ));
|
DATA(insert ( 2745 1041 1041 4 2744 ));
|
||||||
|
DATA(insert ( 2745 1041 1041 6 3920 ));
|
||||||
DATA(insert ( 2745 651 651 1 926 ));
|
DATA(insert ( 2745 651 651 1 926 ));
|
||||||
DATA(insert ( 2745 651 651 2 2743 ));
|
DATA(insert ( 2745 651 651 2 2743 ));
|
||||||
DATA(insert ( 2745 651 651 3 2774 ));
|
DATA(insert ( 2745 651 651 3 2774 ));
|
||||||
DATA(insert ( 2745 651 651 4 2744 ));
|
DATA(insert ( 2745 651 651 4 2744 ));
|
||||||
|
DATA(insert ( 2745 651 651 6 3920 ));
|
||||||
DATA(insert ( 2745 1005 1005 1 350 ));
|
DATA(insert ( 2745 1005 1005 1 350 ));
|
||||||
DATA(insert ( 2745 1005 1005 2 2743 ));
|
DATA(insert ( 2745 1005 1005 2 2743 ));
|
||||||
DATA(insert ( 2745 1005 1005 3 2774 ));
|
DATA(insert ( 2745 1005 1005 3 2774 ));
|
||||||
DATA(insert ( 2745 1005 1005 4 2744 ));
|
DATA(insert ( 2745 1005 1005 4 2744 ));
|
||||||
|
DATA(insert ( 2745 1005 1005 6 3920 ));
|
||||||
DATA(insert ( 2745 1016 1016 1 842 ));
|
DATA(insert ( 2745 1016 1016 1 842 ));
|
||||||
DATA(insert ( 2745 1016 1016 2 2743 ));
|
DATA(insert ( 2745 1016 1016 2 2743 ));
|
||||||
DATA(insert ( 2745 1016 1016 3 2774 ));
|
DATA(insert ( 2745 1016 1016 3 2774 ));
|
||||||
DATA(insert ( 2745 1016 1016 4 2744 ));
|
DATA(insert ( 2745 1016 1016 4 2744 ));
|
||||||
|
DATA(insert ( 2745 1016 1016 6 3920 ));
|
||||||
DATA(insert ( 2745 1187 1187 1 1315 ));
|
DATA(insert ( 2745 1187 1187 1 1315 ));
|
||||||
DATA(insert ( 2745 1187 1187 2 2743 ));
|
DATA(insert ( 2745 1187 1187 2 2743 ));
|
||||||
DATA(insert ( 2745 1187 1187 3 2774 ));
|
DATA(insert ( 2745 1187 1187 3 2774 ));
|
||||||
DATA(insert ( 2745 1187 1187 4 2744 ));
|
DATA(insert ( 2745 1187 1187 4 2744 ));
|
||||||
|
DATA(insert ( 2745 1187 1187 6 3920 ));
|
||||||
DATA(insert ( 2745 1040 1040 1 836 ));
|
DATA(insert ( 2745 1040 1040 1 836 ));
|
||||||
DATA(insert ( 2745 1040 1040 2 2743 ));
|
DATA(insert ( 2745 1040 1040 2 2743 ));
|
||||||
DATA(insert ( 2745 1040 1040 3 2774 ));
|
DATA(insert ( 2745 1040 1040 3 2774 ));
|
||||||
DATA(insert ( 2745 1040 1040 4 2744 ));
|
DATA(insert ( 2745 1040 1040 4 2744 ));
|
||||||
|
DATA(insert ( 2745 1040 1040 6 3920 ));
|
||||||
DATA(insert ( 2745 1003 1003 1 359 ));
|
DATA(insert ( 2745 1003 1003 1 359 ));
|
||||||
DATA(insert ( 2745 1003 1003 2 2743 ));
|
DATA(insert ( 2745 1003 1003 2 2743 ));
|
||||||
DATA(insert ( 2745 1003 1003 3 2774 ));
|
DATA(insert ( 2745 1003 1003 3 2774 ));
|
||||||
DATA(insert ( 2745 1003 1003 4 2744 ));
|
DATA(insert ( 2745 1003 1003 4 2744 ));
|
||||||
|
DATA(insert ( 2745 1003 1003 6 3920 ));
|
||||||
DATA(insert ( 2745 1231 1231 1 1769 ));
|
DATA(insert ( 2745 1231 1231 1 1769 ));
|
||||||
DATA(insert ( 2745 1231 1231 2 2743 ));
|
DATA(insert ( 2745 1231 1231 2 2743 ));
|
||||||
DATA(insert ( 2745 1231 1231 3 2774 ));
|
DATA(insert ( 2745 1231 1231 3 2774 ));
|
||||||
DATA(insert ( 2745 1231 1231 4 2744 ));
|
DATA(insert ( 2745 1231 1231 4 2744 ));
|
||||||
|
DATA(insert ( 2745 1231 1231 6 3920 ));
|
||||||
DATA(insert ( 2745 1028 1028 1 356 ));
|
DATA(insert ( 2745 1028 1028 1 356 ));
|
||||||
DATA(insert ( 2745 1028 1028 2 2743 ));
|
DATA(insert ( 2745 1028 1028 2 2743 ));
|
||||||
DATA(insert ( 2745 1028 1028 3 2774 ));
|
DATA(insert ( 2745 1028 1028 3 2774 ));
|
||||||
DATA(insert ( 2745 1028 1028 4 2744 ));
|
DATA(insert ( 2745 1028 1028 4 2744 ));
|
||||||
|
DATA(insert ( 2745 1028 1028 6 3920 ));
|
||||||
DATA(insert ( 2745 1013 1013 1 404 ));
|
DATA(insert ( 2745 1013 1013 1 404 ));
|
||||||
DATA(insert ( 2745 1013 1013 2 2743 ));
|
DATA(insert ( 2745 1013 1013 2 2743 ));
|
||||||
DATA(insert ( 2745 1013 1013 3 2774 ));
|
DATA(insert ( 2745 1013 1013 3 2774 ));
|
||||||
DATA(insert ( 2745 1013 1013 4 2744 ));
|
DATA(insert ( 2745 1013 1013 4 2744 ));
|
||||||
|
DATA(insert ( 2745 1013 1013 6 3920 ));
|
||||||
DATA(insert ( 2745 1183 1183 1 1107 ));
|
DATA(insert ( 2745 1183 1183 1 1107 ));
|
||||||
DATA(insert ( 2745 1183 1183 2 2743 ));
|
DATA(insert ( 2745 1183 1183 2 2743 ));
|
||||||
DATA(insert ( 2745 1183 1183 3 2774 ));
|
DATA(insert ( 2745 1183 1183 3 2774 ));
|
||||||
DATA(insert ( 2745 1183 1183 4 2744 ));
|
DATA(insert ( 2745 1183 1183 4 2744 ));
|
||||||
|
DATA(insert ( 2745 1183 1183 6 3920 ));
|
||||||
DATA(insert ( 2745 1185 1185 1 1314 ));
|
DATA(insert ( 2745 1185 1185 1 1314 ));
|
||||||
DATA(insert ( 2745 1185 1185 2 2743 ));
|
DATA(insert ( 2745 1185 1185 2 2743 ));
|
||||||
DATA(insert ( 2745 1185 1185 3 2774 ));
|
DATA(insert ( 2745 1185 1185 3 2774 ));
|
||||||
DATA(insert ( 2745 1185 1185 4 2744 ));
|
DATA(insert ( 2745 1185 1185 4 2744 ));
|
||||||
|
DATA(insert ( 2745 1185 1185 6 3920 ));
|
||||||
DATA(insert ( 2745 1270 1270 1 1358 ));
|
DATA(insert ( 2745 1270 1270 1 1358 ));
|
||||||
DATA(insert ( 2745 1270 1270 2 2743 ));
|
DATA(insert ( 2745 1270 1270 2 2743 ));
|
||||||
DATA(insert ( 2745 1270 1270 3 2774 ));
|
DATA(insert ( 2745 1270 1270 3 2774 ));
|
||||||
DATA(insert ( 2745 1270 1270 4 2744 ));
|
DATA(insert ( 2745 1270 1270 4 2744 ));
|
||||||
|
DATA(insert ( 2745 1270 1270 6 3920 ));
|
||||||
DATA(insert ( 2745 1563 1563 1 1672 ));
|
DATA(insert ( 2745 1563 1563 1 1672 ));
|
||||||
DATA(insert ( 2745 1563 1563 2 2743 ));
|
DATA(insert ( 2745 1563 1563 2 2743 ));
|
||||||
DATA(insert ( 2745 1563 1563 3 2774 ));
|
DATA(insert ( 2745 1563 1563 3 2774 ));
|
||||||
DATA(insert ( 2745 1563 1563 4 2744 ));
|
DATA(insert ( 2745 1563 1563 4 2744 ));
|
||||||
|
DATA(insert ( 2745 1563 1563 6 3920 ));
|
||||||
DATA(insert ( 2745 1115 1115 1 2045 ));
|
DATA(insert ( 2745 1115 1115 1 2045 ));
|
||||||
DATA(insert ( 2745 1115 1115 2 2743 ));
|
DATA(insert ( 2745 1115 1115 2 2743 ));
|
||||||
DATA(insert ( 2745 1115 1115 3 2774 ));
|
DATA(insert ( 2745 1115 1115 3 2774 ));
|
||||||
DATA(insert ( 2745 1115 1115 4 2744 ));
|
DATA(insert ( 2745 1115 1115 4 2744 ));
|
||||||
|
DATA(insert ( 2745 1115 1115 6 3920 ));
|
||||||
DATA(insert ( 2745 791 791 1 377 ));
|
DATA(insert ( 2745 791 791 1 377 ));
|
||||||
DATA(insert ( 2745 791 791 2 2743 ));
|
DATA(insert ( 2745 791 791 2 2743 ));
|
||||||
DATA(insert ( 2745 791 791 3 2774 ));
|
DATA(insert ( 2745 791 791 3 2774 ));
|
||||||
DATA(insert ( 2745 791 791 4 2744 ));
|
DATA(insert ( 2745 791 791 4 2744 ));
|
||||||
|
DATA(insert ( 2745 791 791 6 3920 ));
|
||||||
DATA(insert ( 2745 1024 1024 1 380 ));
|
DATA(insert ( 2745 1024 1024 1 380 ));
|
||||||
DATA(insert ( 2745 1024 1024 2 2743 ));
|
DATA(insert ( 2745 1024 1024 2 2743 ));
|
||||||
DATA(insert ( 2745 1024 1024 3 2774 ));
|
DATA(insert ( 2745 1024 1024 3 2774 ));
|
||||||
DATA(insert ( 2745 1024 1024 4 2744 ));
|
DATA(insert ( 2745 1024 1024 4 2744 ));
|
||||||
|
DATA(insert ( 2745 1024 1024 6 3920 ));
|
||||||
DATA(insert ( 2745 1025 1025 1 381 ));
|
DATA(insert ( 2745 1025 1025 1 381 ));
|
||||||
DATA(insert ( 2745 1025 1025 2 2743 ));
|
DATA(insert ( 2745 1025 1025 2 2743 ));
|
||||||
DATA(insert ( 2745 1025 1025 3 2774 ));
|
DATA(insert ( 2745 1025 1025 3 2774 ));
|
||||||
DATA(insert ( 2745 1025 1025 4 2744 ));
|
DATA(insert ( 2745 1025 1025 4 2744 ));
|
||||||
|
DATA(insert ( 2745 1025 1025 6 3920 ));
|
||||||
DATA(insert ( 3659 3614 3614 1 3724 ));
|
DATA(insert ( 3659 3614 3614 1 3724 ));
|
||||||
DATA(insert ( 3659 3614 3614 2 3656 ));
|
DATA(insert ( 3659 3614 3614 2 3656 ));
|
||||||
DATA(insert ( 3659 3614 3614 3 3657 ));
|
DATA(insert ( 3659 3614 3614 3 3657 ));
|
||||||
DATA(insert ( 3659 3614 3614 4 3658 ));
|
DATA(insert ( 3659 3614 3614 4 3658 ));
|
||||||
DATA(insert ( 3659 3614 3614 5 2700 ));
|
DATA(insert ( 3659 3614 3614 5 2700 ));
|
||||||
|
DATA(insert ( 3659 3614 3614 6 3921 ));
|
||||||
|
|
||||||
|
|
||||||
/* sp-gist */
|
/* sp-gist */
|
||||||
|
@ -3991,6 +3991,8 @@ DATA(insert OID = 2774 ( ginqueryarrayextract PGNSP PGUID 12 1 0 0 0 f f f f t
|
|||||||
DESCR("GIN array support");
|
DESCR("GIN array support");
|
||||||
DATA(insert OID = 2744 ( ginarrayconsistent PGNSP PGUID 12 1 0 0 0 f f f f t f i 8 0 16 "2281 21 2277 23 2281 2281 2281 2281" _null_ _null_ _null_ _null_ ginarrayconsistent _null_ _null_ _null_ ));
|
DATA(insert OID = 2744 ( ginarrayconsistent PGNSP PGUID 12 1 0 0 0 f f f f t f i 8 0 16 "2281 21 2277 23 2281 2281 2281 2281" _null_ _null_ _null_ _null_ ginarrayconsistent _null_ _null_ _null_ ));
|
||||||
DESCR("GIN array support");
|
DESCR("GIN array support");
|
||||||
|
DATA(insert OID = 3920 ( ginarraytriconsistent PGNSP PGUID 12 1 0 0 0 f f f f t f i 7 0 16 "2281 21 2277 23 2281 2281 2281" _null_ _null_ _null_ _null_ ginarraytriconsistent _null_ _null_ _null_ ));
|
||||||
|
DESCR("GIN array support");
|
||||||
DATA(insert OID = 3076 ( ginarrayextract PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 2281 "2277 2281" _null_ _null_ _null_ _null_ ginarrayextract_2args _null_ _null_ _null_ ));
|
DATA(insert OID = 3076 ( ginarrayextract PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 2281 "2277 2281" _null_ _null_ _null_ _null_ ginarrayextract_2args _null_ _null_ _null_ ));
|
||||||
DESCR("GIN array support (obsolete)");
|
DESCR("GIN array support (obsolete)");
|
||||||
|
|
||||||
@ -4334,6 +4336,8 @@ DATA(insert OID = 3657 ( gin_extract_tsquery PGNSP PGUID 12 1 0 0 0 f f f f t f
|
|||||||
DESCR("GIN tsvector support");
|
DESCR("GIN tsvector support");
|
||||||
DATA(insert OID = 3658 ( gin_tsquery_consistent PGNSP PGUID 12 1 0 0 0 f f f f t f i 8 0 16 "2281 21 3615 23 2281 2281 2281 2281" _null_ _null_ _null_ _null_ gin_tsquery_consistent _null_ _null_ _null_ ));
|
DATA(insert OID = 3658 ( gin_tsquery_consistent PGNSP PGUID 12 1 0 0 0 f f f f t f i 8 0 16 "2281 21 3615 23 2281 2281 2281 2281" _null_ _null_ _null_ _null_ gin_tsquery_consistent _null_ _null_ _null_ ));
|
||||||
DESCR("GIN tsvector support");
|
DESCR("GIN tsvector support");
|
||||||
|
DATA(insert OID = 3921 ( gin_tsquery_triconsistent PGNSP PGUID 12 1 0 0 0 f f f f t f i 7 0 16 "2281 21 3615 23 2281 2281 2281" _null_ _null_ _null_ _null_ gin_tsquery_triconsistent _null_ _null_ _null_ ));
|
||||||
|
DESCR("GIN tsvector support");
|
||||||
DATA(insert OID = 3724 ( gin_cmp_tslexeme PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 23 "25 25" _null_ _null_ _null_ _null_ gin_cmp_tslexeme _null_ _null_ _null_ ));
|
DATA(insert OID = 3724 ( gin_cmp_tslexeme PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 23 "25 25" _null_ _null_ _null_ _null_ gin_cmp_tslexeme _null_ _null_ _null_ ));
|
||||||
DESCR("GIN tsvector support");
|
DESCR("GIN tsvector support");
|
||||||
DATA(insert OID = 2700 ( gin_cmp_prefix PGNSP PGUID 12 1 0 0 0 f f f f t f i 4 0 23 "25 25 21 2281" _null_ _null_ _null_ _null_ gin_cmp_prefix _null_ _null_ _null_ ));
|
DATA(insert OID = 2700 ( gin_cmp_prefix PGNSP PGUID 12 1 0 0 0 f f f f t f i 4 0 23 "25 25 21 2281" _null_ _null_ _null_ _null_ gin_cmp_prefix _null_ _null_ _null_ ));
|
||||||
|
@ -149,6 +149,7 @@ extern Datum gin_cmp_tslexeme(PG_FUNCTION_ARGS);
|
|||||||
extern Datum gin_cmp_prefix(PG_FUNCTION_ARGS);
|
extern Datum gin_cmp_prefix(PG_FUNCTION_ARGS);
|
||||||
extern Datum gin_extract_tsquery(PG_FUNCTION_ARGS);
|
extern Datum gin_extract_tsquery(PG_FUNCTION_ARGS);
|
||||||
extern Datum gin_tsquery_consistent(PG_FUNCTION_ARGS);
|
extern Datum gin_tsquery_consistent(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum gin_tsquery_triconsistent(PG_FUNCTION_ARGS);
|
||||||
extern Datum gin_extract_tsvector_2args(PG_FUNCTION_ARGS);
|
extern Datum gin_extract_tsvector_2args(PG_FUNCTION_ARGS);
|
||||||
extern Datum gin_extract_tsquery_5args(PG_FUNCTION_ARGS);
|
extern Datum gin_extract_tsquery_5args(PG_FUNCTION_ARGS);
|
||||||
extern Datum gin_tsquery_consistent_6args(PG_FUNCTION_ARGS);
|
extern Datum gin_tsquery_consistent_6args(PG_FUNCTION_ARGS);
|
||||||
|
@ -1161,6 +1161,7 @@ extern Datum ginarrayextract(PG_FUNCTION_ARGS);
|
|||||||
extern Datum ginarrayextract_2args(PG_FUNCTION_ARGS);
|
extern Datum ginarrayextract_2args(PG_FUNCTION_ARGS);
|
||||||
extern Datum ginqueryarrayextract(PG_FUNCTION_ARGS);
|
extern Datum ginqueryarrayextract(PG_FUNCTION_ARGS);
|
||||||
extern Datum ginarrayconsistent(PG_FUNCTION_ARGS);
|
extern Datum ginarrayconsistent(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum ginarraytriconsistent(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
/* access/transam/twophase.c */
|
/* access/transam/twophase.c */
|
||||||
extern Datum pg_prepared_xact(PG_FUNCTION_ARGS);
|
extern Datum pg_prepared_xact(PG_FUNCTION_ARGS);
|
||||||
|
@ -1297,46 +1297,49 @@ WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
|
|||||||
|
|
||||||
-- Detect missing pg_amproc entries: should have as many support functions
|
-- Detect missing pg_amproc entries: should have as many support functions
|
||||||
-- as AM expects for each datatype combination supported by the opfamily.
|
-- as AM expects for each datatype combination supported by the opfamily.
|
||||||
-- btree/GiST/GIN each allow one optional support function, though.
|
SELECT * FROM (
|
||||||
SELECT p1.amname, p2.opfname, p3.amproclefttype, p3.amprocrighttype
|
SELECT p1.amname, p2.opfname, p3.amproclefttype, p3.amprocrighttype,
|
||||||
FROM pg_am AS p1, pg_opfamily AS p2, pg_amproc AS p3
|
array_agg(p3.amprocnum ORDER BY amprocnum) AS procnums
|
||||||
WHERE p2.opfmethod = p1.oid AND p3.amprocfamily = p2.oid AND
|
FROM pg_am AS p1, pg_opfamily AS p2, pg_amproc AS p3
|
||||||
(SELECT count(*) FROM pg_amproc AS p4
|
WHERE p2.opfmethod = p1.oid AND p3.amprocfamily = p2.oid
|
||||||
WHERE p4.amprocfamily = p2.oid AND
|
GROUP BY p1.amname, p2.opfname, p3.amproclefttype, p3.amprocrighttype
|
||||||
p4.amproclefttype = p3.amproclefttype AND
|
) AS t
|
||||||
p4.amprocrighttype = p3.amprocrighttype)
|
WHERE NOT (
|
||||||
NOT BETWEEN
|
-- btree has one mandatory and one optional support function.
|
||||||
(CASE WHEN p1.amname IN ('btree', 'gist', 'gin') THEN p1.amsupport - 1
|
-- hash has one support function, which is mandatory.
|
||||||
ELSE p1.amsupport END)
|
-- GiST has eight support functions, one of which is optional.
|
||||||
AND p1.amsupport;
|
-- GIN has six support functions. 1-3 are mandatory, 5 is optional, and
|
||||||
amname | opfname | amproclefttype | amprocrighttype
|
-- at least one of 4 and 6 must be given.
|
||||||
--------+---------+----------------+-----------------
|
-- SP-GiST has five support functions, all mandatory
|
||||||
|
amname = 'btree' AND procnums @> '{1}' OR
|
||||||
|
amname = 'hash' AND procnums = '{1}' OR
|
||||||
|
amname = 'gist' AND procnums @> '{1, 2, 3, 4, 5, 6, 7}' OR
|
||||||
|
amname = 'gin' AND (procnums @> '{1, 2, 3}' AND (procnums && '{4, 6}')) OR
|
||||||
|
amname = 'spgist' AND procnums = '{1, 2, 3, 4, 5}'
|
||||||
|
);
|
||||||
|
amname | opfname | amproclefttype | amprocrighttype | procnums
|
||||||
|
--------+---------+----------------+-----------------+----------
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
-- Also, check if there are any pg_opclass entries that don't seem to have
|
-- Also, check if there are any pg_opclass entries that don't seem to have
|
||||||
-- pg_amproc support. Again, opclasses with an optional support proc have
|
-- pg_amproc support.
|
||||||
-- to be checked specially.
|
SELECT * FROM (
|
||||||
SELECT amname, opcname, count(*)
|
SELECT amname, opcname, array_agg(amprocnum ORDER BY amprocnum) as procnums
|
||||||
FROM pg_am am JOIN pg_opclass op ON opcmethod = am.oid
|
FROM pg_am am JOIN pg_opclass op ON opcmethod = am.oid
|
||||||
LEFT JOIN pg_amproc p ON amprocfamily = opcfamily AND
|
LEFT JOIN pg_amproc p ON amprocfamily = opcfamily AND
|
||||||
amproclefttype = amprocrighttype AND amproclefttype = opcintype
|
amproclefttype = amprocrighttype AND amproclefttype = opcintype
|
||||||
WHERE am.amname <> 'btree' AND am.amname <> 'gist' AND am.amname <> 'gin'
|
GROUP BY amname, opcname, amprocfamily
|
||||||
GROUP BY amname, amsupport, opcname, amprocfamily
|
) AS t
|
||||||
HAVING count(*) != amsupport OR amprocfamily IS NULL;
|
WHERE NOT (
|
||||||
amname | opcname | count
|
-- same per-AM rules as above
|
||||||
--------+---------+-------
|
amname = 'btree' AND procnums @> '{1}' OR
|
||||||
(0 rows)
|
amname = 'hash' AND procnums = '{1}' OR
|
||||||
|
amname = 'gist' AND procnums @> '{1, 2, 3, 4, 5, 6, 7}' OR
|
||||||
SELECT amname, opcname, count(*)
|
amname = 'gin' AND (procnums @> '{1, 2, 3}' AND (procnums && '{4, 6}')) OR
|
||||||
FROM pg_am am JOIN pg_opclass op ON opcmethod = am.oid
|
amname = 'spgist' AND procnums = '{1, 2, 3, 4, 5}'
|
||||||
LEFT JOIN pg_amproc p ON amprocfamily = opcfamily AND
|
);
|
||||||
amproclefttype = amprocrighttype AND amproclefttype = opcintype
|
amname | opcname | procnums
|
||||||
WHERE am.amname = 'btree' OR am.amname = 'gist' OR am.amname = 'gin'
|
--------+---------+----------
|
||||||
GROUP BY amname, amsupport, opcname, amprocfamily
|
|
||||||
HAVING (count(*) != amsupport AND count(*) != amsupport - 1)
|
|
||||||
OR amprocfamily IS NULL;
|
|
||||||
amname | opcname | count
|
|
||||||
--------+---------+-------
|
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
-- Unfortunately, we can't check the amproc link very well because the
|
-- Unfortunately, we can't check the amproc link very well because the
|
||||||
|
@ -992,40 +992,46 @@ WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
|
|||||||
|
|
||||||
-- Detect missing pg_amproc entries: should have as many support functions
|
-- Detect missing pg_amproc entries: should have as many support functions
|
||||||
-- as AM expects for each datatype combination supported by the opfamily.
|
-- as AM expects for each datatype combination supported by the opfamily.
|
||||||
-- btree/GiST/GIN each allow one optional support function, though.
|
|
||||||
|
|
||||||
SELECT p1.amname, p2.opfname, p3.amproclefttype, p3.amprocrighttype
|
SELECT * FROM (
|
||||||
FROM pg_am AS p1, pg_opfamily AS p2, pg_amproc AS p3
|
SELECT p1.amname, p2.opfname, p3.amproclefttype, p3.amprocrighttype,
|
||||||
WHERE p2.opfmethod = p1.oid AND p3.amprocfamily = p2.oid AND
|
array_agg(p3.amprocnum ORDER BY amprocnum) AS procnums
|
||||||
(SELECT count(*) FROM pg_amproc AS p4
|
FROM pg_am AS p1, pg_opfamily AS p2, pg_amproc AS p3
|
||||||
WHERE p4.amprocfamily = p2.oid AND
|
WHERE p2.opfmethod = p1.oid AND p3.amprocfamily = p2.oid
|
||||||
p4.amproclefttype = p3.amproclefttype AND
|
GROUP BY p1.amname, p2.opfname, p3.amproclefttype, p3.amprocrighttype
|
||||||
p4.amprocrighttype = p3.amprocrighttype)
|
) AS t
|
||||||
NOT BETWEEN
|
WHERE NOT (
|
||||||
(CASE WHEN p1.amname IN ('btree', 'gist', 'gin') THEN p1.amsupport - 1
|
-- btree has one mandatory and one optional support function.
|
||||||
ELSE p1.amsupport END)
|
-- hash has one support function, which is mandatory.
|
||||||
AND p1.amsupport;
|
-- GiST has eight support functions, one of which is optional.
|
||||||
|
-- GIN has six support functions. 1-3 are mandatory, 5 is optional, and
|
||||||
|
-- at least one of 4 and 6 must be given.
|
||||||
|
-- SP-GiST has five support functions, all mandatory
|
||||||
|
amname = 'btree' AND procnums @> '{1}' OR
|
||||||
|
amname = 'hash' AND procnums = '{1}' OR
|
||||||
|
amname = 'gist' AND procnums @> '{1, 2, 3, 4, 5, 6, 7}' OR
|
||||||
|
amname = 'gin' AND (procnums @> '{1, 2, 3}' AND (procnums && '{4, 6}')) OR
|
||||||
|
amname = 'spgist' AND procnums = '{1, 2, 3, 4, 5}'
|
||||||
|
);
|
||||||
|
|
||||||
-- Also, check if there are any pg_opclass entries that don't seem to have
|
-- Also, check if there are any pg_opclass entries that don't seem to have
|
||||||
-- pg_amproc support. Again, opclasses with an optional support proc have
|
-- pg_amproc support.
|
||||||
-- to be checked specially.
|
|
||||||
|
|
||||||
SELECT amname, opcname, count(*)
|
SELECT * FROM (
|
||||||
FROM pg_am am JOIN pg_opclass op ON opcmethod = am.oid
|
SELECT amname, opcname, array_agg(amprocnum ORDER BY amprocnum) as procnums
|
||||||
|
FROM pg_am am JOIN pg_opclass op ON opcmethod = am.oid
|
||||||
LEFT JOIN pg_amproc p ON amprocfamily = opcfamily AND
|
LEFT JOIN pg_amproc p ON amprocfamily = opcfamily AND
|
||||||
amproclefttype = amprocrighttype AND amproclefttype = opcintype
|
amproclefttype = amprocrighttype AND amproclefttype = opcintype
|
||||||
WHERE am.amname <> 'btree' AND am.amname <> 'gist' AND am.amname <> 'gin'
|
GROUP BY amname, opcname, amprocfamily
|
||||||
GROUP BY amname, amsupport, opcname, amprocfamily
|
) AS t
|
||||||
HAVING count(*) != amsupport OR amprocfamily IS NULL;
|
WHERE NOT (
|
||||||
|
-- same per-AM rules as above
|
||||||
SELECT amname, opcname, count(*)
|
amname = 'btree' AND procnums @> '{1}' OR
|
||||||
FROM pg_am am JOIN pg_opclass op ON opcmethod = am.oid
|
amname = 'hash' AND procnums = '{1}' OR
|
||||||
LEFT JOIN pg_amproc p ON amprocfamily = opcfamily AND
|
amname = 'gist' AND procnums @> '{1, 2, 3, 4, 5, 6, 7}' OR
|
||||||
amproclefttype = amprocrighttype AND amproclefttype = opcintype
|
amname = 'gin' AND (procnums @> '{1, 2, 3}' AND (procnums && '{4, 6}')) OR
|
||||||
WHERE am.amname = 'btree' OR am.amname = 'gist' OR am.amname = 'gin'
|
amname = 'spgist' AND procnums = '{1, 2, 3, 4, 5}'
|
||||||
GROUP BY amname, amsupport, opcname, amprocfamily
|
);
|
||||||
HAVING (count(*) != amsupport AND count(*) != amsupport - 1)
|
|
||||||
OR amprocfamily IS NULL;
|
|
||||||
|
|
||||||
-- Unfortunately, we can't check the amproc link very well because the
|
-- Unfortunately, we can't check the amproc link very well because the
|
||||||
-- signature of the function may be different for different support routines
|
-- signature of the function may be different for different support routines
|
||||||
|
Loading…
x
Reference in New Issue
Block a user