API Reference
Audit
Audit Package
example
BEGIN
pck_api_audit.info(
p_message => 'App Audit Package Deployed',
p_attributes => pck_api_audit.attributes( -- key value pairs
'uuid', LOWER(SYS_GUID()),
'username', 'test'
)
);
END;
/
DECLARE
c_data CLOB := '[
{
"severity": "INFO",
"message": "Bulk Log Entry 1",
"attributes": {
"uuid": "433c66c3ccfe9b02e0630301590ac258",
"username": "test1"
},
"created": "2023-10-01T12:00:00Z"
},
{
"severity": "ERROR",
"message": "Bulk Log Entry 2",
"attributes": {
"uuid": "fffc66c3ccfe9b02e0630301590ac258",
"username": "test2"
},
"created": "2023-10-01T12:00:00Z"
}
]';
BEGIN
pck_api_audit.bulk(c_data);
END;
/
SELECT * FROM app_audit
ORDER BY created DESC
FETCH FIRST 10 ROWS ONLY;
/Authentication
Package provides methods for issuing and validating tokens
example
set serveroutput on;
/
DECLARE
v_uuid CHAR(32 CHAR);
v_token VARCHAR2(2000 char);
BEGIN
SELECT uuid INTO v_uuid FROM app_users WHERE username = UPPER('admin@odbvue.com');
v_token := pck_api_auth.issue_token(v_uuid,'ACCESS');
dbms_output.put_line('Issued Token: ');
dbms_output.put_line(v_token);
v_uuid := pck_api_auth.uuid_from_token(v_token);
dbms_output.put_line('UUID from Token: ');
dbms_output.put_line(v_uuid);
END;
/Classifiers
Package provides classifier lookup
example
SET SERVEROUTPUT ON;
DECLARE
c CLOB;
BEGIN
DBMS_OUTPUT.PUT_LINE('Countries:');
c:=pck_api_classifiers.lookup(
'countries',
'be',
'Y',
10,
0
);
DBMS_OUTPUT.PUT_LINE(c);
DBMS_OUTPUT.PUT_LINE('');
DBMS_OUTPUT.PUT_LINE('Currencies:');
c:=pck_api_classifiers.lookup(
'currencies',
'dollar',
'Y',
10,
0
);
DBMS_OUTPUT.PUT_LINE(c);
DBMS_OUTPUT.PUT_LINE('');
DBMS_OUTPUT.PUT_LINE('Languages:');
c:=pck_api_classifiers.lookup(
'languages',
'po',
'Y',
10,
0
);
DBMS_OUTPUT.PUT_LINE(c);
DBMS_OUTPUT.PUT_LINE('');
END;
/Consents
Package for managing user consents
example
SET SERVEROUTPUT ON;
DECLARE
c CLOB;
id app_consents.id%TYPE;
BEGIN
c := pck_api_consents.lookup();
DBMS_OUTPUT.PUT_LINE('Consents: ' || SUBSTR(c,1,200) || '...');
id := JSON_VALUE(c, '$[0].id');
DBMS_OUTPUT.PUT_LINE('First Consent ID: ' || id);
c:= pck_api_consents.download(id);
DBMS_OUTPUT.PUT_LINE('Consent Content: ' || SUBSTR(c,1,200) || '...');
END;
/Emails
Package for sending emails
example
DECLARE
v_id app_emails.id%TYPE;
BEGIN
IF pck_api_settings.read('APP_EMAILS_SMTP_USERNAME') IS NULL OR pck_api_settings.read('APP_EMAILS_SMTP_PASSWORD') IS NULL THEN
RAISE_APPLICATION_ERROR(-20001, 'SMTP Credentials not set up!');
END IF;
pck_api_emails.mail(v_id, 'admin@odbvue.com', 'Admin User', 'Test email 123', 'This is a <b>test</b> email!');
pck_api_emails.send(v_id);
END;
/Labels
Package provides methods for managing labels
example
BEGIN
-- Numeric
pck_api_labels.link_label_nm('Important', 'document', 123);
pck_api_labels.link_label_nm('Important', 'document', 234);
pck_api_labels.link_label_nm('Important', 'document', 345);
pck_api_labels.link_label_nm('Nice to have', 'document', 456);
pck_api_labels.link_label_nm('Nice to have', 'document', 567);
pck_api_labels.unlink_label_nm('Important', 'document', 234);
pck_api_labels.unlink_label_nm('Important', 'document', 678); -- non-existing link
-- Variable Character
pck_api_labels.link_label_vc('Important', 'folder', 'abc123');
pck_api_labels.link_label_vc('Important', 'folder', 'def456');
pck_api_labels.link_label_vc('Important', 'folder', 'ghi789');
pck_api_labels.link_label_vc('Nice to have', 'folder', 'jkl012');
pck_api_labels.link_label_vc('Nice to have', 'folder', 'mno345');
pck_api_labels.unlink_label_vc('Important', 'folder', 'def456');
pck_api_labels.unlink_label_vc('Important', 'folder', 'xyz999'); -- non-existing link
-- done
COMMIT;
END;
/
SELECT
ll.entity_name,
COALESCE(ll.entity_id_vc, TO_CHAR(ll.entity_id_nm)) AS entity_id,
l.name AS label_name
FROM app_label_links ll
JOIN app_labels l ON ll.label_id = l.id
ORDER BY ll.entity_name, l.code;LOB
Package for LOB processing. Credit: https://github.com/paulzip-dev/Base64
example
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;
/HTTP
Package for HTTP call processing
example
DECLARE
v_req utl_http.req;
v_text CLOB;
BEGIN
BEGIN
pck_api_http.request(v_req, 'GET', 'https://api.chucknorris.io/jokes/random');
pck_api_http.response_text(v_req, v_text);
DBMS_OUTPUT.PUT_LINE(JSON_VALUE(v_text, '$.value'));
EXCEPTION
WHEN OTHERS THEN
DECLARE
v_error_stack VARCHAR2(4000) := DBMS_UTILITY.FORMAT_ERROR_STACK();
BEGIN
IF v_error_stack LIKE '%ORA-24247%' THEN
DBMS_OUTPUT.PUT_LINE('ERROR (ORA-24247): Network access denied by Access Control List (ACL).');
DBMS_OUTPUT.PUT_LINE('ACL must be enabled first using pck_api_admin.acl_append_host.');
DBMS_OUTPUT.PUT_LINE('exec admin.pck_api_admin.acl_append_host(''ODBVUE'', ''api.chucknorris.io'', 443, 443, ''http'');');
ELSE
RAISE;
END IF;
END;
END;
END;
/Jobs
Package for managing jobs
example
BEGIN
pck_api_jobs.add('test','pck_api_audit.info', '[{"type":"VARCHAR2", "name": "p_message", "value":"Test job"}]', 'FREQ=WEEKLY; BYDAY=MON; BYHOUR=0; BYMINUTE=0; BYSECOND=0', 'Weekly Test Job');
pck_api_jobs.run('test');
pck_api_jobs.remove('test');
END;
/
SELECT *
FROM user_scheduler_job_run_details
WHERE job_name = 'TEST_JOB'
ORDER BY log_date DESC
FETCH FIRST 10 ROWS ONLY;JSON
Package for handling json
example
DECLARE
c clob;
r clob;
v clob;
p VARCHAR2(2000 CHAR);
b boolean;
n PLS_INTEGER;
PROCEDURE print(c clob DEFAULT NULL)
AS
BEGIN
dbms_output.put_line(dbms_lob.substr(c, 4000));
END;
FUNCTION tf(b IN boolean) RETURN VARCHAR2
AS
BEGIN
RETURN CASE WHEN b THEN 'true' ELSE 'false' END;
END;
BEGIN
print('Init');
c:= pck_api_json.init;
print(c);
print;
print('Exists');
c:='{"a":1,"b":{"c":2},"d":[1,2,3]}';
p := '$.a';
b := pck_api_json.exists(c, p);
print(p || ' in ' || c || ' => ' || tf(b)); -- true
p := '$.b.c';
b := pck_api_json.exists(c, p);
print(p || ' in ' || c || ' => ' || tf(b)); -- true
p := '$.b.d';
b := pck_api_json.exists(c, p);
print(p || ' in ' || c || ' => ' || tf(b)); -- false
p := '$.x';
b := pck_api_json.exists(c, p);
print(p || ' in ' || c || ' => ' || tf(b)); -- false
p := '$.d[1]';
b := pck_api_json.exists(c, p);
print(p || ' in ' || c || ' => ' || tf(b)); -- true
p := '$.d[10]';
b := pck_api_json.exists(c, p);
print(p || ' in ' || c || ' => ' || tf(b)); -- false
print;
print('Read');
c:='{"a":1,"b":{"c":2},"d":[1,2,3]}';
p := '$.a';
r := pck_api_json.read(c, p);
print(p || ' from ' || c || ' => ' || r); -- 1
p := '$.b';
r := pck_api_json.read(c, p);
print(p || ' from ' || c || ' => ' || r); -- {"c":2}
p := '$.d[2]';
r := pck_api_json.read(c, p);
print(p || ' from ' || c || ' => ' || r); -- 3 (index starts with 0)
p := '$.d[10]';
r := pck_api_json.read(c, p);
print(p || ' from ' || c || ' => ' || r); -- NULL
print;
print('Typeof');
c:='{"a":1,"b":{"c":2},"d":[1,2,3]}';
p := '$.a';
r := pck_api_json.typeof(c, p);
print(p || ' type in ' || c || ' => ' || r); -- number
p := '$.b';
r := pck_api_json.typeof(c, p);
print(p || ' type in ' || c || ' => ' || r); -- object
p := '$.d';
r := pck_api_json.typeof(c, p);
print(p || ' type in ' || c || ' => ' || r); -- array
p := '$.x';
r := pck_api_json.typeof(c, p);
print(p || ' type in ' || c || ' => ' || r); -- undefined
print;
print('Elcount');
c:='{"a":1,"b":{"c":2},"d":[1,2,3],"e":{"f":4,"g":5}}';
p := '$.a';
n := pck_api_json.elcount(c, p);
print(p || ' element count in ' || c || ' => ' || n); -- 1
p := '$.d';
n := pck_api_json.elcount(c, p);
print(p || ' element count in ' || c || ' => ' || n); -- 3
p := '$.e';
n := pck_api_json.elcount(c, p);
print(p || ' element count in ' || c || ' => ' || n); -- 2
print;
print('Keys');
c:='{"a":1,"b":{"c":2},"d":[1,2,3]}';
p := '$';
r := pck_api_json.keys(c, p);
print(p || ' keys in ' || c || ' => ' || r); -- 1
p := '$.b';
r := pck_api_json.keys(c, p);
print(p || ' keys in ' || c || ' => ' || r); -- 1
p := '$.d';
r := pck_api_json.keys(c, p);
print(p || ' keys in ' || c || ' => ' || r); -- []
print;
print ('Write');
--
c:='{"a":1,"b":{"c":2},"d":[1,2,3]}';
r:=c;
p := '$.a';
v:='42';
pck_api_json.write(r, p, v);
print(v || ' at ' || p || ' in ' || c || ' => ' || r);
--
c:='{"a":1,"b":{"c":2},"d":[1,2,3]}';
r:=c;
p := '$.b.c';
v:='{"e":"f"}';
pck_api_json.write(r, p, v);
print(v || ' at ' || p || ' in ' || c || ' => ' || r);
--
c:='{"a":1,"b":{"c":2},"d":[1,2,3]}';
r:=c;
p := '$.d';
v:=null;
pck_api_json.write(r, p, v);
print(COALESCE(v, 'null') || ' at ' || p || ' in ' || c || ' => ' || r);
--c:='{"a":1,"b":{"c":2},"d":[1,2,3]}';
r:=c;
p := '$';
v:=null;
pck_api_json.write(r, p, v);
print(COALESCE(v, 'null') || ' at ' || p || ' in ' || c || ' => ' || r);
--
print;
print('Print');
c:='{"a":1,"b":{"c":2},"d":[1,2,3]}';
r:=c;
pck_api_json.print(r);
print(c || ' => ' || CHR(10) || r);
print;
print('To XML');
c:='{"a":1,"b":{"c":{"d":"e"}},"f":[1,2,3],"g":"hello world","h":true,"i":null,"j":3.14}';
r:=pck_api_json.to_xml(c);
print(c || ' => ' || CHR(10) || r);
print;
print('To YAML');
c:='{"a":1,"b":{"c":{"d":"e"}},"f":[1,2,3],"g":"hello world","h":true,"i":null,"j":3.14}';
r:=pck_api_json.to_yaml(c);
print(c || ' => ' || CHR(10) || r);
print;
end;
/Markdown
Package for Markdown document generation and export to PDF and HTML
example
DECLARE
c clob;
b blob;
h clob;
BEGIN
pck_api_md.init(c);
pck_api_md.h1(c, 'Title');
pck_api_md.h2(c, 'Subtitle 1');
pck_api_md.p(c, 'Paragraph with some text.');
pck_api_md.li(c, 'item 1');
pck_api_md.li(c, 'item 2');
pck_api_md.lf(c);
pck_api_md.h2(c, 'Subtitle 2');
pck_api_md.p(c, 'Another paragraph under subtitle 2.');
pck_api_md.link(c, 'Link text', 'https://odbvue.com');
pck_api_md.md_table(
c,
'[{"col1":"abc","col2":"123"},{"col1":"def","col2":"456"}]',
'{"col1":{"title":"Column 1"},"col2":{"title":"Column 2"}}'
);
pck_api_md.image(c, 'https://wiki.odbvue.com/logo.svg', 'logo');
pck_api_md.code_inline(c, 'inline code example');
pck_api_md.code_block(c, 'SELECT * FROM dual;', 'sql');
pck_api_md.h2(c, 'Subtitle 3');
pck_api_md.quote(c, 'This is a ' || pck_api_md.b('blockquote') || ' example.');
pck_api_md.note(c, 'This is a note.');
dbms_output.put_line('');
dbms_output.put_line('--- Generated MD ---');
dbms_output.put_line(dbms_lob.substr(c, 32000, 1));
dbms_output.put_line('');
dbms_output.put_line('--- Converted to HTML ---');
pck_api_md.to_html(c, h);
dbms_output.put_line(dbms_lob.substr(h, 32000, 1));
dbms_output.put_line('');
dbms_output.put_line('--- Converted to PDF ---');
pck_api_md.to_pdf(c, b);
dbms_output.put_line('Size: ' || dbms_lob.getlength(b));
dbms_output.put_line(pck_api_lob.blob_to_base64(b));
pck_api_md.finalize(c);
END;
/Openai
Package provides implementation of Open AI API
example
DECLARE
c_api_key VARCHAR2(2000 CHAR) := '****************';
r_message CLOB;
r_error VARCHAR2(2000 CHAR);
BEGIN
DBMS_OUTPUT.PUT_LINE('Testing OpenAI API');
DBMS_OUTPUT.PUT_LINE('');
DBMS_OUTPUT.PUT_LINE('RESPONSES');
pck_api_openai.responses(
p_api_key => c_api_key,
p_model => 'gpt-5',
p_input => 'Please tell me a joke about databases.',
r_output => r_message,
r_error => r_error
);
IF r_error IS NOT NULL THEN
DBMS_OUTPUT.PUT_LINE('Error: ' || r_error);
RETURN;
END IF;
DBMS_OUTPUT.PUT_LINE(r_message);
DBMS_OUTPUT.PUT_LINE('');
END;
/Pdf
Package for creating PDF documents, credits to https://github.com/antonscheffer/as_pdf
example
DECLARE
v_pdf_blob blob;
BEGIN
-- Initialize PDF
pck_api_pdf.init();
-- Set document info
pck_api_pdf.set_info(
p_title => 'Simple PDF Example',
p_author => 'PL/SQL',
p_subject => 'Basic PDF Generation'
);
-- Add first page
pck_api_pdf.new_page();
-- Write title
pck_api_pdf.set_font(p_family => 'helvetica', p_style => 'B', p_fontsize_pt => 24);
pck_api_pdf.insert_txt(
p_x => 50,
p_y => 750,
p_txt => 'Simple PDF Example',
p_fontsize => 24,
p_color => '0000FF'
);
-- Write paragraph
pck_api_pdf.set_font(p_family => 'helvetica', p_style => 'N', p_fontsize_pt => 12);
pck_api_pdf.multi_cell(
p_txt => 'This is a simple example of PDF generation using the pck_api_pdf package. ' ||
'This paragraph demonstrates basic text output in a PDF document. ' ||
'The PDF library supports various fonts, sizes, colors, and formatting options.',
p_x => 50,
p_y => 700,
p_width => 300,
p_fontsize => 12,
p_txt_color => '000000'
);
-- Generate PDF
v_pdf_blob := pck_api_pdf.finish_pdf();
-- Display info
dbms_output.put_line('PDF generated successfully!');
dbms_output.put_line('Size: ' || dbms_lob.getlength(v_pdf_blob) || ' bytes');
dbms_output.put_line(pck_api_lob.blob_to_base64(v_pdf_blob));
EXCEPTION WHEN OTHERS THEN
dbms_output.put_line('Error: ' || sqlerrm);
END;
/Settings
Package provides methods for managing application settings
example
SET SERVEROUTPUT ON;
DECLARE
v_value app_settings.value%TYPE;
BEGIN
pck_api_settings.write('DUMMY', 'Dummy setting', '1');
COMMIT;
pck_api_settings.read('DUMMY', v_value);
DBMS_OUTPUT.PUT_LINE('Value of DUMMY setting: ' || v_value);
END;
/
DECLARE
v_value VARCHAR2(200 CHAR) := 'This is a secret value';
BEGIN
DBMS_OUTPUT.PUT_LINE(v_value);
DBMS_OUTPUT.PUT_LINE('=>');
v_value := pck_api_settings.enc(v_value);
DBMS_OUTPUT.PUT_LINE(v_value);
DBMS_OUTPUT.PUT_LINE('=>');
v_value := pck_api_settings.dec(v_value);
DBMS_OUTPUT.PUT_LINE(v_value);
DBMS_OUTPUT.PUT_LINE('=>');
END;
/Storage
Package for storing and processing large binary objects
example
DECLARE
id app_storage.id%TYPE;
b app_storage.content%TYPE;
n app_storage.file_name%TYPE;
s PLS_INTEGER;
e VARCHAR2(100);
m VARCHAR2(100);
BEGIN
-- local
b := utl_raw.cast_to_raw('Hello World!');
n := 'hello.txt';
pck_api_storage.upload(b, n, id);
dbms_output.put_line(' uploaded file ID: ' || id);
COMMIT;
b := EMPTY_BLOB();
pck_api_storage.download(id, b, n, s, e, m);
dbms_output.put_line(' downloaded file name: ' || n);
dbms_output.put_line(' downloaded file size: ' || s);
dbms_output.put_line(' downloaded file extension: ' || e);
dbms_output.put_line(' downloaded file mime type: ' || m);
dbms_output.put_line(' -- ');
dbms_output.put_line(' downloaded file actual size: ' || dbms_lob.getlength(b));
-- s3
-- pck_api_settings.write('APP_STORAGE_S3_URI', 'Storage URI for S3 files', 'https://objectstorage.<region>.oraclecloud.com/n/<namespace>/b/<bucket/o/');
pck_api_settings.write('APP_STORAGE_S3_URI', 'Storage URI for S3 files', 'https://objectstorage.eu-stockholm-1.oraclecloud.com/n/axuctz2iko0g/b/odbvue-obj/o/');
pck_api_storage.upload(b, n, id, TRUE);
dbms_output.put_line(' uploaded file ID to S3: ' || id);
COMMIT;
b := EMPTY_BLOB();
pck_api_storage.download(id, b, n, s, e, m);
dbms_output.put_line(' downloaded file name from S3: ' || n);
dbms_output.put_line(' downloaded file size from S3: ' || s);
dbms_output.put_line(' downloaded file extension from S3: ' || e);
dbms_output.put_line(' downloaded file mime type from S3: ' || m);
dbms_output.put_line(' -- ');
dbms_output.put_line(' downloaded file actual size from S3: ' || dbms_lob.getlength(b));
END;
/XML
Package for handling xml
example
DECLARE
c clob := '<root>
<a>1</a>
<b>
<c>
<d>e</d>
</c>
</b>
<f>
<item>1</item>
<item>2</item>
<item>3</item>
</f>
<g>hello world</g>
<h>true</h>
<i>null</i>
<j>3.14</j>
</root>';
r clob;
v clob;
p VARCHAR2(2000 CHAR);
b boolean;
n PLS_INTEGER;
PROCEDURE print(c clob DEFAULT NULL)
AS
BEGIN
dbms_output.put_line(dbms_lob.substr(c, 4000));
END;
FUNCTION tf(b IN boolean) RETURN VARCHAR2
AS
BEGIN
RETURN CASE WHEN b THEN 'true' ELSE 'false' END;
END;
BEGIN
print('Begin');
print(c);
print;
print('Init');
r:= pck_api_xml.init;
print(r);
print;
print('Exists');
p := '$.a';
b := pck_api_xml.exists(c, p);
print(p || ' => ' || tf(b)); -- true
p := '$.b.c';
b := pck_api_xml.exists(c, p);
print(p || ' => ' || tf(b)); -- true
p := '$.b.d';
b := pck_api_xml.exists(c, p);
print(p || ' => ' || tf(b)); -- false
p := '$.x';
b := pck_api_xml.exists(c, p);
print(p || ' => ' || tf(b)); -- false
p := '$.f[1]';
b := pck_api_xml.exists(c, p);
print(p || ' => ' || tf(b)); -- true
p := '$.f[10]';
b := pck_api_xml.exists(c, p);
print(p || ' => ' || tf(b)); -- false
print;
print('Read');
p := '$.a';
r := pck_api_xml.read(c, p);
print(p || ' => ' || r); -- 1
p := '$.b';
r := pck_api_xml.read(c, p);
print(p || ' => ' || r); -- <c>2</c>
p := '$.f[3]';
r := pck_api_xml.read(c, p);
print(p || ' => ' || r); -- 3
p := '$.f[10]';
r := pck_api_xml.read(c, p);
print(p || ' => ' || r); -- NULL
print;
print('Typeof');
p := '$.a';
r := pck_api_xml.typeof(c, p);
print(p || ' => ' || r); -- string or number
p := '$.b';
r := pck_api_xml.typeof(c, p);
print(p || ' => ' || r); -- object
p := '$.f';
r := pck_api_xml.typeof(c, p);
print(p || ' => ' || r); -- array
p := '$.x';
r := pck_api_xml.typeof(c, p);
print(p || ' => ' || r); -- undefined
print;
print('Elcount');
p := '$.a';
n := pck_api_xml.elcount(c, p);
print(p || ' element count => ' || n); -- 1
p := '$.f';
n := pck_api_xml.elcount(c, p);
print(p || ' element count in => ' || n); -- 3
p := '$';
n := pck_api_xml.elcount(c, p);
print(p || ' element count in => ' || n); -- 7
print;
print('Keys');
p := '$';
r := pck_api_xml.keys(c, p);
print(p || ' keys => ' || r); -- ["a","b","f","g","h","i","j"]
p := '$.b';
r := pck_api_xml.keys(c, p);
print(p || ' keys => ' || r); -- ["c"]
p := '$.f';
r := pck_api_xml.keys(c, p);
print(p || ' keys => ' || r); -- []
print;
print ('Write');
--
r:=c;
p := '$.a';
v:='42';
pck_api_xml.write(r, p, v);
print(v || ' at ' || p || ' => ' || r);
--
r:=c;
p := '$.a.b.c';
v:='<x><y>z</y></x>';
pck_api_xml.write(r, p, v);
print(v || ' at ' || p || ' => ' || r);
--
r:=c;
p := '$.b';
v:=null;
pck_api_xml.write(r, p, v);
print(COALESCE(v, 'null') || ' at ' || p || ' => ' || r);
r:=c;
p := '$';
v:=null;
pck_api_xml.write(r, p, v);
print(COALESCE(v, 'null') || ' at ' || p || ' => ' || r);
--
print;
print('Print');
r:='<root><a>1</a><b><c>2</c></b><d><item>1</item><item>2</item><item>3</item></d></root>';
v:=r;
pck_api_xml.print(v);
print(r || ' => ' || CHR(10) || v);
print;
print('To YAML');
r:=pck_api_xml.to_yaml(c);
print(r);
print;
print('To JSON');
r:=pck_api_xml.to_json(c);
print(r);
print;
end;
/Validate
Package provides methods for validating values against rules
example
SET FEEDBACK OFF;
PROMPT ========== REQUIRED ==========
-- TEST 1.1: required - POSITIVE (non-empty value)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('John', '{"type":"required","message":"Name is required"}');
DBMS_OUTPUT.put_line('TEST 1.1 (required - POSITIVE): '||NVL(v_msg,'OK'));
END;
/
-- TEST 1.2: required - NEGATIVE (empty value)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('', '{"type":"required","message":"Name is required"}');
DBMS_OUTPUT.put_line('TEST 1.2 (required - NEGATIVE): '||NVL(v_msg,'OK'));
END;
/
PROMPT ========== MIN-LENGTH ==========
-- TEST 2.1: min-length - POSITIVE (length meets minimum)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('Hello', '{"type":"min-length","params":3,"message":"Min 3 chars"}');
DBMS_OUTPUT.put_line('TEST 2.1 (min-length - POSITIVE): '||NVL(v_msg,'OK'));
END;
/
-- TEST 2.2: min-length - NEGATIVE (length below minimum)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('Hi', '{"type":"min-length","params":3,"message":"Min 3 chars"}');
DBMS_OUTPUT.put_line('TEST 2.2 (min-length - NEGATIVE): '||NVL(v_msg,'OK'));
END;
/
PROMPT ========== MAX-LENGTH ==========
-- TEST 3.1: max-length - POSITIVE (length within maximum)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('Hi', '{"type":"max-length","params":5,"message":"Max 5 chars"}');
DBMS_OUTPUT.put_line('TEST 3.1 (max-length - POSITIVE): '||NVL(v_msg,'OK'));
END;
/
-- TEST 3.2: max-length - NEGATIVE (length exceeds maximum)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('HelloWorld', '{"type":"max-length","params":5,"message":"Max 5 chars"}');
DBMS_OUTPUT.put_line('TEST 3.2 (max-length - NEGATIVE): '||NVL(v_msg,'OK'));
END;
/
PROMPT ========== EQUALS ==========
-- TEST 4.1: equals - POSITIVE (values match)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('admin', '{"type":"equals","params":"admin","message":"Must be admin"}');
DBMS_OUTPUT.put_line('TEST 4.1 (equals - POSITIVE): '||NVL(v_msg,'OK'));
END;
/
-- TEST 4.2: equals - NEGATIVE (values do not match)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('user', '{"type":"equals","params":"admin","message":"Must be admin"}');
DBMS_OUTPUT.put_line('TEST 4.2 (equals - NEGATIVE): '||NVL(v_msg,'OK'));
END;
/
PROMPT ========== EQUALS-NOT ==========
-- TEST 5.1: equals-not - POSITIVE (values are different)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('user', '{"type":"equals-not","params":"admin","message":"Cannot be admin"}');
DBMS_OUTPUT.put_line('TEST 5.1 (equals-not - POSITIVE): '||NVL(v_msg,'OK'));
END;
/
-- TEST 5.2: equals-not - NEGATIVE (values are the same)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('admin', '{"type":"equals-not","params":"admin","message":"Cannot be admin"}');
DBMS_OUTPUT.put_line('TEST 5.2 (equals-not - NEGATIVE): '||NVL(v_msg,'OK'));
END;
/
PROMPT ========== SAME-AS ==========
-- TEST 6.1: same-as - POSITIVE (values match)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('SecurePass123', '{"type":"same-as","params":"SecurePass123","message":"Passwords must match"}');
DBMS_OUTPUT.put_line('TEST 6.1 (same-as - POSITIVE): '||NVL(v_msg,'OK'));
END;
/
-- TEST 6.2: same-as - NEGATIVE (values do not match)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('SecurePass123', '{"type":"same-as","params":"DifferentPass","message":"Passwords must match"}');
DBMS_OUTPUT.put_line('TEST 6.2 (same-as - NEGATIVE): '||NVL(v_msg,'OK'));
END;
/
PROMPT ========== STARTS-WITH ==========
-- TEST 7.1: starts-with - POSITIVE (starts with prefix)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('https://example.com', '{"type":"starts-with","params":"https","message":"Must start with https"}');
DBMS_OUTPUT.put_line('TEST 7.1 (starts-with - POSITIVE): '||NVL(v_msg,'OK'));
END;
/
-- TEST 7.2: starts-with - NEGATIVE (does not start with prefix)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('http://example.com', '{"type":"starts-with","params":"https","message":"Must start with https"}');
DBMS_OUTPUT.put_line('TEST 7.2 (starts-with - NEGATIVE): '||NVL(v_msg,'OK'));
END;
/
PROMPT ========== ENDS-WITH ==========
-- TEST 8.1: ends-with - POSITIVE (ends with suffix)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('user@example.com', '{"type":"ends-with","params":".com","message":"Must end with .com"}');
DBMS_OUTPUT.put_line('TEST 8.1 (ends-with - POSITIVE): '||NVL(v_msg,'OK'));
END;
/
-- TEST 8.2: ends-with - NEGATIVE (does not end with suffix)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('user@example.org', '{"type":"ends-with","params":".com","message":"Must end with .com"}');
DBMS_OUTPUT.put_line('TEST 8.2 (ends-with - NEGATIVE): '||NVL(v_msg,'OK'));
END;
/
PROMPT ========== CONTAINS ==========
-- TEST 9.1: contains - POSITIVE (contains substring)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('Hello World', '{"type":"contains","params":"World","message":"Must contain World"}');
DBMS_OUTPUT.put_line('TEST 9.1 (contains - POSITIVE): '||NVL(v_msg,'OK'));
END;
/
-- TEST 9.2: contains - NEGATIVE (does not contain substring)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('Hello There', '{"type":"contains","params":"World","message":"Must contain World"}');
DBMS_OUTPUT.put_line('TEST 9.2 (contains - NEGATIVE): '||NVL(v_msg,'OK'));
END;
/
PROMPT ========== GREATER-THAN ==========
-- TEST 10.1: greater-than - POSITIVE (value greater than param)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('100', '{"type":"greater-than","params":50,"message":"Must be > 50"}');
DBMS_OUTPUT.put_line('TEST 10.1 (greater-than - POSITIVE): '||NVL(v_msg,'OK'));
END;
/
-- TEST 10.2: greater-than - NEGATIVE (value not greater than param)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('25', '{"type":"greater-than","params":50,"message":"Must be > 50"}');
DBMS_OUTPUT.put_line('TEST 10.2 (greater-than - NEGATIVE): '||NVL(v_msg,'OK'));
END;
/
PROMPT ========== LESS-THAN ==========
-- TEST 11.1: less-than - POSITIVE (value less than param)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('30', '{"type":"less-than","params":50,"message":"Must be < 50"}');
DBMS_OUTPUT.put_line('TEST 11.1 (less-than - POSITIVE): '||NVL(v_msg,'OK'));
END;
/
-- TEST 11.2: less-than - NEGATIVE (value not less than param)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('75', '{"type":"less-than","params":50,"message":"Must be < 50"}');
DBMS_OUTPUT.put_line('TEST 11.2 (less-than - NEGATIVE): '||NVL(v_msg,'OK'));
END;
/
PROMPT ========== IN-RANGE ==========
-- TEST 12.1: in-range - POSITIVE (value within range)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('15', '{"type":"in-range","params":[10,20],"message":"Must be between 10 and 20"}');
DBMS_OUTPUT.put_line('TEST 12.1 (in-range - POSITIVE): '||NVL(v_msg,'OK'));
END;
/
-- TEST 12.2: in-range - NEGATIVE (value outside range)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('25', '{"type":"in-range","params":[10,20],"message":"Must be between 10 and 20"}');
DBMS_OUTPUT.put_line('TEST 12.2 (in-range - NEGATIVE): '||NVL(v_msg,'OK'));
END;
/
PROMPT ========== INCLUDES ==========
-- TEST 13.1: includes - POSITIVE (value in list)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('green', '{"type":"includes","params":["red","green","blue"],"message":"Invalid color"}');
DBMS_OUTPUT.put_line('TEST 13.1 (includes - POSITIVE): '||NVL(v_msg,'OK'));
END;
/
-- TEST 13.2: includes - NEGATIVE (value not in list)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('yellow', '{"type":"includes","params":["red","green","blue"],"message":"Invalid color"}');
DBMS_OUTPUT.put_line('TEST 13.2 (includes - NEGATIVE): '||NVL(v_msg,'OK'));
END;
/
PROMPT ========== SET ==========
-- TEST 14.1: set - POSITIVE (value in set)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('active', '{"type":"set","params":["active","inactive","pending"],"message":"Invalid status"}');
DBMS_OUTPUT.put_line('TEST 14.1 (set - POSITIVE): '||NVL(v_msg,'OK'));
END;
/
-- TEST 14.2: set - NEGATIVE (value not in set)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('deleted', '{"type":"set","params":["active","inactive","pending"],"message":"Invalid status"}');
DBMS_OUTPUT.put_line('TEST 14.2 (set - NEGATIVE): '||NVL(v_msg,'OK'));
END;
/
PROMPT ========== EMAIL ==========
-- TEST 15.1: email - POSITIVE (valid email)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('user@example.com', '{"type":"email","message":"Invalid email"}');
DBMS_OUTPUT.put_line('TEST 15.1 (email - POSITIVE): '||NVL(v_msg,'OK'));
END;
/
-- TEST 15.2: email - NEGATIVE (invalid email)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('notanemail', '{"type":"email","message":"Invalid email"}');
DBMS_OUTPUT.put_line('TEST 15.2 (email - NEGATIVE): '||NVL(v_msg,'OK'));
END;
/
PROMPT ========== URL ==========
-- TEST 16.1: url - POSITIVE (valid URL)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('https://example.com/path', '{"type":"url","message":"Invalid URL"}');
DBMS_OUTPUT.put_line('TEST 16.1 (url - POSITIVE): '||NVL(v_msg,'OK'));
END;
/
-- TEST 16.2: url - NEGATIVE (invalid URL)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('not a url', '{"type":"url","message":"Invalid URL"}');
DBMS_OUTPUT.put_line('TEST 16.2 (url - NEGATIVE): '||NVL(v_msg,'OK'));
END;
/
PROMPT ========== PASSWORD ==========
-- TEST 17.1: password - POSITIVE (valid password)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('SecurePass123', '{"type":"password","message":"Invalid password"}');
DBMS_OUTPUT.put_line('TEST 17.1 (password - POSITIVE): '||NVL(v_msg,'OK'));
END;
/
-- TEST 17.2: password - NEGATIVE (password too short)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('Pass1', '{"type":"password","message":"Invalid password"}');
DBMS_OUTPUT.put_line('TEST 17.2 (password - NEGATIVE): '||NVL(v_msg,'OK'));
END;
/
PROMPT ========== IP ==========
-- TEST 18.1: ip - POSITIVE (valid IPv4)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('192.168.1.1', '{"type":"ip","message":"Invalid IP"}');
DBMS_OUTPUT.put_line('TEST 18.1 (ip - POSITIVE): '||NVL(v_msg,'OK'));
END;
/
-- TEST 18.2: ip - NEGATIVE (invalid IPv4)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('999.999.999.999', '{"type":"ip","message":"Invalid IP"}');
DBMS_OUTPUT.put_line('TEST 18.2 (ip - NEGATIVE): '||NVL(v_msg,'OK'));
END;
/
PROMPT ========== REGEXP ==========
-- TEST 19.1: regexp - POSITIVE (matches pattern)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('ABC123', '{"type":"regexp","params":"^[A-Z]{3}[0-9]{3}$","message":"Invalid format"}');
DBMS_OUTPUT.put_line('TEST 19.1 (regexp - POSITIVE): '||NVL(v_msg,'OK'));
END;
/
-- TEST 19.2: regexp - NEGATIVE (does not match pattern)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('XYZ', '{"type":"regexp","params":"^[A-Z]{3}[0-9]{3}$","message":"Invalid format"}');
DBMS_OUTPUT.put_line('TEST 19.2 (regexp - NEGATIVE): '||NVL(v_msg,'OK'));
END;
/
PROMPT ========== IS-JSON ==========
-- TEST 20.1: is-json - POSITIVE (valid JSON)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('{"key":"value"}', '{"type":"is-json","message":"Invalid JSON"}');
DBMS_OUTPUT.put_line('TEST 20.1 (is-json - POSITIVE): '||NVL(v_msg,'OK'));
END;
/
-- TEST 20.2: is-json - NEGATIVE (invalid JSON)
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('not json', '{"type":"is-json","message":"Invalid JSON"}');
DBMS_OUTPUT.put_line('TEST 20.2 (is-json - NEGATIVE): '||NVL(v_msg,'OK'));
END;
/
PROMPT ========== MULTI-RULE CASE ==========
-- TEST 21: Multiple rules - all must pass
DECLARE
v_msg VARCHAR2(4000);
v_rules CLOB := '[
{"type":"required","message":"Email is required"},
{"type":"min-length","params":5,"message":"Email must be at least 5 chars"},
{"type":"email","message":"Must be a valid email"}
]';
BEGIN
v_msg := pck_api_validate.validate('user@example.com', v_rules);
DBMS_OUTPUT.put_line('TEST 21 (multi-rule - POSITIVE): '||NVL(v_msg,'OK'));
END;
/
-- TEST 22: Multiple rules - fails on first violation
DECLARE
v_msg VARCHAR2(4000);
v_rules CLOB := '[
{"type":"required","message":"Email is required"},
{"type":"min-length","params":5,"message":"Email must be at least 5 chars"},
{"type":"email","message":"Must be a valid email"}
]';
BEGIN
v_msg := pck_api_validate.validate('a@b.c', v_rules);
DBMS_OUTPUT.put_line('TEST 22 (multi-rule - NEGATIVE): '||NVL(v_msg,'OK'));
END;
/
PROMPT ========== NO MESSAGE CASE ==========
-- TEST 23: Rule without custom message - uses default
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('123', '{"type":"required"}');
DBMS_OUTPUT.put_line('TEST 23 (no message - POSITIVE): '||NVL(v_msg,'OK'));
END;
/
-- TEST 24: Rule without custom message - negative case shows default message
DECLARE
v_msg VARCHAR2(4000);
BEGIN
v_msg := pck_api_validate.validate('', '{"type":"required"}');
DBMS_OUTPUT.put_line('TEST 24 (no message - NEGATIVE): '||NVL(v_msg,'OK'));
END;
/YAML
Package for handling YAML
example
DECLARE
c CLOB := 'a: 1
b:
c:
d: e
f:
- 1
- 2
- 3
g: hello world
h: true
i: null
j: 3.14';
r CLOB;
p VARCHAR2(2000 CHAR);
v CLOB;
b BOOLEAN;
n PLS_INTEGER;
PROCEDURE print(c clob DEFAULT NULL)
AS
BEGIN
dbms_output.put_line(dbms_lob.substr(c, 4000));
END;
FUNCTION tf(b IN boolean) RETURN VARCHAR2
AS
BEGIN
RETURN CASE WHEN b THEN 'true' ELSE 'false' END;
END;
BEGIN
print('YAML Input:');
print('-------------------');
print(c);
print('-------------------');
print;
print('Init');
r:= pck_api_yaml.init;
print(r || ' => ' || '(0 bytes)');
print;
print('Exists');
p := '$.a';
b := pck_api_yaml.exists(c, p);
print(p || ' => ' || tf(b)); -- true
p := '$.b.c';
b := pck_api_yaml.exists(c, p);
print(p || ' => ' || tf(b)); -- true
p := '$.c.d';
b := pck_api_yaml.exists(c, p);
print(p || ' => ' || tf(b)); -- false
p := '$.x';
b := pck_api_yaml.exists(c, p);
print(p || ' => ' || tf(b)); -- false
p := '$.f[0]';
b := pck_api_yaml.exists(c, p);
print(p || ' => ' || tf(b)); -- true
p := '$.f[10]';
b := pck_api_yaml.exists(c, p);
print(p || ' => ' || tf(b)); -- false
print;
print('Read');
p := '$.a';
r := pck_api_yaml.read(c, p);
print(p || ' => ' || r); -- 1
p := '$.b';
r := pck_api_yaml.read(c, p);
print(p || ' => ' || r); -- {c: {d: e}}
p := '$.f[2]';
r := pck_api_yaml.read(c, p);
print(p || ' => ' || r); -- {item: 3}
p := '$.f[10]';
r := pck_api_yaml.read(c, p);
print(p || ' => ' || r); -- NULL
print;
print('Typeof');
p := '$.a';
r := pck_api_yaml.typeof(c, p);
print(p || ' => ' || r); -- number
p := '$.b';
r := pck_api_yaml.typeof(c, p);
print(p || ' => ' || r); -- object
p := '$.f';
r := pck_api_yaml.typeof(c, p);
print(p || ' => ' || r); -- array
p := '$.x';
r := pck_api_yaml.typeof(c, p);
print(p || ' => ' || r); -- undefined
print;
print('Elcount');
p := '$.a';
n := pck_api_yaml.elcount(c, p);
print(p || ' element count => ' || n); -- 1
p := '$.f';
n := pck_api_yaml.elcount(c, p);
print(p || ' element count in => ' || n); -- 3
p := '$.root';
n := pck_api_yaml.elcount(c, p);
print(p || ' element count in => ' || n); -- 7
print;
print('Keys');
p := '$';
r := pck_api_yaml.keys(c, p);
print(p || ' keys => ' || r); -- ["a","b","f","g","h","i","j"]
p := '$.b';
r := pck_api_yaml.keys(c, p);
print(p || ' keys => ' || r); -- ["c"]
p := '$.f';
r := pck_api_yaml.keys(c, p);
print(p || ' keys => ' || r); -- []
print;
print ('Write');
--
r:=c;
p := '$.a';
v:='42';
pck_api_yaml.write(r, p, v);
print(v || ' at ' || p || ' => ' );
print('----');
print(r);
print('----');
--
r:=c;
p := '$.b.c';
v:='x:
y:
z: data';
pck_api_yaml.write(r, p, v);
print(v || ' at ' || p || ' => ');
print('----');
print(r);
print('----');
--
r:=c;
p := '$.b';
v:=null;
pck_api_yaml.write(r, p, v);
print(COALESCE(v, 'null') || ' at ' || p || ' => ');
print('----');
print(r);
print('----');
--
p := '$';
v:=null;
pck_api_yaml.write(r, p, v);
print(COALESCE(v, 'null') || ' at ' || p || ' => ');
--
print('----');
print(r);
print('----');
print('Print');
pck_api_yaml.print(c);
print(r || ' => ' || CHR(10) || c);
print;
print('To XML');
r:=pck_api_yaml.to_xml(c);
print(r);
print;
print('To JSON');
r:=pck_api_yaml.to_json(c);
print(r);
print;
END;
/ZIP
Package for handling zip files, Credit: https://github.com/antonscheffer/as_zip
example
DECLARE
v_zip BLOB;
v_content BLOB;
v_files odbvue.pck_api_zip.t_file_list;
BEGIN
v_zip := NULL;
v_content := utl_raw.cast_to_raw('Hello from ZIP!');
odbvue.pck_api_zip.add(v_zip, 'test.txt', v_content);
v_files := odbvue.pck_api_zip.list(v_zip);
DBMS_OUTPUT.PUT_LINE('Files in ZIP: ' || v_files.COUNT);
DBMS_OUTPUT.PUT_LINE('File: ' || v_files(1));
odbvue.pck_api_zip.extract(v_zip, 'test.txt', v_content);
DBMS_OUTPUT.PUT_LINE('Content: ' || utl_raw.cast_to_varchar2(v_content));
END;
/