Skip to content

Large Object Binaries ​

Package for LOB processing. Credit: https://github.com/paulzip-dev/Base64

example
sql
DECLARE
  v_text  CLOB := 'Hello, World!';
  v_blob  BLOB;
  v_b64   CLOB;
  v_blob2 BLOB;
  v_text2 CLOB;
BEGIN
  v_blob  := odbvue.pck_api_lob.clob_to_blob(v_text);
  v_b64   := odbvue.pck_api_lob.blob_to_base64(v_blob, 0);
  v_blob2 := odbvue.pck_api_lob.base64_to_blob(v_b64);
  v_text2 := odbvue.pck_api_lob.blob_to_clob(v_blob2);
  
  DBMS_OUTPUT.PUT_LINE('Original: ' || v_text);
  DBMS_OUTPUT.PUT_LINE('Base64:   ' || SUBSTR(v_b64, 1, 50));
  DBMS_OUTPUT.PUT_LINE('Final:    ' || v_text2);
END;
/
specification
sql
CREATE OR REPLACE PACKAGE odbvue.pck_api_lob AS -- Package for LOB processing. Credit: https://github.com/paulzip-dev/Base64

    SUBTYPE boolean IS PLS_INTEGER RANGE 0..1;
    FUNCTION clob_to_blob ( -- Function converts CLOB to BLOB
        p_clob             CLOB, -- CLOB
        p_charset_id       INTEGER DEFAULT dbms_lob.default_csid, -- Character set ID 
        p_error_on_warning BOOLEAN DEFAULT 0 -- Raise exception on warning (0 - No, 1 - Yes)
    ) RETURN BLOB; -- BLOB

    FUNCTION blob_to_clob ( --  Function converts BLOB to CLOB
        p_blob             BLOB, -- BLOB
        p_charset_id       INTEGER DEFAULT dbms_lob.default_csid, -- Character set ID 
        p_error_on_warning BOOLEAN DEFAULT 0 -- Raise exception on warning (0 - No, 1 - Yes)
    ) RETURN CLOB; -- CLOB

    FUNCTION blob_to_base64 ( -- Function encodes BLOB to BASE64
        p_blob    BLOB, -- BLOB
        p_newline BOOLEAN DEFAULT 1 -- Split in chunks (0 - No, 1 - Yes) 
    ) RETURN CLOB; -- CLOB

    FUNCTION clob_to_base64 ( -- Function encodes CLOB to BASE64
        p_clob    CLOB, -- CLOB
        p_newline BOOLEAN DEFAULT 1 -- Split in chunks (0 - No, 1 - Yes) 
    ) RETURN CLOB; -- CLOB

    FUNCTION varchar2_to_base64 ( -- Function encodes VARCHAR2 to BASE64
        p_varchar2 VARCHAR2, -- VARCHAR2
        p_newline  BOOLEAN DEFAULT 1 -- Split in chunks (0 - No, 1 - Yes) 
    ) RETURN CLOB; -- CLOB

    FUNCTION base64_to_blob ( -- Function decodes BASE64 to BLOB
        p_base64 CLOB -- BASE64
    ) RETURN BLOB; -- BLOB

    FUNCTION base64_to_clob ( -- Function decodes BASE64 to CLOB
        p_base64 CLOB -- BASE64
    ) RETURN CLOB; -- CLOB

    FUNCTION base64_to_varchar2 ( -- Function decodes BASE64 to VARCHAR2
        p_base64 CLOB -- BASE64
    ) RETURN VARCHAR2; -- VARCHAR2
END;
/


-- sqlcl_snapshot {"hash":"3b42fa73b6f5cc43fea20f64947a6bf98c0a5ec6","type":"PACKAGE_SPEC","name":"PCK_API_LOB","schemaName":"ODBVUE","sxml":""}
implementation
sql
CREATE OR REPLACE PACKAGE BODY odbvue.pck_api_lob AS

  -- PRIVATE

    c_crlf              CONSTANT VARCHAR2(2) := chr(13)
                                   || chr(10);
    c_whitespace        CONSTANT VARCHAR2(6) := ' '
                                         || chr(13)
                                         || chr(10)
                                         || chr(9)
                                         || chr(11)
                                         || chr(12);
    c_max_enc_chunk_len CONSTANT PLS_INTEGER := 23760;
    c_max_dec_chunk_len CONSTANT PLS_INTEGER := 31680;

    FUNCTION remove_whitespace (
        p_varchar2 VARCHAR2
    ) RETURN VARCHAR2 AS
    BEGIN
        RETURN translate(p_varchar2, 'a' || c_whitespace, 'a');
    END;

    FUNCTION decode_raw (
        p_varchar2          VARCHAR2,
        p_remove_whitespace BOOLEAN DEFAULT 1
    ) RETURN RAW AS
    BEGIN
        RETURN
            CASE
                WHEN p_varchar2 IS NOT NULL THEN
                    utl_encode.base64_decode(utl_raw.cast_to_raw(
                        CASE
                            WHEN p_remove_whitespace = 0 THEN
                                p_varchar2
                            ELSE
                                remove_whitespace(p_varchar2)
                        END
                    ))
            END;
    END;

  -- PUBLIC

    FUNCTION clob_to_blob (
        p_clob             CLOB,
        p_charset_id       INTEGER DEFAULT dbms_lob.default_csid,
        p_error_on_warning BOOLEAN DEFAULT 0
    ) RETURN BLOB AS

        v_result       BLOB;
        v_dest_offset  INTEGER := 1;
        v_src_offset   INTEGER := 1;
        v_lang_context INTEGER := dbms_lob.default_lang_ctx;
        v_warning      INTEGER;
    BEGIN
        dbms_lob.createtemporary(v_result, TRUE, dbms_lob.call);
        dbms_lob.converttoblob(
            dest_lob     => v_result,
            src_clob     => p_clob,
            amount       => dbms_lob.lobmaxsize,
            dest_offset  => v_dest_offset,
            src_offset   => v_src_offset,
            blob_csid    => p_charset_id,
            lang_context => v_lang_context,
            warning      => v_warning
        );

        IF
            v_warning <> dbms_lob.no_warning
            AND p_error_on_warning = 1
        THEN
            raise_application_error(-20001, 'Error during lob conversion : '
                                            ||
                CASE
                    WHEN v_warning = dbms_lob.warn_inconvertible_char THEN
                        'Inconvertible character'
                    ELSE
                        'Warning code ' || v_warning
                END
            );
        END IF;

        RETURN v_result;
    END;

    FUNCTION blob_to_clob (
        p_blob             BLOB,
        p_charset_id       INTEGER DEFAULT dbms_lob.default_csid,
        p_error_on_warning BOOLEAN DEFAULT 0
    ) RETURN CLOB AS

        v_result       CLOB;
        v_dest_offset  INTEGER := 1;
        v_src_offset   INTEGER := 1;
        v_lang_context INTEGER := dbms_lob.default_lang_ctx;
        v_warning      INTEGER;
    BEGIN
        dbms_lob.createtemporary(v_result, TRUE, dbms_lob.call);
        dbms_lob.converttoclob(
            dest_lob     => v_result,
            src_blob     => p_blob,
            amount       => dbms_lob.lobmaxsize,
            dest_offset  => v_dest_offset,
            src_offset   => v_src_offset,
            blob_csid    => p_charset_id,
            lang_context => v_lang_context,
            warning      => v_warning
        );

        IF
            v_warning <> dbms_lob.no_warning
            AND p_error_on_warning = 1
        THEN
            raise_application_error(-20001, 'Error during lob conversion : '
                                            ||
                CASE
                    WHEN v_warning = dbms_lob.warn_inconvertible_char THEN
                        'Inconvertible character'
                    ELSE
                        'Warning code ' || v_warning
                END
            );
        END IF;

        RETURN v_result;
    END;

    FUNCTION encode_raw (
        p_raw     RAW,
        p_newline BOOLEAN DEFAULT 1
    ) RETURN VARCHAR2 AS
    BEGIN
        RETURN
            CASE
                WHEN p_raw IS NULL THEN
                    NULL
                WHEN p_newline = 0 THEN
                    replace(
                        utl_raw.cast_to_varchar2(utl_encode.base64_encode(p_raw)),
                        c_crlf,
                        ''
                    )
                ELSE
                    rtrim(
                        utl_raw.cast_to_varchar2(utl_encode.base64_encode(p_raw)),
                        c_crlf
                    )
            END;
    END;

    FUNCTION blob_to_base64 (
        p_blob    BLOB,
        p_newline BOOLEAN DEFAULT 1
    ) RETURN CLOB AS

        v_length PLS_INTEGER := coalesce(
            dbms_lob.getlength(p_blob),
            0
        );
        v_offset PLS_INTEGER := 1;
        v_chunk  VARCHAR2(32767);
        v_crlf   VARCHAR2(2) :=
            CASE
                WHEN p_newline = 0 THEN
                    NULL
                ELSE
                    c_crlf
            END;
        v_result CLOB;
    BEGIN
        CASE
            WHEN v_length = 0 THEN
                v_result :=
                    CASE
                        WHEN p_blob IS NULL THEN
                            NULL
                        ELSE
                            empty_clob()
                    END;
            WHEN v_length <= c_max_enc_chunk_len THEN
                v_result := encode_raw(p_blob, p_newline);
            ELSE
                dbms_lob.createtemporary(v_result, TRUE, dbms_lob.call);
                FOR i IN 1..ceil(v_length / c_max_enc_chunk_len) LOOP
                    v_chunk :=
                        CASE
                            WHEN i > 1 THEN
                                v_crlf
                        END
                        || encode_raw(
                        dbms_lob.substr(p_blob, c_max_enc_chunk_len, v_offset),
                        p_newline
                    );

                    dbms_lob.writeappend(v_result,
                                         length(v_chunk),
                                         v_chunk);
                    v_offset := v_offset + c_max_enc_chunk_len;
                END LOOP;

        END CASE;

        RETURN v_result;
    END;

    FUNCTION clob_to_base64 (
        p_clob    CLOB,
        p_newline BOOLEAN DEFAULT 1
    ) RETURN CLOB AS
    BEGIN
        RETURN
            CASE
                WHEN p_clob IS NULL
                     OR p_clob = empty_clob() THEN
                    p_clob
                ELSE
                    blob_to_base64(
                        clob_to_blob(p_clob),
                        p_newline
                    )
            END;
    END;

    FUNCTION varchar2_to_base64 (
        p_varchar2 VARCHAR2,
        p_newline  BOOLEAN DEFAULT 1
    ) RETURN CLOB AS
    BEGIN
        RETURN encode_raw(
            utl_raw.cast_to_raw(p_varchar2),
            p_newline
        );
    END;

    FUNCTION base64_to_blob (
        p_base64 CLOB
    ) RETURN BLOB AS

        v_offset        INTEGER := 1;
        v_length        PLS_INTEGER := coalesce(
            dbms_lob.getlength(p_base64),
            0
        );
        v_buffer        VARCHAR2(32767);
        v_modulo        PLS_INTEGER;
        v_overflow      VARCHAR2(4);
        v_buffer_length PLS_INTEGER;
        v_amount        INTEGER := c_max_dec_chunk_len;
        v_result        BLOB;

        PROCEDURE append_chunk (
            p_chunk VARCHAR2
        ) AS
            v_buffer_raw RAW(32767);
        BEGIN
            v_buffer_raw := decode_raw(p_chunk,
                                       p_remove_whitespace => 0);
            dbms_lob.writeappend(v_result,
                                 utl_raw.length(v_buffer_raw),
                                 v_buffer_raw);
        END;

    BEGIN
        CASE
            WHEN v_length = 0 THEN
                v_result :=
                    CASE
                        WHEN p_base64 IS NULL THEN
                            NULL
                        ELSE
                            empty_blob()
                    END;
            WHEN v_length <= c_max_dec_chunk_len THEN
                v_result := decode_raw(p_base64);
            WHEN v_length > c_max_dec_chunk_len THEN
                dbms_lob.createtemporary(v_result, FALSE, dbms_lob.call);
                WHILE v_offset <= v_length LOOP
                    dbms_lob.read(p_base64, v_amount, v_offset, v_buffer);
                    v_buffer := remove_whitespace(v_buffer);
                    v_buffer_length := length(v_buffer);
                    v_modulo := MOD(v_buffer_length, 4);
                    IF v_modulo > 0 THEN
                        append_chunk(v_overflow || substr(v_buffer, 1, v_buffer_length - v_modulo));
                        v_overflow := substr(v_buffer, -v_modulo);
                    ELSE
                        append_chunk(v_buffer);
                        v_overflow := NULL;
                    END IF;

                    v_offset := v_offset + v_amount;
                END LOOP;

                IF v_overflow IS NOT NULL THEN
                    append_chunk(v_overflow);
                END IF;
        END CASE;

        RETURN v_result;
    END;

    FUNCTION base64_to_clob (
        p_base64 CLOB
    ) RETURN CLOB AS
        v_length PLS_INTEGER := coalesce(
            dbms_lob.getlength(p_base64),
            0
        );
    BEGIN
        RETURN
            CASE
                WHEN v_length = 0                    THEN
                    p_base64
                WHEN v_length <= c_max_dec_chunk_len THEN
                    base64_to_varchar2(p_base64)
                WHEN v_length > c_max_dec_chunk_len  THEN
                    blob_to_clob(base64_to_blob(p_base64))
            END;
    END;

    FUNCTION base64_to_varchar2 (
        p_base64 CLOB
    ) RETURN VARCHAR2 AS
    BEGIN
        RETURN utl_raw.cast_to_varchar2(decode_raw(p_base64));
    END;

END;
/


-- sqlcl_snapshot {"hash":"9ac7586c3c6f6abae1e5848e3d3c8ff0232afb6d","type":"PACKAGE_BODY","name":"PCK_API_LOB","schemaName":"ODBVUE","sxml":""}

BASE64_TO_BLOB ​

Function decodes BASE64 to BLOB

Argument nameIn OutData typeDefault valueDescription
OUTBLOBBLOB
P_BASE64INCLOBBASE64

BASE64_TO_CLOB ​

Function decodes BASE64 to CLOB

Argument nameIn OutData typeDefault valueDescription
OUTCLOBCLOB
P_BASE64INCLOBBASE64

BASE64_TO_VARCHAR2 ​

Function decodes BASE64 to VARCHAR2

Argument nameIn OutData typeDefault valueDescription
OUTVARCHAR2VARCHAR2
P_BASE64INCLOBBASE64

BLOB_TO_BASE64 ​

Function encodes BLOB to BASE64

Argument nameIn OutData typeDefault valueDescription
OUTCLOBCLOB
P_BLOBINBLOBBLOB
P_NEWLINEINBINARY_INTEGER1Split in chunks (0 - No, 1 - Yes)

BLOB_TO_CLOB ​

Function converts BLOB to CLOB

Argument nameIn OutData typeDefault valueDescription
OUTCLOBCLOB
P_BLOBINBLOBBLOB
P_CHARSET_IDINNUMBERdbms_lob.default_csidCharacter set ID
P_ERROR_ON_WARNINGINBINARY_INTEGER0Raise exception on warning (0 - No, 1 - Yes)

CLOB_TO_BASE64 ​

Function encodes CLOB to BASE64

Argument nameIn OutData typeDefault valueDescription
OUTCLOBCLOB
P_CLOBINCLOBCLOB
P_NEWLINEINBINARY_INTEGER1Split in chunks (0 - No, 1 - Yes)

CLOB_TO_BLOB ​

Function converts CLOB to BLOB

Argument nameIn OutData typeDefault valueDescription
OUTBLOBBLOB
P_CLOBINCLOBCLOB
P_CHARSET_IDINNUMBERdbms_lob.default_csidCharacter set ID
P_ERROR_ON_WARNINGINBINARY_INTEGER0Raise exception on warning (0 - No, 1 - Yes)

VARCHAR2_TO_BASE64 ​

Function encodes VARCHAR2 to BASE64

Argument nameIn OutData typeDefault valueDescription
OUTCLOBCLOB
P_VARCHAR2INVARCHAR2VARCHAR2
P_NEWLINEINBINARY_INTEGER1Split in chunks (0 - No, 1 - Yes)