Oracle
 sql >> Base de données >  >> RDS >> Oracle

Puis-je stocker une chaîne binaire dans la colonne CLOB

En général, vous ne pouvez pas faire cela. Surtout si votre base de données utilise UTF-8 (la valeur par défaut de nos jours), vous avez de nombreuses valeurs de bits qui ne correspondent pas à un caractère valide et elles seraient remplacées par un espace réservé (généralement ¿ ) tout en insérant et en sélectionnant.

Ce que vous pouvez faire est d'encoder vos données binaires sous forme de chaîne Base64. Il s'agit d'un moyen très courant de transférer des données binaires sur des interfaces qui ne prennent en charge que le texte (par exemple, des fichiers XML ou des e-mails SMTP)

Utilisez cette fonction pour encoder vos données binaires sous forme de texte :

FUNCTION EncodeBASE64(InBlob IN BLOB) RETURN CLOB IS

    BlobLen INTEGER := DBMS_LOB.GETLENGTH(InBlob);
    read_offset INTEGER := 1;
    warning INTEGER;

    amount INTEGER := 1440; -- must be a whole multiple of 3
    -- size of a whole multiple of 48 is beneficial to get NEW_LINE after each 64 characters 
    buffer RAW(1440);
    res CLOB := EMPTY_CLOB();

BEGIN

    IF InBlob IS NULL OR NVL(BlobLen, 0) = 0 THEN 
        RETURN NULL;
    ELSIF BlobLen <= 24000 THEN
        RETURN UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(InBlob));
    ELSE
        -- UTL_ENCODE.BASE64_ENCODE is limited to 32k, process in chunks if bigger
        LOOP
            EXIT WHEN read_offset >= BlobLen;
            DBMS_LOB.READ(InBlob, amount, read_offset, buffer);
            res := res || UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(buffer));       
            read_offset := read_offset + amount;
        END LOOP;
    END IF;
    RETURN res;

END EncodeBASE64;

Et cette fonction pour reconvertir en BLOB

FUNCTION DecodeBASE64(InBase64Char IN CLOB) RETURN BLOB IS

    res BLOB;
    clob_trim CLOB;

    dest_offset INTEGER := 1;
    src_offset INTEGER := 1;
    read_offset INTEGER := 1;
    ClobLen INTEGER := DBMS_LOB.GETLENGTH(InBase64Char);

    amount INTEGER := 1440; -- must be a whole multiple of 4
    buffer RAW(1440);
    stringBuffer VARCHAR2(1440);
    -- BASE64 characters are always simple ASCII. Thus you get never any Mulit-Byte character and having the same size as 'amount' is sufficient

BEGIN

    IF InBase64Char IS NULL OR NVL(ClobLen, 0) = 0 THEN 
        RETURN NULL;
    ELSIF ClobLen <= 32000 THEN
        RETURN TO_BLOB(UTL_ENCODE.BASE64_DECODE(UTL_RAW.CAST_TO_RAW(InBase64Char)));
    ELSE
        -- Remove all NEW_LINE from base64 string
        DBMS_LOB.CREATETEMPORARY(clob_trim, TRUE);
        LOOP
            EXIT WHEN read_offset > ClobLen;
            stringBuffer := REPLACE(REPLACE(DBMS_LOB.SUBSTR(InBase64Char, amount, read_offset), CHR(13), NULL), CHR(10), NULL);
            DBMS_LOB.WRITEAPPEND(clob_trim, LENGTH(stringBuffer), stringBuffer);
            read_offset := read_offset + amount;
        END LOOP;

        read_offset := 1;
        ClobLen := DBMS_LOB.GETLENGTH(clob_trim);
        DBMS_LOB.CREATETEMPORARY(res, TRUE);
        LOOP
            EXIT WHEN read_offset > ClobLen;
            buffer := UTL_ENCODE.BASE64_DECODE(UTL_RAW.CAST_TO_RAW(DBMS_LOB.SUBSTR(clob_trim, amount, read_offset)));
            DBMS_LOB.WRITEAPPEND(res, DBMS_LOB.GETLENGTH(buffer), buffer);
            read_offset := read_offset + amount;
        END LOOP;
        DBMS_LOB.FREETEMPORARY(clob_trim);
    END IF;

    RETURN res;    

END DecodeBASE64;

Vous trouvez de nombreux décodeurs/encodeurs Base64 en ligne sur Internet où vous pouvez vérifier votre procédure.