@@ -754,3 +754,154 @@ deleteLOfd(int fd)
754754{
755755 cookies [fd ] = NULL ;
756756}
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