RosettaCodeData/Task/Rot-13/PL-SQL/rot-13.sql

45 lines
1.6 KiB
SQL

-- Works for VARCHAR2 (up to 32k chars)
CREATE OR REPLACE FUNCTION fn_rot13_native(p_text VARCHAR2) RETURN VARCHAR2 IS
c_source CONSTANT VARCHAR2(52) := 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
c_target CONSTANT VARCHAR2(52) := 'NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm';
BEGIN
RETURN TRANSLATE(p_text, c_source, c_target);
END;
/
-- For CLOBs (translate only works with VARCHAR2, so do it in chunks)
CREATE OR REPLACE FUNCTION fn_rot13_clob(p_text CLOB) RETURN CLOB IS
c_source CONSTANT VARCHAR2(52) := 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
c_target CONSTANT VARCHAR2(52) := 'NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm';
c_chunk_size CONSTANT PLS_INTEGER := 4000;
v_result CLOB := NULL;
BEGIN
FOR i IN 0..TRUNC(LENGTH(p_text) / c_chunk_size) LOOP
v_result := v_result ||
TRANSLATE(dbms_lob.substr(p_text, c_chunk_size, i * c_chunk_size + 1), c_source, c_target);
END LOOP;
RETURN v_result;
END;
/
-- The full algorithm (Slower. And MUCH slower if using CLOB!)
CREATE OR REPLACE FUNCTION fn_rot13_algorithm(p_text VARCHAR2) RETURN CLOB IS
c_upper_a CONSTANT PLS_INTEGER := ASCII('A');
c_lower_a CONSTANT PLS_INTEGER := ASCII('a');
v_rot VARCHAR2(32000);
v_char VARCHAR2(1);
BEGIN
FOR i IN 1..LENGTH(p_text) LOOP
v_char := SUBSTR(p_text, i, 1);
IF v_char BETWEEN 'A' AND 'Z' THEN
v_rot := v_rot || CHR(MOD(ASCII(v_char) - c_upper_a + 13, 26) + c_upper_a);
ELSIF v_char BETWEEN 'a' AND 'z' THEN
v_rot := v_rot || CHR(MOD(ASCII(v_char) - c_lower_a + 13, 26) + c_lower_a);
ELSE
v_rot := v_rot || v_char;
END IF;
END LOOP;
RETURN v_rot;
END;
/