mirror of
https://github.com/pgvector/pgvector.git
synced 2026-07-22 20:15:46 +08:00
Compare commits
1 Commits
pairinghea
...
bound2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5f66019f49 |
@@ -1,8 +1,3 @@
|
|||||||
## 0.4.2 (unreleased)
|
|
||||||
|
|
||||||
- Added notice when index created with little data
|
|
||||||
- Fixed installation error with Postgres 12.0-12.2
|
|
||||||
|
|
||||||
## 0.4.1 (2023-03-21)
|
## 0.4.1 (2023-03-21)
|
||||||
|
|
||||||
- Improved performance of cosine distance
|
- Improved performance of cosine distance
|
||||||
|
|||||||
31
README.md
31
README.md
@@ -2,11 +2,7 @@
|
|||||||
|
|
||||||
Open-source vector similarity search for Postgres
|
Open-source vector similarity search for Postgres
|
||||||
|
|
||||||
Supports
|
Supports exact and approximate nearest neighbor search for L2 distance, inner product, and cosine distance
|
||||||
|
|
||||||
- exact and approximate nearest neighbor search
|
|
||||||
- L2 distance, inner product, and cosine distance
|
|
||||||
- any [language](#languages) with a Postgres client
|
|
||||||
|
|
||||||
[](https://github.com/pgvector/pgvector/actions)
|
[](https://github.com/pgvector/pgvector/actions)
|
||||||
|
|
||||||
@@ -40,7 +36,7 @@ Create a vector column with 3 dimensions
|
|||||||
CREATE TABLE items (id bigserial PRIMARY KEY, embedding vector(3));
|
CREATE TABLE items (id bigserial PRIMARY KEY, embedding vector(3));
|
||||||
```
|
```
|
||||||
|
|
||||||
Insert vectors
|
Insert values
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
INSERT INTO items (embedding) VALUES ('[1,2,3]'), ('[4,5,6]');
|
INSERT INTO items (embedding) VALUES ('[1,2,3]'), ('[4,5,6]');
|
||||||
@@ -128,7 +124,7 @@ SELECT embedding <-> '[3,1,2]' AS distance FROM items;
|
|||||||
For inner product, multiply by -1 (since `<#>` returns the negative inner product)
|
For inner product, multiply by -1 (since `<#>` returns the negative inner product)
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT (embedding <#> '[3,1,2]') * -1 AS inner_product FROM items;
|
SELECT -1 * (embedding <#> '[3,1,2]') AS inner_product FROM items;
|
||||||
```
|
```
|
||||||
|
|
||||||
For cosine similarity, use 1 - cosine distance
|
For cosine similarity, use 1 - cosine distance
|
||||||
@@ -137,7 +133,7 @@ For cosine similarity, use 1 - cosine distance
|
|||||||
SELECT 1 - (embedding <=> '[3,1,2]') AS cosine_similarity FROM items;
|
SELECT 1 - (embedding <=> '[3,1,2]') AS cosine_similarity FROM items;
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Aggregates
|
#### Averaging
|
||||||
|
|
||||||
Average vectors
|
Average vectors
|
||||||
|
|
||||||
@@ -157,11 +153,15 @@ By default, pgvector performs exact nearest neighbor search, which provides perf
|
|||||||
|
|
||||||
You can add an index to use approximate nearest neighbor search, which trades some recall for performance. Unlike typical indexes, you will see different results for queries after adding an approximate index.
|
You can add an index to use approximate nearest neighbor search, which trades some recall for performance. Unlike typical indexes, you will see different results for queries after adding an approximate index.
|
||||||
|
|
||||||
Three keys to achieving good recall are:
|
Two keys to achieving good recall are:
|
||||||
|
|
||||||
1. Create the index *after* the table has some data
|
1. Create the index *after* the table has some data
|
||||||
2. Choose an appropriate number of lists - a good place to start is `rows / 1000` for up to 1M rows and `sqrt(rows)` for over 1M rows
|
2. Choose an appropriate number of lists (lower is better for recall, higher is better for speed)
|
||||||
3. When querying, specify an appropriate number of [probes](#query-options) (higher is better for recall, lower is better for speed) - a good place to start is `lists / 10` for up to 1M rows and `sqrt(lists)` for over 1M rows
|
|
||||||
|
A good place to start is:
|
||||||
|
|
||||||
|
- `rows / 1000` for up to 1M rows
|
||||||
|
- `sqrt(rows)` for over 1M rows
|
||||||
|
|
||||||
Add an index for each distance function you want to use.
|
Add an index for each distance function you want to use.
|
||||||
|
|
||||||
@@ -190,7 +190,7 @@ Vectors with up to 2,000 dimensions can be indexed.
|
|||||||
Specify the number of probes (1 by default)
|
Specify the number of probes (1 by default)
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SET ivfflat.probes = 10;
|
SET ivfflat.probes = 1;
|
||||||
```
|
```
|
||||||
|
|
||||||
A higher value provides better recall at the cost of speed, and it can be set to the number of lists for exact nearest neighbor search (at which point the planner won’t use the index)
|
A higher value provides better recall at the cost of speed, and it can be set to the number of lists for exact nearest neighbor search (at which point the planner won’t use the index)
|
||||||
@@ -199,7 +199,7 @@ Use `SET LOCAL` inside a transaction to set it for a single query
|
|||||||
|
|
||||||
```sql
|
```sql
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SET LOCAL ivfflat.probes = 10;
|
SET LOCAL ivfflat.probes = 1;
|
||||||
SELECT ...
|
SELECT ...
|
||||||
COMMIT;
|
COMMIT;
|
||||||
```
|
```
|
||||||
@@ -279,10 +279,8 @@ Language | Libraries / Examples
|
|||||||
--- | ---
|
--- | ---
|
||||||
C++ | [pgvector-cpp](https://github.com/pgvector/pgvector-cpp)
|
C++ | [pgvector-cpp](https://github.com/pgvector/pgvector-cpp)
|
||||||
C# | [pgvector-dotnet](https://github.com/pgvector/pgvector-dotnet)
|
C# | [pgvector-dotnet](https://github.com/pgvector/pgvector-dotnet)
|
||||||
Crystal | [pgvector-crystal](https://github.com/pgvector/pgvector-crystal)
|
|
||||||
Elixir | [pgvector-elixir](https://github.com/pgvector/pgvector-elixir)
|
Elixir | [pgvector-elixir](https://github.com/pgvector/pgvector-elixir)
|
||||||
Go | [pgvector-go](https://github.com/pgvector/pgvector-go)
|
Go | [pgvector-go](https://github.com/pgvector/pgvector-go)
|
||||||
Haskell | [pgvector-haskell](https://github.com/pgvector/pgvector-haskell)
|
|
||||||
Java, Scala | [pgvector-java](https://github.com/pgvector/pgvector-java)
|
Java, Scala | [pgvector-java](https://github.com/pgvector/pgvector-java)
|
||||||
Julia | [pgvector-julia](https://github.com/pgvector/pgvector-julia)
|
Julia | [pgvector-julia](https://github.com/pgvector/pgvector-julia)
|
||||||
Lua | [pgvector-lua](https://github.com/pgvector/pgvector-lua)
|
Lua | [pgvector-lua](https://github.com/pgvector/pgvector-lua)
|
||||||
@@ -293,7 +291,6 @@ Python | [pgvector-python](https://github.com/pgvector/pgvector-python)
|
|||||||
R | [pgvector-r](https://github.com/pgvector/pgvector-r)
|
R | [pgvector-r](https://github.com/pgvector/pgvector-r)
|
||||||
Ruby | [pgvector-ruby](https://github.com/pgvector/pgvector-ruby), [Neighbor](https://github.com/ankane/neighbor)
|
Ruby | [pgvector-ruby](https://github.com/pgvector/pgvector-ruby), [Neighbor](https://github.com/ankane/neighbor)
|
||||||
Rust | [pgvector-rust](https://github.com/pgvector/pgvector-rust)
|
Rust | [pgvector-rust](https://github.com/pgvector/pgvector-rust)
|
||||||
Swift | [pgvector-swift](https://github.com/pgvector/pgvector-swift)
|
|
||||||
|
|
||||||
## Frequently Asked Questions
|
## Frequently Asked Questions
|
||||||
|
|
||||||
@@ -448,7 +445,7 @@ To request a new extension on other providers:
|
|||||||
- Google Cloud SQL - vote or comment on [this page](https://issuetracker.google.com/issues/265172065)
|
- Google Cloud SQL - vote or comment on [this page](https://issuetracker.google.com/issues/265172065)
|
||||||
- Azure Database - vote or comment on [this page](https://feedback.azure.com/d365community/idea/7b423322-6189-ed11-a81b-000d3ae49307)
|
- Azure Database - vote or comment on [this page](https://feedback.azure.com/d365community/idea/7b423322-6189-ed11-a81b-000d3ae49307)
|
||||||
- DigitalOcean Managed Databases - vote or comment on [this page](https://ideas.digitalocean.com/app-framework-services/p/pgvector-extension-for-postgresql)
|
- DigitalOcean Managed Databases - vote or comment on [this page](https://ideas.digitalocean.com/app-framework-services/p/pgvector-extension-for-postgresql)
|
||||||
- Heroku Postgres - vote or comment on [this page](https://github.com/heroku/roadmap/issues/156)
|
- Render - vote or comment on [this page](https://feedback.render.com/features/p/add-pgvector-extension-to-postgresql)
|
||||||
|
|
||||||
## Upgrading
|
## Upgrading
|
||||||
|
|
||||||
|
|||||||
@@ -431,18 +431,8 @@ ComputeCenters(IvfflatBuildState * buildstate)
|
|||||||
/* TODO Ensure within maintenance_work_mem */
|
/* TODO Ensure within maintenance_work_mem */
|
||||||
buildstate->samples = VectorArrayInit(numSamples, buildstate->dimensions);
|
buildstate->samples = VectorArrayInit(numSamples, buildstate->dimensions);
|
||||||
if (buildstate->heap != NULL)
|
if (buildstate->heap != NULL)
|
||||||
{
|
|
||||||
SampleRows(buildstate);
|
SampleRows(buildstate);
|
||||||
|
|
||||||
if (buildstate->samples->length < buildstate->lists)
|
|
||||||
{
|
|
||||||
ereport(NOTICE,
|
|
||||||
(errmsg("ivfflat index created with little data"),
|
|
||||||
errdetail("this will cause poor recall"),
|
|
||||||
errhint("drop the index until the table has more data")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Calculate centers */
|
/* Calculate centers */
|
||||||
IvfflatBench("k-means", IvfflatKmeans(buildstate->index, buildstate->samples, buildstate->centers));
|
IvfflatBench("k-means", IvfflatKmeans(buildstate->index, buildstate->samples, buildstate->centers));
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
int ivfflat_probes;
|
int ivfflat_probes;
|
||||||
|
int ivfflat_bound;
|
||||||
static relopt_kind ivfflat_relopt_kind;
|
static relopt_kind ivfflat_relopt_kind;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -32,6 +33,10 @@ _PG_init(void)
|
|||||||
DefineCustomIntVariable("ivfflat.probes", "Sets the number of probes",
|
DefineCustomIntVariable("ivfflat.probes", "Sets the number of probes",
|
||||||
"Valid range is 1..lists.", &ivfflat_probes,
|
"Valid range is 1..lists.", &ivfflat_probes,
|
||||||
1, 1, IVFFLAT_MAX_LISTS, PGC_USERSET, 0, NULL, NULL, NULL);
|
1, 1, IVFFLAT_MAX_LISTS, PGC_USERSET, 0, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
DefineCustomIntVariable("ivfflat.bound", "Sets the max results from index (experimental)",
|
||||||
|
NULL, &ivfflat_bound,
|
||||||
|
0, 0, INT_MAX, PGC_USERSET, 0, NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -78,6 +78,7 @@
|
|||||||
|
|
||||||
/* Variables */
|
/* Variables */
|
||||||
extern int ivfflat_probes;
|
extern int ivfflat_probes;
|
||||||
|
extern int ivfflat_bound;
|
||||||
|
|
||||||
/* Exported functions */
|
/* Exported functions */
|
||||||
PGDLLEXPORT void _PG_init(void);
|
PGDLLEXPORT void _PG_init(void);
|
||||||
@@ -187,14 +188,6 @@ typedef struct IvfflatScanList
|
|||||||
double distance;
|
double distance;
|
||||||
} IvfflatScanList;
|
} IvfflatScanList;
|
||||||
|
|
||||||
typedef struct IvfflatScanItem
|
|
||||||
{
|
|
||||||
pairingheap_node ph_node;
|
|
||||||
BlockNumber searchPage;
|
|
||||||
double distance;
|
|
||||||
ItemPointerData tid;
|
|
||||||
} IvfflatScanItem;
|
|
||||||
|
|
||||||
typedef struct IvfflatScanOpaqueData
|
typedef struct IvfflatScanOpaqueData
|
||||||
{
|
{
|
||||||
int probes;
|
int probes;
|
||||||
@@ -212,13 +205,6 @@ typedef struct IvfflatScanOpaqueData
|
|||||||
FmgrInfo *normprocinfo;
|
FmgrInfo *normprocinfo;
|
||||||
Oid collation;
|
Oid collation;
|
||||||
|
|
||||||
/* Items */
|
|
||||||
int maxItems;
|
|
||||||
int itemCount;
|
|
||||||
pairingheap *itemQueue;
|
|
||||||
IvfflatScanItem *items;
|
|
||||||
IvfflatScanItem **sortedItems;
|
|
||||||
|
|
||||||
/* Lists */
|
/* Lists */
|
||||||
pairingheap *listQueue;
|
pairingheap *listQueue;
|
||||||
IvfflatScanList lists[FLEXIBLE_ARRAY_MEMBER]; /* must come last */
|
IvfflatScanList lists[FLEXIBLE_ARRAY_MEMBER]; /* must come last */
|
||||||
|
|||||||
143
src/ivfscan.c
143
src/ivfscan.c
@@ -26,21 +26,6 @@ CompareLists(const pairingheap_node *a, const pairingheap_node *b, void *arg)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Compare item distances
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
CompareItems(const pairingheap_node *a, const pairingheap_node *b, void *arg)
|
|
||||||
{
|
|
||||||
if (((const IvfflatScanItem *) a)->distance > ((const IvfflatScanItem *) b)->distance)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (((const IvfflatScanItem *) a)->distance < ((const IvfflatScanItem *) b)->distance)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get lists and sort by distance
|
* Get lists and sort by distance
|
||||||
*/
|
*/
|
||||||
@@ -126,10 +111,13 @@ GetScanItems(IndexScanDesc scan, Datum value)
|
|||||||
Datum datum;
|
Datum datum;
|
||||||
bool isnull;
|
bool isnull;
|
||||||
TupleDesc tupdesc = RelationGetDescr(scan->indexRelation);
|
TupleDesc tupdesc = RelationGetDescr(scan->indexRelation);
|
||||||
int i;
|
double tuples = 0;
|
||||||
double distance;
|
|
||||||
IvfflatScanItem *scanitem;
|
#if PG_VERSION_NUM >= 120000
|
||||||
double maxDistance = DBL_MAX;
|
TupleTableSlot *slot = MakeSingleTupleTableSlot(so->tupdesc, &TTSOpsVirtual);
|
||||||
|
#else
|
||||||
|
TupleTableSlot *slot = MakeSingleTupleTableSlot(so->tupdesc);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reuse same set of shared buffers for scan
|
* Reuse same set of shared buffers for scan
|
||||||
@@ -138,6 +126,10 @@ GetScanItems(IndexScanDesc scan, Datum value)
|
|||||||
*/
|
*/
|
||||||
BufferAccessStrategy bas = GetAccessStrategy(BAS_BULKREAD);
|
BufferAccessStrategy bas = GetAccessStrategy(BAS_BULKREAD);
|
||||||
|
|
||||||
|
/* Set the max number of results */
|
||||||
|
if (ivfflat_bound > 0)
|
||||||
|
tuplesort_set_bound(so->sortstate, ivfflat_bound);
|
||||||
|
|
||||||
/* Search closest probes lists */
|
/* Search closest probes lists */
|
||||||
while (!pairingheap_is_empty(so->listQueue))
|
while (!pairingheap_is_empty(so->listQueue))
|
||||||
{
|
{
|
||||||
@@ -155,40 +147,25 @@ GetScanItems(IndexScanDesc scan, Datum value)
|
|||||||
{
|
{
|
||||||
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offno));
|
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offno));
|
||||||
datum = index_getattr(itup, 1, tupdesc, &isnull);
|
datum = index_getattr(itup, 1, tupdesc, &isnull);
|
||||||
distance = DatumGetFloat8(FunctionCall2Coll(so->procinfo, so->collation, datum, value));
|
|
||||||
|
|
||||||
if (so->itemCount < so->maxItems)
|
/*
|
||||||
{
|
* Add virtual tuple
|
||||||
scanitem = &so->items[so->itemCount];
|
*
|
||||||
scanitem->searchPage = searchPage;
|
* Use procinfo from the index instead of scan key for
|
||||||
scanitem->tid = itup->t_tid;
|
* performance
|
||||||
scanitem->distance = distance;
|
*/
|
||||||
so->itemCount++;
|
ExecClearTuple(slot);
|
||||||
|
slot->tts_values[0] = FunctionCall2Coll(so->procinfo, so->collation, datum, value);
|
||||||
|
slot->tts_isnull[0] = false;
|
||||||
|
slot->tts_values[1] = PointerGetDatum(&itup->t_tid);
|
||||||
|
slot->tts_isnull[1] = false;
|
||||||
|
slot->tts_values[2] = Int32GetDatum((int) searchPage);
|
||||||
|
slot->tts_isnull[2] = false;
|
||||||
|
ExecStoreVirtualTuple(slot);
|
||||||
|
|
||||||
/* Add to heap */
|
tuplesort_puttupleslot(so->sortstate, slot);
|
||||||
pairingheap_add(so->itemQueue, &scanitem->ph_node);
|
|
||||||
|
|
||||||
/* Calculate max distance */
|
tuples++;
|
||||||
if (so->itemCount == so->maxItems)
|
|
||||||
{
|
|
||||||
maxDistance = ((IvfflatScanItem *) pairingheap_first(so->itemQueue))->distance;
|
|
||||||
scanitem = &so->items[so->itemCount];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (distance < maxDistance)
|
|
||||||
{
|
|
||||||
/* Reuse */
|
|
||||||
scanitem->searchPage = searchPage;
|
|
||||||
scanitem->tid = itup->t_tid;
|
|
||||||
scanitem->distance = distance;
|
|
||||||
pairingheap_add(so->itemQueue, &scanitem->ph_node);
|
|
||||||
|
|
||||||
/* Remove */
|
|
||||||
scanitem = (IvfflatScanItem *) pairingheap_remove_first(so->itemQueue);
|
|
||||||
|
|
||||||
/* Update max distance */
|
|
||||||
maxDistance = ((IvfflatScanItem *) pairingheap_first(so->itemQueue))->distance;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
searchPage = IvfflatPageGetOpaque(page)->nextblkno;
|
searchPage = IvfflatPageGetOpaque(page)->nextblkno;
|
||||||
@@ -197,10 +174,14 @@ GetScanItems(IndexScanDesc scan, Datum value)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < so->itemCount; i++)
|
/* TODO Scan more lists */
|
||||||
so->sortedItems[i] = (IvfflatScanItem *) pairingheap_remove_first(so->itemQueue);
|
if (tuples < 100)
|
||||||
|
ereport(DEBUG1,
|
||||||
|
(errmsg("index scan found few tuples"),
|
||||||
|
errdetail("index may have been created without data or lists is too high"),
|
||||||
|
errhint("recreate the index and possibly decrease lists")));
|
||||||
|
|
||||||
Assert(pairingheap_is_empty(so->itemQueue));
|
tuplesort_performsort(so->sortstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -212,6 +193,10 @@ ivfflatbeginscan(Relation index, int nkeys, int norderbys)
|
|||||||
IndexScanDesc scan;
|
IndexScanDesc scan;
|
||||||
IvfflatScanOpaque so;
|
IvfflatScanOpaque so;
|
||||||
int lists;
|
int lists;
|
||||||
|
AttrNumber attNums[] = {1};
|
||||||
|
Oid sortOperators[] = {Float8LessOperator};
|
||||||
|
Oid sortCollations[] = {InvalidOid};
|
||||||
|
bool nullsFirstFlags[] = {false};
|
||||||
int probes = ivfflat_probes;
|
int probes = ivfflat_probes;
|
||||||
|
|
||||||
scan = RelationGetIndexScan(index, nkeys, norderbys);
|
scan = RelationGetIndexScan(index, nkeys, norderbys);
|
||||||
@@ -230,13 +215,26 @@ ivfflatbeginscan(Relation index, int nkeys, int norderbys)
|
|||||||
so->normprocinfo = IvfflatOptionalProcInfo(index, IVFFLAT_NORM_PROC);
|
so->normprocinfo = IvfflatOptionalProcInfo(index, IVFFLAT_NORM_PROC);
|
||||||
so->collation = index->rd_indcollation[0];
|
so->collation = index->rd_indcollation[0];
|
||||||
|
|
||||||
so->listQueue = pairingheap_allocate(CompareLists, scan);
|
/* Create tuple description for sorting */
|
||||||
|
#if PG_VERSION_NUM >= 120000
|
||||||
|
so->tupdesc = CreateTemplateTupleDesc(3);
|
||||||
|
#else
|
||||||
|
so->tupdesc = CreateTemplateTupleDesc(3, false);
|
||||||
|
#endif
|
||||||
|
TupleDescInitEntry(so->tupdesc, (AttrNumber) 1, "distance", FLOAT8OID, -1, 0);
|
||||||
|
TupleDescInitEntry(so->tupdesc, (AttrNumber) 2, "tid", TIDOID, -1, 0);
|
||||||
|
TupleDescInitEntry(so->tupdesc, (AttrNumber) 3, "indexblkno", INT4OID, -1, 0);
|
||||||
|
|
||||||
so->maxItems = 10;
|
/* Prep sort */
|
||||||
so->itemCount = 0;
|
so->sortstate = tuplesort_begin_heap(so->tupdesc, 1, attNums, sortOperators, sortCollations, nullsFirstFlags, work_mem, NULL, false);
|
||||||
so->itemQueue = pairingheap_allocate(CompareItems, scan);
|
|
||||||
so->items = palloc(sizeof(IvfflatScanItem) * (so->maxItems + 1));
|
#if PG_VERSION_NUM >= 120000
|
||||||
so->sortedItems = palloc(sizeof(IvfflatScanItem *) * so->maxItems);
|
so->slot = MakeSingleTupleTableSlot(so->tupdesc, &TTSOpsMinimalTuple);
|
||||||
|
#else
|
||||||
|
so->slot = MakeSingleTupleTableSlot(so->tupdesc);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
so->listQueue = pairingheap_allocate(CompareLists, scan);
|
||||||
|
|
||||||
scan->opaque = so;
|
scan->opaque = so;
|
||||||
|
|
||||||
@@ -251,10 +249,13 @@ ivfflatrescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int
|
|||||||
{
|
{
|
||||||
IvfflatScanOpaque so = (IvfflatScanOpaque) scan->opaque;
|
IvfflatScanOpaque so = (IvfflatScanOpaque) scan->opaque;
|
||||||
|
|
||||||
|
#if PG_VERSION_NUM >= 130000
|
||||||
|
if (!so->first)
|
||||||
|
tuplesort_reset(so->sortstate);
|
||||||
|
#endif
|
||||||
|
|
||||||
so->first = true;
|
so->first = true;
|
||||||
pairingheap_reset(so->listQueue);
|
pairingheap_reset(so->listQueue);
|
||||||
pairingheap_reset(so->itemQueue);
|
|
||||||
so->itemCount = 0;
|
|
||||||
|
|
||||||
if (keys && scan->numberOfKeys > 0)
|
if (keys && scan->numberOfKeys > 0)
|
||||||
memmove(scan->keyData, keys, scan->numberOfKeys * sizeof(ScanKeyData));
|
memmove(scan->keyData, keys, scan->numberOfKeys * sizeof(ScanKeyData));
|
||||||
@@ -314,18 +315,15 @@ ivfflatgettuple(IndexScanDesc scan, ScanDirection dir)
|
|||||||
pfree(DatumGetPointer(value));
|
pfree(DatumGetPointer(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (so->itemCount > 0)
|
if (tuplesort_gettupleslot(so->sortstate, true, false, so->slot, NULL))
|
||||||
{
|
{
|
||||||
IvfflatScanItem *scanitem;
|
ItemPointer tid = (ItemPointer) DatumGetPointer(slot_getattr(so->slot, 2, &so->isnull));
|
||||||
|
BlockNumber indexblkno = DatumGetInt32(slot_getattr(so->slot, 3, &so->isnull));
|
||||||
so->itemCount--;
|
|
||||||
|
|
||||||
scanitem = so->sortedItems[so->itemCount];
|
|
||||||
|
|
||||||
#if PG_VERSION_NUM >= 120000
|
#if PG_VERSION_NUM >= 120000
|
||||||
scan->xs_heaptid = scanitem->tid;
|
scan->xs_heaptid = *tid;
|
||||||
#else
|
#else
|
||||||
scan->xs_ctup.t_self = scanitem->tid;
|
scan->xs_ctup.t_self = *tid;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (BufferIsValid(so->buf))
|
if (BufferIsValid(so->buf))
|
||||||
@@ -337,7 +335,7 @@ ivfflatgettuple(IndexScanDesc scan, ScanDirection dir)
|
|||||||
*
|
*
|
||||||
* https://www.postgresql.org/docs/current/index-locking.html
|
* https://www.postgresql.org/docs/current/index-locking.html
|
||||||
*/
|
*/
|
||||||
so->buf = ReadBuffer(scan->indexRelation, scanitem->searchPage);
|
so->buf = ReadBuffer(scan->indexRelation, indexblkno);
|
||||||
|
|
||||||
scan->xs_recheckorderby = false;
|
scan->xs_recheckorderby = false;
|
||||||
return true;
|
return true;
|
||||||
@@ -359,10 +357,7 @@ ivfflatendscan(IndexScanDesc scan)
|
|||||||
ReleaseBuffer(so->buf);
|
ReleaseBuffer(so->buf);
|
||||||
|
|
||||||
pairingheap_free(so->listQueue);
|
pairingheap_free(so->listQueue);
|
||||||
|
tuplesort_end(so->sortstate);
|
||||||
pairingheap_free(so->itemQueue);
|
|
||||||
pfree(so->items);
|
|
||||||
pfree(so->sortedItems);
|
|
||||||
|
|
||||||
pfree(so);
|
pfree(so);
|
||||||
scan->opaque = NULL;
|
scan->opaque = NULL;
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ CheckStateArray(ArrayType *statearray, const char *caller)
|
|||||||
return (float8 *) ARR_DATA_PTR(statearray);
|
return (float8 *) ARR_DATA_PTR(statearray);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PG_VERSION_NUM < 120003
|
#if PG_VERSION_NUM < 120000
|
||||||
static pg_noinline void
|
static pg_noinline void
|
||||||
float_overflow_error(void)
|
float_overflow_error(void)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user