|
14 | 14 | #include "postgres.h" |
15 | 15 |
|
16 | 16 | #include "access/detoast.h" |
17 | | -#include "access/genam.h" |
18 | | -#include "access/heaptoast.h" |
19 | 17 | #include "access/table.h" |
| 18 | +#include "access/tableam.h" |
20 | 19 | #include "access/toast_internals.h" |
21 | 20 | #include "common/pg_lzcompress.h" |
22 | 21 | #include "utils/expandeddatum.h" |
23 | | -#include "utils/fmgroids.h" |
24 | 22 | #include "utils/rel.h" |
25 | 23 |
|
26 | 24 | static struct varlena *toast_fetch_datum(struct varlena *attr); |
27 | 25 | static struct varlena *toast_fetch_datum_slice(struct varlena *attr, |
28 | 26 | int32 sliceoffset, |
29 | 27 | int32 slicelength); |
30 | | -static void heap_fetch_toast_slice(Relation toastrel, Oid valueid, |
31 | | - int32 attrsize, int32 sliceoffset, |
32 | | - int32 slicelength, struct varlena *result); |
33 | 28 | static struct varlena *toast_decompress_datum(struct varlena *attr); |
34 | 29 | static struct varlena *toast_decompress_datum_slice(struct varlena *attr, int32 slicelength); |
35 | 30 |
|
@@ -356,8 +351,8 @@ toast_fetch_datum(struct varlena *attr) |
356 | 351 | toastrel = table_open(toast_pointer.va_toastrelid, AccessShareLock); |
357 | 352 |
|
358 | 353 | /* Fetch all chunks */ |
359 | | - heap_fetch_toast_slice(toastrel, toast_pointer.va_valueid, attrsize, 0, |
360 | | - attrsize, result); |
| 354 | + table_relation_fetch_toast_slice(toastrel, toast_pointer.va_valueid, |
| 355 | + attrsize, 0, attrsize, result); |
361 | 356 |
|
362 | 357 | /* Close toast table */ |
363 | 358 | table_close(toastrel, AccessShareLock); |
@@ -431,198 +426,16 @@ toast_fetch_datum_slice(struct varlena *attr, int32 sliceoffset, |
431 | 426 | toastrel = table_open(toast_pointer.va_toastrelid, AccessShareLock); |
432 | 427 |
|
433 | 428 | /* Fetch all chunks */ |
434 | | - heap_fetch_toast_slice(toastrel, toast_pointer.va_valueid, attrsize, |
435 | | - sliceoffset, slicelength, result); |
| 429 | + table_relation_fetch_toast_slice(toastrel, toast_pointer.va_valueid, |
| 430 | + attrsize, sliceoffset, slicelength, |
| 431 | + result); |
436 | 432 |
|
437 | 433 | /* Close toast table */ |
438 | 434 | table_close(toastrel, AccessShareLock); |
439 | 435 |
|
440 | 436 | return result; |
441 | 437 | } |
442 | 438 |
|
443 | | -/* |
444 | | - * Fetch a TOAST slice from a heap table. |
445 | | - * |
446 | | - * toastrel is the relation from which chunks are to be fetched. |
447 | | - * valueid identifies the TOAST value from which chunks are being fetched. |
448 | | - * attrsize is the total size of the TOAST value. |
449 | | - * sliceoffset is the byte offset within the TOAST value from which to fetch. |
450 | | - * slicelength is the number of bytes to be fetched from the TOAST value. |
451 | | - * result is the varlena into which the results should be written. |
452 | | - */ |
453 | | -static void |
454 | | -heap_fetch_toast_slice(Relation toastrel, Oid valueid, int32 attrsize, |
455 | | - int32 sliceoffset, int32 slicelength, |
456 | | - struct varlena *result) |
457 | | -{ |
458 | | - Relation *toastidxs; |
459 | | - ScanKeyData toastkey[3]; |
460 | | - TupleDesc toasttupDesc = toastrel->rd_att; |
461 | | - int nscankeys; |
462 | | - SysScanDesc toastscan; |
463 | | - HeapTuple ttup; |
464 | | - int32 expectedchunk; |
465 | | - int32 totalchunks = ((attrsize - 1) / TOAST_MAX_CHUNK_SIZE) + 1; |
466 | | - int startchunk; |
467 | | - int endchunk; |
468 | | - int num_indexes; |
469 | | - int validIndex; |
470 | | - SnapshotData SnapshotToast; |
471 | | - |
472 | | - /* Look for the valid index of toast relation */ |
473 | | - validIndex = toast_open_indexes(toastrel, |
474 | | - AccessShareLock, |
475 | | - &toastidxs, |
476 | | - &num_indexes); |
477 | | - |
478 | | - startchunk = sliceoffset / TOAST_MAX_CHUNK_SIZE; |
479 | | - endchunk = (sliceoffset + slicelength - 1) / TOAST_MAX_CHUNK_SIZE; |
480 | | - Assert(endchunk <= totalchunks); |
481 | | - |
482 | | - /* |
483 | | - * Setup a scan key to fetch from the index. This is either two keys or |
484 | | - * three depending on the number of chunks. |
485 | | - */ |
486 | | - ScanKeyInit(&toastkey[0], |
487 | | - (AttrNumber) 1, |
488 | | - BTEqualStrategyNumber, F_OIDEQ, |
489 | | - ObjectIdGetDatum(valueid)); |
490 | | - |
491 | | - /* |
492 | | - * No additional condition if fetching all chunks. Otherwise, use an |
493 | | - * equality condition for one chunk, and a range condition otherwise. |
494 | | - */ |
495 | | - if (startchunk == 0 && endchunk == totalchunks - 1) |
496 | | - nscankeys = 1; |
497 | | - else if (startchunk == endchunk) |
498 | | - { |
499 | | - ScanKeyInit(&toastkey[1], |
500 | | - (AttrNumber) 2, |
501 | | - BTEqualStrategyNumber, F_INT4EQ, |
502 | | - Int32GetDatum(startchunk)); |
503 | | - nscankeys = 2; |
504 | | - } |
505 | | - else |
506 | | - { |
507 | | - ScanKeyInit(&toastkey[1], |
508 | | - (AttrNumber) 2, |
509 | | - BTGreaterEqualStrategyNumber, F_INT4GE, |
510 | | - Int32GetDatum(startchunk)); |
511 | | - ScanKeyInit(&toastkey[2], |
512 | | - (AttrNumber) 2, |
513 | | - BTLessEqualStrategyNumber, F_INT4LE, |
514 | | - Int32GetDatum(endchunk)); |
515 | | - nscankeys = 3; |
516 | | - } |
517 | | - |
518 | | - /* Prepare for scan */ |
519 | | - init_toast_snapshot(&SnapshotToast); |
520 | | - toastscan = systable_beginscan_ordered(toastrel, toastidxs[validIndex], |
521 | | - &SnapshotToast, nscankeys, toastkey); |
522 | | - |
523 | | - /* |
524 | | - * Read the chunks by index |
525 | | - * |
526 | | - * The index is on (valueid, chunkidx) so they will come in order |
527 | | - */ |
528 | | - expectedchunk = startchunk; |
529 | | - while ((ttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL) |
530 | | - { |
531 | | - int32 curchunk; |
532 | | - Pointer chunk; |
533 | | - bool isnull; |
534 | | - char *chunkdata; |
535 | | - int32 chunksize; |
536 | | - int32 expected_size; |
537 | | - int32 chcpystrt; |
538 | | - int32 chcpyend; |
539 | | - |
540 | | - /* |
541 | | - * Have a chunk, extract the sequence number and the data |
542 | | - */ |
543 | | - curchunk = DatumGetInt32(fastgetattr(ttup, 2, toasttupDesc, &isnull)); |
544 | | - Assert(!isnull); |
545 | | - chunk = DatumGetPointer(fastgetattr(ttup, 3, toasttupDesc, &isnull)); |
546 | | - Assert(!isnull); |
547 | | - if (!VARATT_IS_EXTENDED(chunk)) |
548 | | - { |
549 | | - chunksize = VARSIZE(chunk) - VARHDRSZ; |
550 | | - chunkdata = VARDATA(chunk); |
551 | | - } |
552 | | - else if (VARATT_IS_SHORT(chunk)) |
553 | | - { |
554 | | - /* could happen due to heap_form_tuple doing its thing */ |
555 | | - chunksize = VARSIZE_SHORT(chunk) - VARHDRSZ_SHORT; |
556 | | - chunkdata = VARDATA_SHORT(chunk); |
557 | | - } |
558 | | - else |
559 | | - { |
560 | | - /* should never happen */ |
561 | | - elog(ERROR, "found toasted toast chunk for toast value %u in %s", |
562 | | - valueid, RelationGetRelationName(toastrel)); |
563 | | - chunksize = 0; /* keep compiler quiet */ |
564 | | - chunkdata = NULL; |
565 | | - } |
566 | | - |
567 | | - /* |
568 | | - * Some checks on the data we've found |
569 | | - */ |
570 | | - if (curchunk != expectedchunk) |
571 | | - ereport(ERROR, |
572 | | - (errcode(ERRCODE_DATA_CORRUPTED), |
573 | | - errmsg_internal("unexpected chunk number %d (expected %d) for toast value %u in %s", |
574 | | - curchunk, expectedchunk, valueid, |
575 | | - RelationGetRelationName(toastrel)))); |
576 | | - if (curchunk > endchunk) |
577 | | - ereport(ERROR, |
578 | | - (errcode(ERRCODE_DATA_CORRUPTED), |
579 | | - errmsg_internal("unexpected chunk number %d (out of range %d..%d) for toast value %u in %s", |
580 | | - curchunk, |
581 | | - startchunk, endchunk, valueid, |
582 | | - RelationGetRelationName(toastrel)))); |
583 | | - expected_size = curchunk < totalchunks - 1 ? TOAST_MAX_CHUNK_SIZE |
584 | | - : attrsize - ((totalchunks - 1) * TOAST_MAX_CHUNK_SIZE); |
585 | | - if (chunksize != expected_size) |
586 | | - ereport(ERROR, |
587 | | - (errcode(ERRCODE_DATA_CORRUPTED), |
588 | | - errmsg_internal("unexpected chunk size %d (expected %d) in chunk %d of %d for toast value %u in %s", |
589 | | - chunksize, expected_size, |
590 | | - curchunk, totalchunks, valueid, |
591 | | - RelationGetRelationName(toastrel)))); |
592 | | - |
593 | | - /* |
594 | | - * Copy the data into proper place in our result |
595 | | - */ |
596 | | - chcpystrt = 0; |
597 | | - chcpyend = chunksize - 1; |
598 | | - if (curchunk == startchunk) |
599 | | - chcpystrt = sliceoffset % TOAST_MAX_CHUNK_SIZE; |
600 | | - if (curchunk == endchunk) |
601 | | - chcpyend = (sliceoffset + slicelength - 1) % TOAST_MAX_CHUNK_SIZE; |
602 | | - |
603 | | - memcpy(VARDATA(result) + |
604 | | - (curchunk * TOAST_MAX_CHUNK_SIZE - sliceoffset) + chcpystrt, |
605 | | - chunkdata + chcpystrt, |
606 | | - (chcpyend - chcpystrt) + 1); |
607 | | - |
608 | | - expectedchunk++; |
609 | | - } |
610 | | - |
611 | | - /* |
612 | | - * Final checks that we successfully fetched the datum |
613 | | - */ |
614 | | - if (expectedchunk != (endchunk + 1)) |
615 | | - ereport(ERROR, |
616 | | - (errcode(ERRCODE_DATA_CORRUPTED), |
617 | | - errmsg_internal("missing chunk number %d for toast value %u in %s", |
618 | | - expectedchunk, valueid, |
619 | | - RelationGetRelationName(toastrel)))); |
620 | | - |
621 | | - /* End scan and close indexes. */ |
622 | | - systable_endscan_ordered(toastscan); |
623 | | - toast_close_indexes(toastidxs, num_indexes, AccessShareLock); |
624 | | -} |
625 | | - |
626 | 439 | /* ---------- |
627 | 440 | * toast_decompress_datum - |
628 | 441 | * |
|
0 commit comments