@@ -754,3 +754,154 @@ deleteLOfd(int fd)
754
754
{
755
755
cookies [fd ] = NULL ;
756
756
}
757
+
758
+ /*****************************************************************************
759
+ * Wrappers oriented toward SQL callers
760
+ *****************************************************************************/
761
+
762
+ /*
763
+ * Read [offset, offset+nbytes) within LO; when nbytes is -1, read to end.
764
+ */
765
+ static bytea *
766
+ lo_get_fragment_internal (Oid loOid , int64 offset , int32 nbytes )
767
+ {
768
+ LargeObjectDesc * loDesc ;
769
+ int64 loSize ;
770
+ int64 result_length ;
771
+ int total_read PG_USED_FOR_ASSERTS_ONLY ;
772
+ bytea * result = NULL ;
773
+
774
+ /*
775
+ * We don't actually need to store into fscxt, but create it anyway to
776
+ * ensure that AtEOXact_LargeObject knows there is state to clean up
777
+ */
778
+ CreateFSContext ();
779
+
780
+ loDesc = inv_open (loOid , INV_READ , fscxt );
781
+
782
+ /* Permission check */
783
+ if (!lo_compat_privileges &&
784
+ pg_largeobject_aclcheck_snapshot (loDesc -> id ,
785
+ GetUserId (),
786
+ ACL_SELECT ,
787
+ loDesc -> snapshot ) != ACLCHECK_OK )
788
+ ereport (ERROR ,
789
+ (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
790
+ errmsg ("permission denied for large object %u" ,
791
+ loDesc -> id )));
792
+
793
+ /*
794
+ * Compute number of bytes we'll actually read, accommodating nbytes == -1
795
+ * and reads beyond the end of the LO.
796
+ */
797
+ loSize = inv_seek (loDesc , 0 , SEEK_END );
798
+ if (loSize > offset )
799
+ {
800
+ if (nbytes >= 0 && nbytes <= loSize - offset )
801
+ result_length = nbytes ; /* request is wholly inside LO */
802
+ else
803
+ result_length = loSize - offset ; /* adjust to end of LO */
804
+ }
805
+ else
806
+ result_length = 0 ; /* request is wholly outside LO */
807
+
808
+ /*
809
+ * A result_length calculated from loSize may not fit in a size_t. Check
810
+ * that the size will satisfy this and subsequently-enforced size limits.
811
+ */
812
+ if (result_length > MaxAllocSize - VARHDRSZ )
813
+ ereport (ERROR ,
814
+ (errcode (ERRCODE_PROGRAM_LIMIT_EXCEEDED ),
815
+ errmsg ("large object read request is too large" )));
816
+
817
+ result = (bytea * ) palloc (VARHDRSZ + result_length );
818
+
819
+ inv_seek (loDesc , offset , SEEK_SET );
820
+ total_read = inv_read (loDesc , VARDATA (result ), result_length );
821
+ Assert (total_read == result_length );
822
+ SET_VARSIZE (result , result_length + VARHDRSZ );
823
+
824
+ inv_close (loDesc );
825
+
826
+ return result ;
827
+ }
828
+
829
+ /*
830
+ * Read entire LO
831
+ */
832
+ Datum
833
+ lo_get (PG_FUNCTION_ARGS )
834
+ {
835
+ Oid loOid = PG_GETARG_OID (0 );
836
+ bytea * result ;
837
+
838
+ result = lo_get_fragment_internal (loOid , 0 , -1 );
839
+
840
+ PG_RETURN_BYTEA_P (result );
841
+ }
842
+
843
+ /*
844
+ * Read range within LO
845
+ */
846
+ Datum
847
+ lo_get_fragment (PG_FUNCTION_ARGS )
848
+ {
849
+ Oid loOid = PG_GETARG_OID (0 );
850
+ int64 offset = PG_GETARG_INT64 (1 );
851
+ int32 nbytes = PG_GETARG_INT32 (2 );
852
+ bytea * result ;
853
+
854
+ if (nbytes < 0 )
855
+ ereport (ERROR ,
856
+ (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
857
+ errmsg ("requested length cannot be negative" )));
858
+
859
+ result = lo_get_fragment_internal (loOid , offset , nbytes );
860
+
861
+ PG_RETURN_BYTEA_P (result );
862
+ }
863
+
864
+ /*
865
+ * Create LO with initial contents
866
+ */
867
+ Datum
868
+ lo_create_bytea (PG_FUNCTION_ARGS )
869
+ {
870
+ Oid loOid = PG_GETARG_OID (0 );
871
+ bytea * str = PG_GETARG_BYTEA_PP (1 );
872
+ LargeObjectDesc * loDesc ;
873
+ int written PG_USED_FOR_ASSERTS_ONLY ;
874
+
875
+ CreateFSContext ();
876
+
877
+ loOid = inv_create (loOid );
878
+ loDesc = inv_open (loOid , INV_WRITE , fscxt );
879
+ written = inv_write (loDesc , VARDATA_ANY (str ), VARSIZE_ANY_EXHDR (str ));
880
+ Assert (written == VARSIZE_ANY_EXHDR (str ));
881
+ inv_close (loDesc );
882
+
883
+ PG_RETURN_OID (loOid );
884
+ }
885
+
886
+ /*
887
+ * Update range within LO
888
+ */
889
+ Datum
890
+ lo_put (PG_FUNCTION_ARGS )
891
+ {
892
+ Oid loOid = PG_GETARG_OID (0 );
893
+ int64 offset = PG_GETARG_INT64 (1 );
894
+ bytea * str = PG_GETARG_BYTEA_PP (2 );
895
+ LargeObjectDesc * loDesc ;
896
+ int written PG_USED_FOR_ASSERTS_ONLY ;
897
+
898
+ CreateFSContext ();
899
+
900
+ loDesc = inv_open (loOid , INV_WRITE , fscxt );
901
+ inv_seek (loDesc , offset , SEEK_SET );
902
+ written = inv_write (loDesc , VARDATA_ANY (str ), VARSIZE_ANY_EXHDR (str ));
903
+ Assert (written == VARSIZE_ANY_EXHDR (str ));
904
+ inv_close (loDesc );
905
+
906
+ PG_RETURN_VOID ();
907
+ }
0 commit comments