mirror of
https://github.com/timescale/timescaledb.git
synced 2025-05-24 06:53:59 +08:00
Add limit option to scanner
This adds an option to set a limit on how many tuples to return in a relation scan using the scanner implemention. This avoids a common pattern of manually implementing limits in the tuple handling function.
This commit is contained in:
parent
66932cf8d5
commit
1d95dfbe44
@ -534,7 +534,6 @@ chunk_collision_scan(ChunkScanCtx *scanctx, Hypercube *cube)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Apply a function to each chunk in the scan context's hash table. If the limit
|
* Apply a function to each chunk in the scan context's hash table. If the limit
|
||||||
* is greater than zero only a limited number of chunks will be processed.
|
* is greater than zero only a limited number of chunks will be processed.
|
||||||
|
@ -31,9 +31,6 @@ chunk_constraint_tuple_found(TupleInfo *ti, void *data)
|
|||||||
|
|
||||||
chunk_constraint_fill(&chunk->constraints[chunk->num_constraints++], ti->tuple);
|
chunk_constraint_fill(&chunk->constraints[chunk->num_constraints++], ti->tuple);
|
||||||
|
|
||||||
if (chunk->capacity == chunk->num_constraints)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,6 +52,7 @@ chunk_constraint_scan_by_chunk_id(Chunk *chunk)
|
|||||||
.scantype = ScannerTypeIndex,
|
.scantype = ScannerTypeIndex,
|
||||||
.nkeys = 1,
|
.nkeys = 1,
|
||||||
.scankey = scankey,
|
.scankey = scankey,
|
||||||
|
.limit = chunk->num_constraints,
|
||||||
.data = chunk,
|
.data = chunk,
|
||||||
.filter = chunk_constraint_for_dimension_slice,
|
.filter = chunk_constraint_for_dimension_slice,
|
||||||
.tuple_found = chunk_constraint_tuple_found,
|
.tuple_found = chunk_constraint_tuple_found,
|
||||||
|
@ -255,6 +255,7 @@ dimension_scan(int32 hypertable_id, Oid main_table_relid, int16 num_dimensions)
|
|||||||
.index = catalog->tables[DIMENSION].index_ids[DIMENSION_HYPERTABLE_ID_IDX],
|
.index = catalog->tables[DIMENSION].index_ids[DIMENSION_HYPERTABLE_ID_IDX],
|
||||||
.scantype = ScannerTypeIndex,
|
.scantype = ScannerTypeIndex,
|
||||||
.nkeys = 1,
|
.nkeys = 1,
|
||||||
|
.limit = num_dimensions,
|
||||||
.scankey = scankey,
|
.scankey = scankey,
|
||||||
.data = space,
|
.data = space,
|
||||||
.tuple_found = dimension_tuple_found,
|
.tuple_found = dimension_tuple_found,
|
||||||
|
@ -53,18 +53,15 @@ typedef struct DimensionSliceScanData
|
|||||||
{
|
{
|
||||||
DimensionVec *slices;
|
DimensionVec *slices;
|
||||||
int limit;
|
int limit;
|
||||||
} DimensionSliceScanData;
|
} DimensionSliceScanData;
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
dimension_vec_tuple_found(TupleInfo *ti, void *data)
|
dimension_vec_tuple_found(TupleInfo *ti, void *data)
|
||||||
{
|
{
|
||||||
DimensionSliceScanData *scandata = data;
|
DimensionVec *slices = data;
|
||||||
DimensionSlice *slice = dimension_slice_from_tuple(ti->tuple);
|
DimensionSlice *slice = dimension_slice_from_tuple(ti->tuple);
|
||||||
|
|
||||||
dimension_vec_add_slice(&scandata->slices, slice);
|
dimension_vec_add_slice(&slices, slice);
|
||||||
|
|
||||||
if (scandata->limit == ti->count)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -73,7 +70,8 @@ static int
|
|||||||
dimension_slice_scan_limit_internal(ScanKeyData *scankey,
|
dimension_slice_scan_limit_internal(ScanKeyData *scankey,
|
||||||
Size num_scankeys,
|
Size num_scankeys,
|
||||||
tuple_found_func on_tuple_found,
|
tuple_found_func on_tuple_found,
|
||||||
void *scandata)
|
void *scandata,
|
||||||
|
int limit)
|
||||||
{
|
{
|
||||||
Catalog *catalog = catalog_get();
|
Catalog *catalog = catalog_get();
|
||||||
ScannerCtx scanCtx = {
|
ScannerCtx scanCtx = {
|
||||||
@ -83,6 +81,7 @@ dimension_slice_scan_limit_internal(ScanKeyData *scankey,
|
|||||||
.nkeys = num_scankeys,
|
.nkeys = num_scankeys,
|
||||||
.scankey = scankey,
|
.scankey = scankey,
|
||||||
.data = scandata,
|
.data = scandata,
|
||||||
|
.limit = limit,
|
||||||
.tuple_found = on_tuple_found,
|
.tuple_found = on_tuple_found,
|
||||||
.lockmode = AccessShareLock,
|
.lockmode = AccessShareLock,
|
||||||
.scandirection = ForwardScanDirection,
|
.scandirection = ForwardScanDirection,
|
||||||
@ -100,10 +99,7 @@ DimensionVec *
|
|||||||
dimension_slice_scan_limit(int32 dimension_id, int64 coordinate, int limit)
|
dimension_slice_scan_limit(int32 dimension_id, int64 coordinate, int limit)
|
||||||
{
|
{
|
||||||
ScanKeyData scankey[3];
|
ScanKeyData scankey[3];
|
||||||
DimensionSliceScanData data = {
|
DimensionVec *slices = dimension_vec_create(limit > 0 ? limit : DIMENSION_VEC_DEFAULT_SIZE);
|
||||||
.slices = dimension_vec_create(limit > 0 ? limit : DIMENSION_VEC_DEFAULT_SIZE),
|
|
||||||
.limit = limit,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Perform an index scan for slices matching the dimension's ID and which
|
* Perform an index scan for slices matching the dimension's ID and which
|
||||||
@ -116,9 +112,9 @@ dimension_slice_scan_limit(int32 dimension_id, int64 coordinate, int limit)
|
|||||||
ScanKeyInit(&scankey[2], Anum_dimension_slice_dimension_id_range_start_range_end_idx_range_end,
|
ScanKeyInit(&scankey[2], Anum_dimension_slice_dimension_id_range_start_range_end_idx_range_end,
|
||||||
BTGreaterStrategyNumber, F_INT8GT, Int64GetDatum(coordinate));
|
BTGreaterStrategyNumber, F_INT8GT, Int64GetDatum(coordinate));
|
||||||
|
|
||||||
dimension_slice_scan_limit_internal(scankey, 3, dimension_vec_tuple_found, &data);
|
dimension_slice_scan_limit_internal(scankey, 3, dimension_vec_tuple_found, slices, limit);
|
||||||
|
|
||||||
return dimension_vec_sort(&data.slices);
|
return dimension_vec_sort(&slices);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -130,10 +126,7 @@ DimensionVec *
|
|||||||
dimension_slice_collision_scan_limit(int32 dimension_id, int64 range_start, int64 range_end, int limit)
|
dimension_slice_collision_scan_limit(int32 dimension_id, int64 range_start, int64 range_end, int limit)
|
||||||
{
|
{
|
||||||
ScanKeyData scankey[3];
|
ScanKeyData scankey[3];
|
||||||
DimensionSliceScanData data = {
|
DimensionVec *slices = dimension_vec_create(limit > 0 ? limit : DIMENSION_VEC_DEFAULT_SIZE);
|
||||||
.slices = dimension_vec_create(limit > 0 ? limit : DIMENSION_VEC_DEFAULT_SIZE),
|
|
||||||
.limit = limit,
|
|
||||||
};
|
|
||||||
|
|
||||||
ScanKeyInit(&scankey[0], Anum_dimension_slice_dimension_id_range_start_range_end_idx_dimension_id,
|
ScanKeyInit(&scankey[0], Anum_dimension_slice_dimension_id_range_start_range_end_idx_dimension_id,
|
||||||
BTEqualStrategyNumber, F_INT4EQ, Int32GetDatum(dimension_id));
|
BTEqualStrategyNumber, F_INT4EQ, Int32GetDatum(dimension_id));
|
||||||
@ -142,9 +135,9 @@ dimension_slice_collision_scan_limit(int32 dimension_id, int64 range_start, int6
|
|||||||
ScanKeyInit(&scankey[2], Anum_dimension_slice_dimension_id_range_start_range_end_idx_range_end,
|
ScanKeyInit(&scankey[2], Anum_dimension_slice_dimension_id_range_start_range_end_idx_range_end,
|
||||||
BTGreaterStrategyNumber, F_INT8GT, Int64GetDatum(range_start));
|
BTGreaterStrategyNumber, F_INT8GT, Int64GetDatum(range_start));
|
||||||
|
|
||||||
dimension_slice_scan_limit_internal(scankey, 3, dimension_vec_tuple_found, &data);
|
dimension_slice_scan_limit_internal(scankey, 3, dimension_vec_tuple_found, slices, limit);
|
||||||
|
|
||||||
return dimension_vec_sort(&data.slices);
|
return dimension_vec_sort(&slices);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -173,7 +166,7 @@ dimension_slice_scan_for_existing(DimensionSlice *slice)
|
|||||||
ScanKeyInit(&scankey[2], Anum_dimension_slice_dimension_id_range_start_range_end_idx_range_end,
|
ScanKeyInit(&scankey[2], Anum_dimension_slice_dimension_id_range_start_range_end_idx_range_end,
|
||||||
BTEqualStrategyNumber, F_INT8EQ, Int64GetDatum(slice->fd.range_end));
|
BTEqualStrategyNumber, F_INT8EQ, Int64GetDatum(slice->fd.range_end));
|
||||||
|
|
||||||
dimension_slice_scan_limit_internal(scankey, 3, dimension_slice_fill, &slice);
|
dimension_slice_scan_limit_internal(scankey, 3, dimension_slice_fill, &slice, 1);
|
||||||
|
|
||||||
return slice;
|
return slice;
|
||||||
}
|
}
|
||||||
@ -200,6 +193,7 @@ dimension_slice_scan_by_id(int32 dimension_slice_id)
|
|||||||
.nkeys = 1,
|
.nkeys = 1,
|
||||||
.scankey = scankey,
|
.scankey = scankey,
|
||||||
.data = &slice,
|
.data = &slice,
|
||||||
|
.limit = 1,
|
||||||
.tuple_found = dimension_slice_tuple_found,
|
.tuple_found = dimension_slice_tuple_found,
|
||||||
.lockmode = AccessShareLock,
|
.lockmode = AccessShareLock,
|
||||||
.scandirection = ForwardScanDirection,
|
.scandirection = ForwardScanDirection,
|
||||||
|
@ -175,7 +175,6 @@ scanner_scan(ScannerCtx *ctx)
|
|||||||
|
|
||||||
while (is_valid)
|
while (is_valid)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (ctx->filter == NULL || ctx->filter(&ictx.tinfo, ctx->data))
|
if (ctx->filter == NULL || ctx->filter(&ictx.tinfo, ctx->data))
|
||||||
{
|
{
|
||||||
ictx.tinfo.count++;
|
ictx.tinfo.count++;
|
||||||
@ -203,6 +202,10 @@ scanner_scan(ScannerCtx *ctx)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if limit is reached */
|
||||||
|
if (ctx->limit > 0 && ictx.tinfo.count >= ctx->limit)
|
||||||
|
break;
|
||||||
|
|
||||||
is_valid = scanner->getnext(&ictx);
|
is_valid = scanner->getnext(&ictx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,9 @@ typedef struct ScannerCtx
|
|||||||
ScannerType scantype;
|
ScannerType scantype;
|
||||||
ScanKey scankey;
|
ScanKey scankey;
|
||||||
int nkeys,
|
int nkeys,
|
||||||
norderbys;
|
norderbys,
|
||||||
|
limit; /* Limit on number of tuples to return. 0 or
|
||||||
|
* less means no limit */
|
||||||
bool want_itup;
|
bool want_itup;
|
||||||
LOCKMODE lockmode;
|
LOCKMODE lockmode;
|
||||||
struct
|
struct
|
||||||
|
Loading…
x
Reference in New Issue
Block a user