Creating Validation Directives
You can create a validation directive using SQL
CREATE DIRECTIVE statement.
CREATE (OR REPLACE) DIRECTIVE directive_name
FOR json_relational_duality_view_name
VALIDATE
ON ( SELECT | INSERT | UPDATE )+
Processing_Stage_Clause
[ Validate_Enable_Clause ]
USING validation_logic;Processing_Stage_Clauseis one of:BEFORE OBJECTAFTER OBJECTON COMMIT
Validate_Enable_Clauseis:(
VALIDATE|NOVALIDATE) (ENABLE|DISABLE)validation_logicis:a SQL/JSON expression, a PL/SQL function, or a PL/SQL anonymous block
Table 9-1 Validation directive clauses and options
| Clause | What it specifies | Options | Notes |
|---|---|---|---|
ON |
Which operations trigger validation | SELECT, INSERT,
UPDATE (one or more)
|
SELECT validation runs when the
full object is selected; it does not run for queries that select
only a single field from the JSON object. For example: a
select * from <duality_view> or
select data from <duality_view> will invoke
the SELECT validation.
|
| Processing stage | When validation is evaluated | BEFORE OBJECT, AFTER OBJECT,
ON COMMIT |
Failures lead to different outcomes (see “Validation failure behavior”). |
VALIDATE / NOVALIDATE |
Whether existing data is validated when the directive is created | VALIDATE or NOVALIDATE |
If you specify VALIDATE and
validation of the existing data fails, creation of the directive
fails. Default is NOVALIDATE.
|
ENABLE / DISABLE |
Whether validation is active after creation | ENABLE or DISABLE |
Default is ENABLE. ALTER
DIRECTIVE can also be used to enable/disable a
validation directive.
|
USING |
The validation logic | Expression or PL/SQL function or PL/SQL anonymous block | Logic must be deterministic and side-effect free.
DML, ALTER SESSION,
COMMIT/ROLLBACK/SAVEPOINT, PRAGMA
AUTONOMOUS_TRANSACTION, package state mutation, and
references to packages such as UTL_HTTP,
UTL_TCP, and UTL_SMTP are
disallowed.
|
Validation failure behavior
The effect of a validation failure depends on when the validation directive is evaluated:
- SELECT: Oracle raises an error and does not return the document that fails validation.
- BEFORE OBJECT: Oracle rejects the operation before applying it. The statement is not executed, and any partial work for the statement is rolled back
- AFTER OBJECT: Oracle rolls back the statement and raises an error.
- ON COMMIT: Oracle rejects the commit. The commit fails and the transaction is rolled back.
Note:
Validation Directives Restrictions:- Unsupported NLS properties: Session-level settings
for the following NLS properties can result in unexpected behavior with
validation directives:
NLS_SORT,NLS_TERRITORY, andNLS_TIMESTAMP_FORMAT. To help keep directive execution invariant across sessions,ALTER SESSIONstatements are disallowed inside directive validation logic. - SYS schema not supported: Validation directives cannot be created
under the
SYSschema. - Parallel and direct-load DML downgrade: If a directive exists on a duality view, parallel DML (PDML) and direct-load operations (IDL/ODL) are downgraded to serial, conventional DML.
Validate an INSERT before writing the document (BEFORE OBJECT)
employee_dv is below 10,000 for
inserts.CREATE DIRECTIVE salary_less_10k FOR employee_dv
VALIDATE
ON INSERT
BEFORE OBJECT
USING json_value(new.data, '$.salary') < 10000;If
validation fails, the insert statement fails and is rolled back.Validate a document when it is selected (SELECT, AFTER OBJECT)
CREATE OR REPLACE DIRECTIVE name_only_king FOR employee_dv
VALIDATE
ON SELECT
AFTER OBJECT
NOVALIDATE ENABLE
USING json_value(new.data, '$.employeeName') = 'KING';If
validation fails, Oracle raises an error and the document is not returned.Validation Using a PL/SQL Function (BEFORE OBJECT, SCOPE OBJECT)
This example shows how to define validation logic in a PL/SQL function and attach it to a duality view using a validation directive. It enforces the business rule: salary must be at least 2000 for new employee objects inserted into duality view.
CREATE OR REPLACE FUNCTION isThisSalaryOK(old_data JSON, new_data JSON)
RETURN BOOLEAN
IS
f BOOLEAN;
BEGIN
IF json_value(new_data, '$.salary') < 2000 THEN
f := false;
ELSE
f := true;
END IF;
RETURN f;
END;
/The
function takes two JSON arguments: old_data - the “before” version
of the document. new_data - the “after” (proposed) version of the
document being inserted/updated. For an INSERT validation, the rule
is typically expressed using new_data (since there is no prior
version in the same sense as an update). The function returns a SQL BOOLEAN:
TRUE means validation passes. FALSE means validation
fails, and the database raises a validation error for the directive.
Step 2: Create the validation directive on the duality view
CREATE DIRECTIVE validate_salary FOR employee_dv
VALIDATE
ON INSERT
BEFORE OBJECT
NOVALIDATE
USING isThisSalaryOK;Here is another example that prevents users from adding items to an order document after the order status is shipped:
Example 9-1 Order-status validation directive
The validation logic runs at commit time, compares the old and new item
counts, and rejects the transaction if the item count changes while the existing
status is shipped. Because the directive runs ON COMMIT, it
also protects related documents that share the same underlying tables.
Step 1: Create a PL/SQL Validation Function
This function checks if the item count has changed and the status is not SHIPPED.
CREATE OR REPLACE FUNCTION ChkItemCntChg(
p_old_json IN JSON,
p_new_json IN JSON
) RETURN BOOLEAN
AS
l_old_obj JSON_OBJECT_T;
l_new_obj JSON_OBJECT_T;
l_old_cnt PLS_INTEGER := 0;
l_new_cnt PLS_INTEGER := 0;
l_status VARCHAR2(20);
BEGIN
-- Read the old and new order objects
l_old_obj := json_object_t(p_old_json.data);
l_new_obj := json_object_t(p_new_json.data);
-- Get the previous order status and previous and latest item counts
l_status := l_old_obj.GET_STRING('status');
l_old_cnt := l_old_obj.GET_ARRAY('orderItems').GET_SIZE;
l_new_cnt := l_new_obj.GET_ARRAY('orderItems').GET_SIZE;
IF l_old_cnt != l_new_cnt AND l_status = 'shipped' THEN
RETURN FALSE; -- reject additions after shipment
END IF;
RETURN TRUE;
END;
/
Step 2: Create a directive to ensure that a new item is not added to an order that has already shipped.
CREATE DIRECTIVE NewItemValidate FOR Orders_DualV
VALIDATE
ON UPDATE INSERT
ON COMMIT
USING CheckItemCntChg;
Note:
Ensure the identifier named in the USING clause matches the
helper function you compile in your environment.