sql >> Databasteknik >  >> RDS >> Oracle

Kan jag lagra binär sträng i CLOB-kolumnen

I allmänhet kan du inte göra det. Speciellt om din databas använder UTF-8 (standard nuförtiden) har du många bitvärden som inte matchar ett giltigt tecken och de skulle ersättas med en platshållare (vanligtvis ¿ ) medan du sätter in och väljer.

Vad du kan göra är att koda din binära data som Base64-sträng. Detta är ett mycket vanligt sätt att överföra binär data vid gränssnitt som endast stöder text (t.ex. XML-filer eller SMTP-e-postmeddelanden)

Använd den här funktionen för att koda dina binära data som text:

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;

Och denna funktion för att konvertera tillbaka till 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;

Du hittar många online Base64-avkodare/kodare på internet där du kan verifiera din procedur.




  1. Blir de snabbare om du lägger till 'LIMIT 1' i MySQL-frågor när du vet att det bara kommer att bli ett resultat?

  2. Fundamentals of table expressions, Del 4 – Härledda tabeller, optimeringsöverväganden, fortsättning

  3. SQL INTERSECT

  4. SQL ALTER TABELL för nybörjare