|
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 | staticstructvarlena*toast_fetch_datum(structvarlena*attr); |
27 | 25 | staticstructvarlena*toast_fetch_datum_slice(structvarlena*attr, |
28 | 26 | int32sliceoffset, |
29 | 27 | int32slicelength); |
30 | | -staticvoidheap_fetch_toast_slice(Relationtoastrel,Oidvalueid, |
31 | | -int32attrsize,int32sliceoffset, |
32 | | -int32slicelength,structvarlena*result); |
33 | 28 | staticstructvarlena*toast_decompress_datum(structvarlena*attr); |
34 | 29 | staticstructvarlena*toast_decompress_datum_slice(structvarlena*attr,int32slicelength); |
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 | returnresult; |
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 | | -staticvoid |
454 | | -heap_fetch_toast_slice(Relationtoastrel,Oidvalueid,int32attrsize, |
455 | | -int32sliceoffset,int32slicelength, |
456 | | -structvarlena*result) |
457 | | -{ |
458 | | -Relation*toastidxs; |
459 | | -ScanKeyDatatoastkey[3]; |
460 | | -TupleDesctoasttupDesc=toastrel->rd_att; |
461 | | -intnscankeys; |
462 | | -SysScanDesctoastscan; |
463 | | -HeapTuplettup; |
464 | | -int32expectedchunk; |
465 | | -int32totalchunks= ((attrsize-1) /TOAST_MAX_CHUNK_SIZE)+1; |
466 | | -intstartchunk; |
467 | | -intendchunk; |
468 | | -intnum_indexes; |
469 | | -intvalidIndex; |
470 | | -SnapshotDataSnapshotToast; |
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 | | -elseif (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 | | -int32curchunk; |
532 | | -Pointerchunk; |
533 | | -boolisnull; |
534 | | -char*chunkdata; |
535 | | -int32chunksize; |
536 | | -int32expected_size; |
537 | | -int32chcpystrt; |
538 | | -int32chcpyend; |
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 | | -elseif (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 | * |
|