Last active
May 2, 2020 12:22
-
-
Save PhilippSalvisberg/65532b3131a0a272db42049542051518 to your computer and use it in GitHub Desktop.
Issue 4 in Trivadis/plsql-cop-sqldev
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CREATE OR REPLACE PACKAGE BODY om_tapigen IS | |
----------------------------------------------------------------------------- | |
-- private global constants (c_*) | |
----------------------------------------------------------------------------- | |
c_generator_error_number CONSTANT PLS_INTEGER := -20000; | |
c_lf CONSTANT VARCHAR2(2 CHAR) := chr(10); | |
c_lflf CONSTANT VARCHAR2(3 CHAR) := chr(10) || chr(10); | |
c_list_delimiter CONSTANT VARCHAR2(3 CHAR) := ',' || c_lf; | |
c_custom_defaults_present_msg CONSTANT VARCHAR2(30) := 'SEE_END_OF_API_PACKAGE_SPEC'; | |
c_spec_options_min_line CONSTANT NUMBER := 5; | |
c_spec_options_max_line CONSTANT NUMBER := 40; | |
c_debug_max_runs CONSTANT NUMBER := 1000; | |
----------------------------------------------------------------------------- | |
-- private record (t_rec_*) and collection (t_tab_*) types | |
----------------------------------------------------------------------------- | |
TYPE t_rec_params IS RECORD( | |
table_name all_objects.object_name%TYPE, | |
owner all_users.username%TYPE, | |
enable_insertion_of_rows BOOLEAN, | |
enable_column_defaults BOOLEAN, | |
enable_update_of_rows BOOLEAN, | |
enable_deletion_of_rows BOOLEAN, | |
enable_parameter_prefixes BOOLEAN, | |
enable_proc_with_out_params BOOLEAN, | |
enable_getter_and_setter BOOLEAN, | |
col_prefix_in_method_names BOOLEAN, | |
return_row_instead_of_pk BOOLEAN, | |
double_quote_names BOOLEAN, | |
default_bulk_limit INTEGER, | |
enable_dml_view BOOLEAN, | |
enable_one_to_one_view BOOLEAN, | |
api_name all_objects.object_name%TYPE, | |
sequence_name all_sequences.sequence_name%TYPE, | |
exclude_column_list VARCHAR2(4000 CHAR), | |
audit_column_mappings VARCHAR2(4000 CHAR), | |
audit_user_expression VARCHAR2(4000 CHAR), | |
row_version_column_mapping VARCHAR2(4000 CHAR), | |
enable_custom_defaults BOOLEAN, | |
custom_default_values XMLTYPE, | |
custom_defaults_serialized VARCHAR2(32767 CHAR)); | |
TYPE t_rec_status IS RECORD( | |
generator_action VARCHAR2(30 CHAR), | |
column_prefix all_tab_cols.column_name%TYPE, | |
pk_is_multi_column BOOLEAN, | |
identity_column all_tab_cols.column_name%TYPE, | |
identity_type VARCHAR2(30 CHAR), | |
xmltype_column_present BOOLEAN, | |
number_of_data_columns INTEGER, | |
number_of_pk_columns INTEGER, | |
number_of_uk_columns INTEGER, | |
number_of_fk_columns INTEGER, | |
rpad_columns INTEGER, | |
rpad_pk_columns INTEGER, | |
rpad_uk_columns INTEGER); | |
-- | |
TYPE t_tab_columns IS TABLE OF t_rec_columns INDEX BY BINARY_INTEGER; -- record type is public beacause of util_view_columns_array | |
-- | |
TYPE t_tab_columns_index IS TABLE OF INTEGER INDEX BY user_tab_columns.column_name%TYPE; | |
-- | |
TYPE t_rec_constraints IS RECORD( | |
constraint_name user_constraints.constraint_name%TYPE); | |
TYPE t_tab_constraints IS TABLE OF t_rec_constraints INDEX BY BINARY_INTEGER; | |
-- | |
TYPE t_rec_cons_columns IS RECORD( | |
constraint_name all_cons_columns.constraint_name%TYPE, | |
position all_cons_columns.position%TYPE, | |
column_name all_cons_columns.column_name%TYPE, | |
column_name_length INTEGER, | |
data_type all_tab_cols.data_type%TYPE, | |
r_owner all_users.username%TYPE, | |
r_table_name all_objects.object_name%TYPE, | |
r_column_name all_tab_cols.column_name%TYPE); | |
TYPE t_tab_cons_columns IS TABLE OF t_rec_cons_columns INDEX BY BINARY_INTEGER; | |
-- | |
TYPE t_rec_code_blocks IS RECORD( | |
template VARCHAR2(32767 CHAR), | |
api_spec CLOB, | |
api_spec_varchar_cache VARCHAR2(32767 CHAR), | |
api_body CLOB, | |
api_body_varchar_cache VARCHAR2(32767 CHAR), | |
dml_view CLOB, | |
dml_view_varchar_cache VARCHAR2(32767 CHAR), | |
dml_view_trigger CLOB, | |
dml_view_trigger_varchar_cache VARCHAR2(32767 CHAR), | |
one_to_one_view CLOB, | |
one_to_one_view_varchar_cache VARCHAR2(32767 CHAR) | |
); | |
-- | |
TYPE t_rec_template_options IS RECORD( | |
use_column_defaults BOOLEAN, | |
crud_mode VARCHAR2(10), | |
padding INTEGER); | |
-- | |
TYPE t_tab_vc2_5k IS TABLE OF VARCHAR2(5000) INDEX BY BINARY_INTEGER; | |
-- | |
TYPE t_rec_iterator IS RECORD( | |
column_name all_tab_cols.column_name%TYPE, | |
method_name all_tab_cols.column_name%TYPE, | |
parameter_name all_tab_cols.column_name%TYPE, | |
old_value VARCHAR2(512 CHAR), | |
new_value VARCHAR2(512 CHAR), | |
current_uk_constraint all_objects.object_name%TYPE); | |
-- | |
TYPE t_rec_debug_details IS RECORD( | |
step INTEGER(4), | |
module st_session_module, | |
action st_session_action, | |
start_time TIMESTAMP(6), | |
stop_time TIMESTAMP(6)); | |
TYPE t_tab_debug_details IS TABLE OF t_rec_debug_details INDEX BY BINARY_INTEGER; | |
-- | |
TYPE t_rec_debug IS RECORD( | |
run INTEGER(4), | |
owner all_users.username%TYPE, | |
table_name all_objects.object_name%TYPE, | |
start_time TIMESTAMP(6), | |
stop_time TIMESTAMP(6), | |
details t_tab_debug_details); | |
TYPE t_tab_debug IS TABLE OF t_rec_debug INDEX BY BINARY_INTEGER; | |
----------------------------------------------------------------------------- | |
-- private global variables (g_*) | |
----------------------------------------------------------------------------- | |
--variables | |
g_debug_enabled BOOLEAN; | |
g_debug_run INTEGER; | |
g_debug_step INTEGER; | |
g_debug_module st_session_module; | |
-- records | |
g_params t_rec_params; | |
g_iterator t_rec_iterator; | |
g_code_blocks t_rec_code_blocks; | |
g_status t_rec_status; | |
g_template_options t_rec_template_options; | |
-- collections | |
g_columns t_tab_columns; | |
g_columns_reverse_index t_tab_columns_index; | |
g_uk_constraints t_tab_constraints; | |
g_fk_constraints t_tab_constraints; | |
g_pk_columns t_tab_cons_columns; | |
g_uk_columns t_tab_cons_columns; | |
g_fk_columns t_tab_cons_columns; | |
g_debug t_tab_debug; | |
----------------------------------------------------------------------------- | |
-- private global cursors (g_cur_*) | |
----------------------------------------------------------------------------- | |
$IF $$db_version < 121 $THEN | |
CURSOR g_cur_columns IS | |
WITH not_null_columns AS | |
(SELECT CASE | |
WHEN instr(column_name_nn, '"') = 0 THEN | |
upper(column_name_nn) | |
ELSE | |
TRIM(both '"' FROM column_name_nn) | |
END AS column_name_nn | |
FROM (SELECT regexp_substr( | |
om_tapigen.util_get_cons_search_condition( | |
p_owner => USER, | |
p_constraint_name => constraint_name), | |
'^\s*("[^"]+"|[a-zA-Z0-9_#$]+)\s+is\s+not\s+null\s*$', | |
1, | |
1, | |
'i', | |
1) AS column_name_nn | |
FROM all_constraints | |
WHERE owner = g_params.owner | |
AND table_name = g_params.table_name | |
AND constraint_type = 'C' | |
AND status = 'ENABLED') | |
WHERE column_name_nn IS NOT NULL), | |
excluded_columns AS | |
(SELECT column_value AS column_name_excluded | |
FROM TABLE(om_tapigen.util_split_to_table(g_params.exclude_column_list))), | |
identity_columns AS ( | |
SELECT 'DUMMY_COLUMN_NAME' AS column_name_identity, | |
NULL AS identity_type | |
FROM dual | |
), | |
t AS | |
(SELECT DISTINCT column_id, | |
column_name, | |
data_type, | |
char_length, | |
data_length, | |
data_precision, | |
data_scale, | |
identity_type, | |
'N' AS default_on_null_yn, | |
CASE | |
WHEN data_default IS NOT NULL THEN | |
(SELECT om_tapigen.util_get_column_data_default(p_owner => g_params.owner, | |
p_table_name => table_name, | |
p_column_name => column_name) | |
FROM dual) | |
ELSE | |
NULL | |
END AS data_default, | |
virtual_column, | |
CASE | |
WHEN column_name_nn IS NOT NULL THEN | |
'N' | |
ELSE | |
'Y' | |
END AS is_nullable_yn, | |
CASE | |
WHEN (virtual_column = 'YES' AND data_type != 'XMLTYPE') OR | |
excluded_columns.column_name_excluded IS NOT NULL THEN | |
'Y' | |
ELSE | |
'N' | |
END AS is_excluded_yn | |
FROM all_tab_cols | |
LEFT JOIN not_null_columns ON all_tab_cols.column_name = not_null_columns.column_name_nn | |
LEFT JOIN excluded_columns ON all_tab_cols.column_name = excluded_columns.column_name_excluded | |
LEFT JOIN identity_columns ON all_tab_cols.column_name = identity_columns.column_name_identity | |
WHERE owner = g_params.owner | |
AND table_name = g_params.table_name | |
AND hidden_column = 'NO' | |
ORDER BY column_id) | |
SELECT column_name, | |
data_type, | |
char_length, | |
data_length, | |
data_precision, | |
data_scale, | |
data_default, | |
NULL AS data_custom_default, | |
NULL AS custom_default_source, | |
identity_type, | |
default_on_null_yn, | |
'N' AS is_pk_yn, | |
'N' AS is_uk_yn, | |
'N' AS is_fk_yn, | |
is_nullable_yn, | |
is_excluded_yn, | |
NULL AS audit_type, | |
NULL AS row_version_expression, | |
NULL AS r_owner, | |
NULL AS r_table_name, | |
NULL AS r_column_name | |
FROM t; | |
$ELSE | |
CURSOR g_cur_columns IS | |
WITH not_null_columns AS | |
(SELECT CASE | |
WHEN instr(column_name_nn, '"') = 0 THEN | |
upper(column_name_nn) | |
ELSE | |
TRIM(both '"' FROM column_name_nn) | |
END AS column_name_nn | |
FROM (SELECT regexp_substr( | |
search_condition_vc, | |
'^\s*("[^"]+"|[a-zA-Z0-9_#$]+)\s+is\s+not\s+null\s*$', | |
1, | |
1, | |
'i', | |
1) AS column_name_nn | |
FROM all_constraints | |
WHERE owner = g_params.owner | |
AND table_name = g_params.table_name | |
AND constraint_type = 'C' | |
AND status = 'ENABLED') | |
WHERE column_name_nn IS NOT NULL), | |
excluded_columns AS | |
(SELECT column_value AS column_name_excluded | |
FROM TABLE(om_tapigen.util_split_to_table(g_params.exclude_column_list))), | |
identity_columns AS | |
(SELECT column_name AS column_name_identity, | |
generation_type AS identity_type | |
FROM all_tab_identity_cols | |
WHERE owner = g_params.owner | |
AND table_name = g_params.table_name), | |
t AS | |
(SELECT DISTINCT column_id, | |
column_name, | |
data_type, | |
char_length, | |
data_length, | |
data_precision, | |
data_scale, | |
identity_type, | |
CASE WHEN default_on_null = 'YES' THEN 'Y' ELSE 'N' END AS default_on_null_yn, | |
CASE | |
WHEN data_default IS NOT NULL THEN | |
(SELECT om_tapigen.util_get_column_data_default(p_owner => g_params.owner, | |
p_table_name => table_name, | |
p_column_name => column_name) | |
FROM dual) | |
ELSE | |
NULL | |
END AS data_default, | |
virtual_column, | |
CASE | |
WHEN column_name_nn IS NOT NULL THEN | |
'N' | |
ELSE | |
'Y' | |
END AS is_nullable_yn, | |
CASE | |
WHEN (virtual_column = 'YES' AND data_type != 'XMLTYPE') OR | |
excluded_columns.column_name_excluded IS NOT NULL THEN | |
'Y' | |
ELSE | |
'N' | |
END AS is_excluded_yn | |
FROM all_tab_cols | |
LEFT JOIN not_null_columns ON all_tab_cols.column_name = not_null_columns.column_name_nn | |
LEFT JOIN excluded_columns ON all_tab_cols.column_name = excluded_columns.column_name_excluded | |
LEFT JOIN identity_columns ON all_tab_cols.column_name = identity_columns.column_name_identity | |
WHERE owner = g_params.owner | |
AND table_name = g_params.table_name | |
AND hidden_column = 'NO' | |
ORDER BY column_id) | |
SELECT column_name, | |
data_type, | |
char_length, | |
data_length, | |
data_precision, | |
data_scale, | |
data_default, | |
NULL AS data_custom_default, | |
NULL AS custom_default_source, | |
identity_type, | |
default_on_null_yn, | |
'N' AS is_pk_yn, | |
'N' AS is_uk_yn, | |
'N' AS is_fk_yn, | |
is_nullable_yn, | |
is_excluded_yn, | |
NULL AS audit_type, | |
NULL AS row_version_expression, | |
NULL AS r_owner, | |
NULL AS r_table_name, | |
NULL AS r_column_name | |
FROM t; | |
$END | |
----------------------------------------------------------------------------- | |
-- util_execute_sql is a private helper procedure that parses and executes | |
-- generated code with the help of DBMS_SQL package. Execute immediate is not | |
-- used here directly, because of the missing possibility of parsing a | |
-- statement in a performant way. Executing immediate and catching | |
-- the error is more expensive than parsing the statement and catching the | |
-- error. | |
----------------------------------------------------------------------------- | |
PROCEDURE util_execute_sql(p_sql IN OUT NOCOPY CLOB) IS | |
v_cursor NUMBER; | |
v_exec_result PLS_INTEGER; | |
BEGIN | |
v_cursor := dbms_sql.open_cursor; | |
dbms_sql.parse(v_cursor, p_sql, dbms_sql.native); | |
v_exec_result := dbms_sql.execute(v_cursor); | |
dbms_sql.close_cursor(v_cursor); | |
EXCEPTION | |
WHEN OTHERS THEN | |
dbms_sql.close_cursor(v_cursor); | |
RAISE; | |
END util_execute_sql; | |
----------------------------------------------------------------------------- | |
-- util_string_to_bool is a private helper function to deliver a | |
-- boolean representation of an string value. True is returned,if: | |
-- true,yes,y,1 | |
-- is given. False is returned when: | |
-- false,no,n,0 | |
-- is given. | |
----------------------------------------------------------------------------- | |
FUNCTION util_string_to_bool(p_string IN VARCHAR2) RETURN BOOLEAN IS | |
BEGIN | |
RETURN CASE WHEN lower(p_string) IN('true', 'yes', 'y', '1') THEN TRUE WHEN lower(p_string) IN('false', | |
'no', | |
'n', | |
'0') THEN FALSE ELSE NULL END; | |
END util_string_to_bool; | |
----------------------------------------------------------------------------- | |
-- util_bool_to_string is a private helper function to deliver a | |
-- varchar2 representation of an boolean value. 'TRUE' is returned,if | |
-- boolean value is true. 'FALSE' is returned when boolean value is false. | |
----------------------------------------------------------------------------- | |
FUNCTION util_bool_to_string(p_bool IN BOOLEAN) RETURN VARCHAR2 IS | |
BEGIN | |
RETURN CASE WHEN p_bool THEN 'TRUE' WHEN NOT p_bool THEN 'FALSE' ELSE NULL END; | |
END util_bool_to_string; | |
FUNCTION util_double_quote(p_name IN VARCHAR2) RETURN VARCHAR2 IS | |
BEGIN | |
RETURN CASE WHEN g_params.double_quote_names THEN '"'||p_name||'"' ELSE p_name END; | |
END util_double_quote; | |
----------------------------------------------------------------------------- | |
-- util_get_attribute_surrogate is a private helper function to find out a | |
-- datatype dependent surrogate. This is required for comparing two | |
-- values of a column e.g. old value and new value. There is the special case | |
-- of null comparisison in Oracle,what means null compared with null is | |
-- never true. That is the reason to compare: | |
-- coalesce(old value,surrogate) = coalesce(new value,surrogate) | |
-- that is true,if both sides are null. | |
----------------------------------------------------------------------------- | |
FUNCTION util_get_attribute_surrogate(p_data_type IN user_tab_cols.data_type%TYPE) RETURN VARCHAR2 IS | |
v_return VARCHAR2(100 CHAR); | |
BEGIN | |
v_return := CASE | |
WHEN p_data_type = 'NUMBER' THEN | |
'-999999999999999.999999999999999' | |
WHEN p_data_type LIKE '%CHAR%' THEN | |
'''@@@@@@@@@@@@@@@''' | |
WHEN p_data_type = 'DATE' THEN | |
'TO_DATE(''01.01.1900'',''DD.MM.YYYY'')' | |
WHEN p_data_type LIKE 'TIMESTAMP%' THEN | |
'TO_TIMESTAMP(''01.01.1900'',''dd.mm.yyyy'')' | |
WHEN p_data_type = 'CLOB' THEN | |
'TO_CLOB(''@@@@@@@@@@@@@@@'')' | |
WHEN p_data_type = 'BLOB' THEN | |
'TO_BLOB(UTL_RAW.cast_to_raw(''@@@@@@@@@@@@@@@''))' | |
WHEN p_data_type = 'XMLTYPE' THEN | |
'XMLTYPE(''<NULL/>'')' | |
ELSE | |
'''@@@@@@@@@@@@@@@''' | |
END; | |
RETURN v_return; | |
END util_get_attribute_surrogate; | |
----------------------------------------------------------------------------- | |
-- util_get_attribute_compare is a private helper function to deliver the | |
-- described (take a look at function util_get_attribute_surrogate) compare | |
-- code for two attributes. In addition to that, the compare operation must | |
-- be dynamically, because e.g. "=" or "<>" or other operations are required. | |
----------------------------------------------------------------------------- | |
FUNCTION util_get_attribute_compare | |
( | |
p_data_type IN user_tab_cols.data_type%TYPE, | |
p_nullable IN BOOLEAN, | |
p_first_attribute IN VARCHAR2, | |
p_second_attribute IN VARCHAR2, | |
p_compare_operation IN VARCHAR2 DEFAULT '<>' | |
) RETURN VARCHAR2 IS | |
v_return VARCHAR2(1000 CHAR); | |
FUNCTION get_coalesce(p_attribute VARCHAR2) RETURN VARCHAR2 IS | |
v_return VARCHAR2(1000 CHAR); | |
BEGIN | |
v_return := CASE | |
WHEN NOT p_nullable THEN | |
p_attribute | |
ELSE | |
'COALESCE(' || p_attribute || ', ' || util_get_attribute_surrogate(p_data_type) || ')' | |
END; | |
RETURN v_return; | |
END; | |
BEGIN | |
v_return := CASE | |
WHEN p_data_type = 'XMLTYPE' THEN | |
'util_xml_compare( ' || get_coalesce(p_first_attribute) || ', ' || get_coalesce(p_second_attribute) || ') ' || | |
p_compare_operation || ' 0' | |
WHEN p_data_type IN ('BLOB', 'CLOB') THEN | |
'DBMS_LOB.compare( ' || get_coalesce(p_first_attribute) || ',' || get_coalesce(p_second_attribute) || ') ' || | |
p_compare_operation || ' 0' | |
ELSE | |
get_coalesce(p_first_attribute) || ' ' || p_compare_operation || ' ' || | |
get_coalesce(p_second_attribute) | |
END; | |
RETURN v_return; | |
END util_get_attribute_compare; | |
----------------------------------------------------------------------------- | |
-- util_get_vc2_4000_operation is a private helper function to deliver a | |
-- varchar2 representation of an attribute in dependency of its datatype. | |
----------------------------------------------------------------------------- | |
FUNCTION util_get_vc2_4000_operation | |
( | |
p_data_type IN all_tab_cols.data_type%TYPE, | |
p_attribute_name IN VARCHAR2 | |
) RETURN VARCHAR2 IS | |
v_return VARCHAR2(1000 CHAR); | |
BEGIN | |
v_return := CASE | |
WHEN p_data_type IN ('NUMBER', 'FLOAT', 'INTEGER') THEN | |
'to_char(' || p_attribute_name || ')' | |
WHEN p_data_type = 'DATE' THEN | |
'to_char(' || p_attribute_name || ',''yyyy.mm.dd hh24:mi:ss'')' | |
WHEN p_data_type LIKE 'TIMESTAMP%' THEN | |
'to_char(' || p_attribute_name || ',''yyyy.mm.dd hh24:mi:ss.ff'')' | |
WHEN p_data_type = 'BLOB' THEN | |
'''Data type "BLOB" is not supported for generic change log''' | |
WHEN p_data_type = 'XMLTYPE' THEN | |
'substr( CASE WHEN ' || p_attribute_name || ' IS NULL THEN NULL ELSE ' || p_attribute_name || | |
'.getStringVal() END,1,4000)' | |
ELSE | |
'substr(' || p_attribute_name || ',1,4000)' | |
END; | |
RETURN v_return; | |
END util_get_vc2_4000_operation; | |
----------------------------------------------------------------------------- | |
-- util_get_user_name is a private helper function to deliver the current | |
-- username. If a valid APEX session exists,then the APEX application user | |
-- is taken,otherwise the current connected operation system user. | |
----------------------------------------------------------------------------- | |
FUNCTION util_get_user_name RETURN all_users.username%TYPE IS | |
BEGIN | |
RETURN upper (coalesce( | |
sys_context('apex$session', 'app_user'), | |
sys_context('userenv', 'os_user'), | |
sys_context('userenv', 'session_user'))); | |
END util_get_user_name; | |
----------------------------------------------------------------------------- | |
-- util_get_parameter_name is a private helper function to deliver a cleaned | |
-- normalized parameter name. | |
----------------------------------------------------------------------------- | |
FUNCTION util_get_parameter_name | |
( | |
p_column_name VARCHAR2, | |
p_rpad INTEGER | |
) RETURN VARCHAR2 IS | |
v_return user_objects.object_name%TYPE; | |
BEGIN | |
v_return := regexp_replace(lower(p_column_name), '[^a-z0-9_]', NULL); | |
IF g_params.enable_parameter_prefixes THEN | |
v_return := 'p_' || substr(v_return, 1, c_ora_max_name_len - 2); | |
END IF; | |
IF p_rpad IS NOT NULL THEN | |
v_return := rpad(v_return, | |
CASE | |
WHEN g_params.enable_parameter_prefixes THEN | |
p_rpad + 2 | |
ELSE | |
p_rpad | |
END); | |
END IF; | |
RETURN v_return; | |
END util_get_parameter_name; | |
----------------------------------------------------------------------------- | |
-- util_get_column_name is a private helper function to deliver a cleaned | |
-- normalized column name. | |
----------------------------------------------------------------------------- | |
FUNCTION util_get_column_name | |
( | |
p_column_name VARCHAR2, | |
p_rpad INTEGER | |
) RETURN VARCHAR2 IS | |
v_return user_objects.object_name%TYPE; | |
BEGIN | |
v_return := regexp_replace(lower(p_column_name), '[^a-z0-9_]', NULL); | |
IF p_rpad IS NOT NULL THEN | |
v_return := rpad(v_return, | |
CASE | |
WHEN g_params.enable_parameter_prefixes THEN | |
p_rpad + 2 | |
ELSE | |
p_rpad | |
END); | |
END IF; | |
RETURN v_return; | |
END util_get_column_name; | |
----------------------------------------------------------------------------- | |
-- util_get_method_name is a private helper function to deliver a cleaned | |
-- normalized method name for the getter and setter functions/procedures. | |
----------------------------------------------------------------------------- | |
FUNCTION util_get_method_name(p_column_name VARCHAR2) RETURN VARCHAR2 IS | |
v_return user_objects.object_name%TYPE; | |
BEGIN | |
v_return := regexp_replace(lower(p_column_name), '[^a-z0-9_]', NULL); | |
v_return := CASE | |
WHEN g_params.col_prefix_in_method_names THEN | |
substr(v_return, 1, c_ora_max_name_len - 4) | |
ELSE | |
substr(v_return, length(g_status.column_prefix) + 2, c_ora_max_name_len - 4) | |
END; | |
RETURN v_return; | |
END; | |
----------------------------------------------------------------------------- | |
FUNCTION util_get_substituted_name(p_name_template VARCHAR2) RETURN VARCHAR2 IS | |
v_return all_objects.object_name%TYPE; | |
v_base_name all_objects.object_name%TYPE; | |
v_replace_string all_objects.object_name%TYPE; | |
v_position PLS_INTEGER; | |
v_length PLS_INTEGER; | |
BEGIN | |
-- Get replace string | |
v_replace_string := regexp_substr(p_name_template, '#[A-Za-z0-9_-]+#', 1, 1); | |
-- Check,if we have to do a replacement | |
IF v_replace_string IS NULL THEN | |
-- Without replacement we return simply the input | |
v_return := p_name_template; | |
ELSE | |
-- Replace possible placeholders in name template | |
v_base_name := rtrim(regexp_substr(upper(v_replace_string), '[A-Z_]+', 1, 1), '_'); | |
-- logger.log('v_base_name: ' || v_base_name); | |
-- Check,if we have a valid base name | |
IF v_base_name NOT IN ('TABLE_NAME', 'PK_COLUMN', 'COLUMN_PREFIX') THEN | |
-- Without a valid base name we return simply the input | |
v_return := p_name_template; | |
ELSE | |
-- Search for start and stop positions | |
v_position := regexp_substr(v_replace_string, '-?\d+', 1, 1); | |
v_length := regexp_substr(v_replace_string, '\d+', 1, 2); | |
-- 1. To be backward compatible we have to support things like this TABLE_NAME_26. | |
-- 2. If someone want to use the substr version he has always to provide position and length. | |
-- 3. Negative position is supported like this #TABLE_NAME_-15_15# (the second number can not be omitted like in substr,see 1.) | |
IF v_position IS NULL AND v_length IS NULL THEN | |
v_length := 200; | |
v_position := 1; | |
ELSIF v_position IS NOT NULL AND v_length IS NULL THEN | |
v_length := v_position; | |
v_position := 1; | |
END IF; | |
v_return := replace(p_name_template, | |
v_replace_string, | |
substr(CASE v_base_name | |
WHEN 'TABLE_NAME' THEN | |
g_params.table_name | |
WHEN 'PK_COLUMN' THEN | |
g_pk_columns(1).column_name | |
WHEN 'COLUMN_PREFIX' THEN | |
g_status.column_prefix | |
END, | |
v_position, | |
v_length)); | |
END IF; | |
END IF; | |
RETURN v_return; | |
END util_get_substituted_name; | |
----------------------------------------------------------------------------- | |
FUNCTION util_get_column_data_default | |
( | |
p_table_name IN VARCHAR2, | |
p_column_name IN VARCHAR2, | |
p_owner VARCHAR2 DEFAULT USER | |
) RETURN VARCHAR2 AS | |
v_return LONG; | |
CURSOR c_utc IS | |
SELECT data_default | |
FROM all_tab_columns | |
WHERE owner = p_owner | |
AND table_name = p_table_name | |
AND column_name = p_column_name; | |
BEGIN | |
OPEN c_utc; | |
FETCH c_utc | |
INTO v_return; | |
CLOSE c_utc; | |
RETURN substr(v_return, 1, 4000); | |
END; | |
-------------------------------------------------------------------------------- | |
FUNCTION util_get_cons_search_condition | |
( | |
p_constraint_name IN VARCHAR2, | |
p_owner IN VARCHAR2 DEFAULT USER | |
) RETURN VARCHAR2 AS | |
v_return LONG; | |
CURSOR c_search_condition IS | |
SELECT search_condition | |
FROM all_constraints | |
WHERE owner = p_owner | |
AND constraint_name = p_constraint_name; | |
BEGIN | |
OPEN c_search_condition; | |
FETCH c_search_condition | |
INTO v_return; | |
CLOSE c_search_condition; | |
RETURN substr(v_return, 1, 4000); | |
END; | |
----------------------------------------------------------------------------- | |
FUNCTION util_get_ora_max_name_len RETURN INTEGER IS | |
BEGIN | |
RETURN c_ora_max_name_len; | |
END; | |
----------------------------------------------------------------------------- | |
FUNCTION util_split_to_table | |
( | |
p_string IN VARCHAR2, | |
p_delimiter IN VARCHAR2 DEFAULT ',' | |
) RETURN t_tab_vc2_4k | |
PIPELINED IS | |
v_offset PLS_INTEGER := 1; | |
v_index PLS_INTEGER := instr(p_string, p_delimiter, v_offset); | |
v_delimiter_length PLS_INTEGER := length(p_delimiter); | |
v_string_length CONSTANT PLS_INTEGER := length(p_string); | |
BEGIN | |
WHILE v_index > 0 LOOP | |
PIPE ROW(TRIM(substr(p_string, v_offset, v_index - v_offset))); | |
v_offset := v_index + v_delimiter_length; | |
v_index := instr(p_string, p_delimiter, v_offset); | |
END LOOP; | |
IF v_string_length - v_offset + 1 > 0 THEN | |
PIPE ROW(TRIM(substr(p_string, v_offset, v_string_length - v_offset + 1))); | |
END IF; | |
RETURN; | |
END util_split_to_table; | |
----------------------------------------------------------------------------- | |
FUNCTION util_serialize_xml(p_xml XMLTYPE) RETURN VARCHAR2 IS | |
v_return VARCHAR2(32767); | |
BEGIN | |
SELECT xmlserialize(document p_xml no indent) INTO v_return FROM dual; | |
RETURN v_return; | |
END util_serialize_xml; | |
-------------------------------------------------------------------------------- | |
PROCEDURE util_set_debug_on IS | |
BEGIN | |
g_debug_enabled := TRUE; | |
g_debug_run := 0; | |
g_debug_step := 0; | |
g_debug.delete; | |
END; | |
-------------------------------------------------------------------------------- | |
PROCEDURE util_set_debug_off IS | |
BEGIN | |
g_debug_enabled := FALSE; | |
END; | |
PROCEDURE util_debug_start_one_run | |
( | |
p_generator_action VARCHAR2, | |
p_table_name VARCHAR2, | |
p_owner VARCHAR2 | |
) IS | |
BEGIN | |
g_debug_module := c_generator || ' v' || c_generator_version || ': ' || p_generator_action; | |
IF g_debug_enabled THEN | |
g_debug_run := g_debug_run + 1; | |
IF g_debug_run <= c_debug_max_runs THEN | |
g_debug_step := 0; | |
g_debug(g_debug_run).run := g_debug_run; | |
g_debug(g_debug_run).owner := p_owner; | |
g_debug(g_debug_run).table_name := p_table_name; | |
g_debug(g_debug_run).start_time := systimestamp; | |
END IF; | |
END IF; | |
END; | |
----------------------------------------------------------------------------- | |
PROCEDURE util_debug_stop_one_run IS | |
BEGIN | |
IF g_debug_enabled AND g_debug_run <= c_debug_max_runs THEN | |
g_debug(g_debug_run).stop_time := systimestamp; | |
END IF; | |
END; | |
----------------------------------------------------------------------------- | |
PROCEDURE util_debug_start_one_step(p_action VARCHAR2) IS | |
BEGIN | |
dbms_application_info.set_module(module_name => g_debug_module, action_name => p_action); | |
IF g_debug_enabled AND g_debug_run <= c_debug_max_runs THEN | |
g_debug_step := g_debug_step + 1; | |
g_debug(g_debug_run).details(g_debug_step).step := g_debug_step; | |
g_debug(g_debug_run).details(g_debug_step).module := g_debug_module; | |
g_debug(g_debug_run).details(g_debug_step).action := p_action; | |
g_debug(g_debug_run).details(g_debug_step).start_time := systimestamp; | |
END IF; | |
END; | |
----------------------------------------------------------------------------- | |
PROCEDURE util_debug_stop_one_step IS | |
BEGIN | |
dbms_application_info.set_module(module_name => NULL, action_name => NULL); | |
IF g_debug_enabled AND g_debug_run <= c_debug_max_runs THEN | |
g_debug(g_debug_run).details(g_debug_step).stop_time := systimestamp; | |
END IF; | |
END; | |
----------------------------------------------------------------------------- | |
FUNCTION util_view_debug_log RETURN t_tab_debug_data | |
PIPELINED IS | |
v_return t_rec_debug_data; | |
BEGIN | |
FOR i IN 1 .. g_debug.count LOOP | |
v_return.run := g_debug(i).run; | |
v_return.run_time := round(SYSDATE + ((g_debug(i).stop_time - g_debug(i).start_time) * 86400) - SYSDATE, 6); | |
v_return.owner := g_debug(i).owner; | |
v_return.table_name := g_debug(i).table_name; | |
FOR j IN 1 .. g_debug(i).details.count LOOP | |
v_return.step := g_debug(i).details(j).step; | |
v_return.elapsed := round(SYSDATE + ((g_debug(i).details(j).stop_time - g_debug(i).start_time) * 86400) - | |
SYSDATE, | |
6); | |
v_return.execution := round(SYSDATE + | |
((g_debug(i).details(j).stop_time - g_debug(i).details(j).start_time) * 86400) - | |
SYSDATE, | |
6); | |
v_return.action := g_debug(i).details(j).action; | |
v_return.start_time := g_debug(i).details(j).start_time; | |
--sysdate + (interval_difference * 86400) - sysdate | |
--https://stackoverflow.com/questions/10092032/extracting-the-total-number-of-seconds-from-an-interval-data-type | |
PIPE ROW(v_return); | |
END LOOP; | |
END LOOP; | |
END; | |
----------------------------------------------------------------------------- | |
FUNCTION util_view_columns_array RETURN t_tab_debug_columns | |
PIPELINED IS | |
v_row t_rec_columns; | |
BEGIN | |
FOR i IN 1 .. g_columns.count LOOP | |
v_row.column_name := g_columns(i).column_name; | |
v_row.data_type := g_columns(i).data_type; | |
v_row.char_length := g_columns(i).char_length; | |
v_row.data_length := g_columns(i).data_length; | |
v_row.data_precision := g_columns(i).data_precision; | |
v_row.data_scale := g_columns(i).data_scale; | |
v_row.data_default := g_columns(i).data_default; | |
v_row.data_custom_default := g_columns(i).data_custom_default; | |
v_row.custom_default_source := g_columns(i).custom_default_source; | |
v_row.identity_type := g_columns(i).identity_type; | |
v_row.default_on_null_yn := g_columns(i).default_on_null_yn; | |
v_row.is_pk_yn := g_columns(i).is_pk_yn; | |
v_row.is_uk_yn := g_columns(i).is_uk_yn; | |
v_row.is_fk_yn := g_columns(i).is_fk_yn; | |
v_row.is_nullable_yn := g_columns(i).is_nullable_yn; | |
v_row.is_excluded_yn := g_columns(i).is_excluded_yn; | |
v_row.audit_type := g_columns(i).audit_type; | |
v_row.row_version_expression := g_columns(i).row_version_expression; | |
v_row.r_owner := g_columns(i).r_owner; | |
v_row.r_table_name := g_columns(i).r_table_name; | |
v_row.r_column_name := g_columns(i).r_column_name; | |
PIPE ROW(v_row); | |
END LOOP; | |
END util_view_columns_array; | |
----------------------------------------------------------------------------- | |
FUNCTION util_view_package_state | |
RETURN t_tab_package_state pipelined IS | |
v_row t_rec_package_state; | |
BEGIN | |
v_row.package_status_key := 'generator_action'; | |
v_row.value := g_status.generator_action; | |
pipe row(v_row); | |
-- | |
v_row.package_status_key := 'api_name'; | |
v_row.value := g_params.api_name; | |
pipe row(v_row); | |
-- | |
v_row.package_status_key := 'column_prefix'; | |
v_row.value := g_status.column_prefix; | |
pipe row(v_row); | |
-- | |
v_row.package_status_key := 'pk_is_multi_column'; | |
v_row.value := util_bool_to_string(g_status.pk_is_multi_column); | |
pipe row(v_row); | |
-- | |
v_row.package_status_key := 'identity_column'; | |
v_row.value := g_status.identity_column; | |
pipe row(v_row); | |
-- | |
v_row.package_status_key := 'identity_type'; | |
v_row.value := g_status.identity_type; | |
pipe row(v_row); | |
-- | |
v_row.package_status_key := 'xmltype_column_present'; | |
v_row.value := util_bool_to_string(g_status.xmltype_column_present); | |
pipe row(v_row); | |
-- | |
v_row.package_status_key := 'number_of_data_columns'; | |
v_row.value := to_char(g_status.number_of_data_columns); | |
pipe row(v_row); | |
-- | |
v_row.package_status_key := 'number_of_pk_columns'; | |
v_row.value := to_char(g_status.number_of_pk_columns); | |
pipe row(v_row); | |
-- | |
v_row.package_status_key := 'number_of_uk_columns'; | |
v_row.value := to_char(g_status.number_of_uk_columns); | |
pipe row(v_row); | |
-- | |
v_row.package_status_key := 'number_of_fk_columns'; | |
v_row.value := to_char(g_status.number_of_fk_columns); | |
pipe row(v_row); | |
-- | |
v_row.package_status_key := 'rpad_columns'; | |
v_row.value := to_char(g_status.rpad_columns); | |
pipe row(v_row); | |
-- | |
v_row.package_status_key := 'rpad_pk_columns'; | |
v_row.value := to_char(g_status.rpad_pk_columns); | |
pipe row(v_row); | |
-- | |
v_row.package_status_key := 'rpad_uk_columns'; | |
v_row.value := to_char(g_status.rpad_uk_columns); | |
pipe row(v_row); | |
END util_view_package_state; | |
-------------------------------------------------------------------------------- | |
FUNCTION util_get_ddl | |
( | |
p_object_type VARCHAR2, | |
p_object_name VARCHAR2, | |
p_owner VARCHAR2 DEFAULT USER | |
) RETURN CLOB IS | |
v_return CLOB; | |
v_count PLS_INTEGER; | |
BEGIN | |
IF p_object_type IN ('PACKAGE', 'PACKAGE BODY', 'VIEW', 'TRIGGER') THEN | |
SELECT COUNT(*) | |
INTO v_count | |
FROM all_objects | |
WHERE owner = p_owner | |
AND object_type = p_object_type | |
AND object_name = p_object_name; | |
IF v_count = 1 THEN | |
dbms_metadata.set_transform_param(dbms_metadata.session_transform, 'SQLTERMINATOR', TRUE); | |
dbms_metadata.set_transform_param(dbms_metadata.session_transform, 'PRETTY', TRUE); | |
CASE p_object_type | |
WHEN 'PACKAGE' THEN | |
v_return := dbms_metadata.get_ddl(object_type => 'PACKAGE_SPEC', NAME => p_object_name, SCHEMA => p_owner); | |
-- v_return := ltrim(substr(v_return, 1, instr(v_return, 'CREATE OR REPLACE PACKAGE') - 1), | |
-- ' ' || chr(10)); | |
WHEN 'PACKAGE BODY' THEN | |
v_return := dbms_metadata.get_ddl(object_type => 'PACKAGE_BODY', NAME => p_object_name, SCHEMA => p_owner); | |
-- v_return := substr(v_return, instr(v_return, 'CREATE OR REPLACE PACKAGE BODY')); | |
WHEN 'VIEW' THEN | |
v_return := | |
ltrim( | |
regexp_replace( | |
regexp_replace( | |
dbms_metadata.get_ddl( | |
object_type => p_object_type, | |
NAME => p_object_name, | |
SCHEMA => p_owner), | |
'\(.*\) ', -- remove additional column list from the compiler | |
NULL, | |
1, | |
1), | |
'^ SELECT', -- remove additional whitespace from the compiler | |
'SELECT', | |
1, | |
1, | |
'im'), | |
' ' || chr(10)); | |
WHEN 'TRIGGER' THEN | |
v_return := ltrim(dbms_metadata.get_ddl(object_type => p_object_type, | |
NAME => p_object_name, | |
SCHEMA => p_owner), | |
' ' || chr(10)); | |
ELSE | |
NULL; | |
END CASE; | |
END IF; | |
ELSE | |
v_return := 'ERROR: unsupported object type "' || p_object_type || '"'; | |
END IF; | |
RETURN v_return; | |
END; | |
----------------------------------------------------------------------------- | |
FUNCTION util_get_fk_value | |
( | |
p_table_name VARCHAR2, | |
p_column_name VARCHAR2, | |
p_owner VARCHAR2 DEFAULT USER | |
) RETURN VARCHAR2 IS | |
v_cur SYS_REFCURSOR; | |
v_return VARCHAR2(4000); | |
v_column_expression VARCHAR2(4000); | |
BEGIN | |
FOR i IN (SELECT data_type | |
FROM all_tab_columns | |
WHERE owner = p_owner | |
AND table_name = p_table_name | |
AND column_name = p_column_name) LOOP | |
v_column_expression := | |
CASE | |
WHEN i.data_type LIKE '%CHAR%' THEN | |
'''''''''||substr(' || p_column_name || ',1,4000)||''''''''' | |
WHEN i.data_type IN ('NUMBER', 'INTEGER', 'FLOAT') THEN | |
'to_char(' || p_column_name || ')' | |
ELSE | |
NULL | |
END; | |
IF v_column_expression IS NOT NULL THEN | |
OPEN v_cur FOR 'SELECT ' || v_column_expression || ' FROM ' || p_table_name; | |
FETCH v_cur | |
INTO v_return; | |
CLOSE v_cur; | |
END IF; | |
END LOOP; | |
RETURN(v_return); | |
END util_get_fk_value; | |
----------------------------------------------------------------------------- | |
FUNCTION util_generate_list(p_list_name VARCHAR2) RETURN t_tab_vc2_5k IS | |
----------------------------------------------------------------------------- | |
FUNCTION get_audit_value ( | |
p_column_index INTEGER) | |
RETURN VARCHAR2 IS | |
BEGIN | |
RETURN | |
CASE | |
WHEN g_columns(p_column_index).audit_type in ('CREATED', 'UPDATED') THEN | |
CASE | |
WHEN g_columns(p_column_index).data_type LIKE '%DATE%' THEN | |
'sysdate' | |
WHEN g_columns(p_column_index).data_type LIKE '%TIMESTAMP%' THEN | |
'systimestamp' | |
ELSE | |
NULL | |
END | |
ELSE | |
g_params.audit_user_expression | |
END; | |
END get_audit_value; | |
----------------------------------------------------------------------------- | |
FUNCTION get_column_comment ( | |
p_column_index INTEGER) | |
RETURN VARCHAR2 is | |
BEGIN | |
RETURN | |
CASE WHEN g_columns(p_column_index).is_pk_yn = 'Y' THEN ' /*PK*/' END || | |
CASE WHEN g_columns(p_column_index).is_uk_yn = 'Y' THEN ' /*UK*/' END || | |
CASE WHEN g_columns(p_column_index).is_fk_yn = 'Y' THEN ' /*FK*/' END || | |
CASE WHEN g_template_options.crud_mode = 'CREATE' AND g_columns(p_column_index).identity_type IS NOT NULL THEN | |
' /*GENERATED ' || g_columns(p_column_index).identity_type || | |
CASE WHEN g_columns(p_column_index).default_on_null_yn = 'Y' THEN | |
' ON NULL' | |
END || | |
' AS IDENTITY*/' | |
END; | |
END get_column_comment; | |
----------------------------------------------------------------------------- | |
FUNCTION check_identity_visibility ( | |
p_column_index INTEGER) | |
RETURN BOOLEAN IS | |
BEGIN | |
RETURN | |
CASE | |
WHEN g_columns(p_column_index).identity_type IS NULL | |
or g_template_options.crud_mode IS NULL | |
or g_template_options.crud_mode = 'CREATE' AND g_columns(p_column_index).identity_type = 'BY DEFAULT' | |
THEN true | |
ELSE false | |
END; | |
END check_identity_visibility; | |
----------------------------------------------------------------------------- | |
FUNCTION check_audit_visibility_create ( | |
p_column_index INTEGER) | |
RETURN BOOLEAN IS | |
BEGIN | |
RETURN | |
CASE | |
WHEN g_columns(p_column_index).audit_type IS NULL | |
or g_columns(p_column_index).audit_type LIKE 'CREATED%' | |
or g_columns(p_column_index).audit_type LIKE 'UPDATED%' AND g_columns(p_column_index).is_nullable_yn = 'N' | |
THEN true | |
ELSE false | |
END; | |
END check_audit_visibility_create; | |
----------------------------------------------------------------------------- | |
FUNCTION check_audit_visibility_update ( | |
p_column_index INTEGER) | |
RETURN BOOLEAN IS | |
BEGIN | |
RETURN | |
CASE | |
WHEN g_columns(p_column_index).audit_type IS NULL | |
OR g_columns(p_column_index).audit_type LIKE 'UPDATED%' | |
THEN true | |
ELSE false | |
END; | |
END check_audit_visibility_update; | |
----------------------------------------------------------------------------- | |
PROCEDURE trim_list(p_list in out nocopy t_tab_vc2_5k) is | |
BEGIN | |
IF p_list.count > 0 THEN | |
p_list(p_list.first) := ltrim(p_list(p_list.first)); | |
IF substr(p_list(p_list.first), 1, 4) = 'AND ' THEN | |
p_list(p_list.first) := substr(p_list(p_list.first), 5); | |
END IF; | |
IF substr(p_list(p_list.first), 1, 2) = ', ' THEN | |
p_list(p_list.first) := substr(p_list(p_list.first), 3); | |
END IF; | |
p_list(p_list.last) := rtrim(p_list(p_list.last), c_lf || c_list_delimiter); | |
END IF; | |
END trim_list; | |
----------------------------------------------------------------------------- | |
FUNCTION list_insert_columns RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
FOR i IN g_columns.first .. g_columns.last LOOP | |
IF g_columns(i).is_excluded_yn = 'N' | |
AND check_identity_visibility(i) | |
AND check_audit_visibility_create(i) | |
THEN | |
v_result(v_result.count + 1) := | |
' ' || util_double_quote(g_columns(i).column_name) || | |
get_column_comment(i) || c_list_delimiter; | |
END IF; | |
END LOOP; | |
trim_list(v_result); | |
RETURN v_result; | |
END list_insert_columns; | |
----------------------------------------------------------------------------- | |
-- Columns as flat list for insert - without p_column_exclude_list: | |
-- {% LIST_INSERT_PARAMS %} | |
-- Example: | |
-- p_col2, | |
-- p_col3, | |
-- p_col4, | |
-- ... | |
----------------------------------------------------------------------------- | |
FUNCTION list_insert_params RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
FOR i IN g_columns.first .. g_columns.last LOOP | |
IF g_columns(i).is_excluded_yn = 'N' | |
AND check_identity_visibility(i) | |
AND check_audit_visibility_create(i) | |
THEN | |
v_result(v_result.count + 1) := | |
' ' || | |
CASE | |
WHEN g_columns(i).is_pk_yn = 'Y' AND NOT g_status.pk_is_multi_column AND | |
g_params.sequence_name IS NOT NULL THEN | |
'COALESCE( ' || util_get_parameter_name(g_columns(i).column_name, NULL) | |
|| ', ' || util_double_quote(g_params.sequence_name) || '.nextval )' | |
WHEN g_columns(i).audit_type IS NOT NULL THEN | |
get_audit_value(i) | |
WHEN g_columns(i).row_version_expression IS NOT NULL THEN | |
g_columns(i).row_version_expression | |
ELSE | |
util_get_parameter_name(g_columns(i).column_name, NULL) | |
END | |
|| c_list_delimiter; | |
END IF; | |
END LOOP; | |
trim_list(v_result); | |
RETURN v_result; | |
END list_insert_params; | |
----------------------------------------------------------------------------- | |
-- Columns as flat list for insert - without p_column_exclude_list: | |
-- {% LIST_INSERT_BULK_PARAMS %} | |
-- Example: | |
-- p_col2, | |
-- p_col3, | |
-- p_col4, | |
-- ... | |
----------------------------------------------------------------------------- | |
FUNCTION list_insert_bulk_params RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
FOR i IN g_columns.first .. g_columns.last LOOP | |
IF g_columns(i).is_excluded_yn = 'N' | |
AND check_identity_visibility(i) | |
AND check_audit_visibility_create(i) | |
THEN | |
v_result(v_result.count + 1) := | |
' ' || | |
CASE | |
WHEN g_columns(i).is_pk_yn = 'Y' AND NOT g_status.pk_is_multi_column AND g_params.sequence_name IS NOT NULL THEN | |
'coalesce( p_rows_tab(i).' || util_double_quote(g_columns(i).column_name) || ', ' | |
|| util_double_quote(g_params.sequence_name) || '.nextval )' | |
WHEN g_columns(i).audit_type IS NOT NULL THEN | |
get_audit_value(i) | |
WHEN g_columns(i).row_version_expression IS NOT NULL THEN | |
g_columns(i).row_version_expression | |
ELSE | |
'p_rows_tab(i).' || util_double_quote(g_columns(i).column_name) | |
END || c_list_delimiter; | |
END IF; | |
END LOOP; | |
trim_list(v_result); | |
RETURN v_result; | |
END list_insert_bulk_params; | |
----------------------------------------------------------------------------- | |
-- Columns as flat list - with p_column_exclude_list: | |
-- {% LIST_COLUMNS_W_PK_FULL %} | |
-- Example: | |
-- col1, | |
-- col2, | |
-- col3, | |
-- ... | |
----------------------------------------------------------------------------- | |
FUNCTION list_columns_w_pk_full RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
FOR i IN g_columns.first .. g_columns.last LOOP | |
v_result(v_result.count + 1) := | |
' ' || util_double_quote(g_columns(i).column_name) || | |
get_column_comment(i) || c_list_delimiter; | |
END LOOP; | |
trim_list(v_result); | |
RETURN v_result; | |
END list_columns_w_pk_full; | |
----------------------------------------------------------------------------- | |
-- Columns as parameter definition for create_row,update_row with PK: | |
-- {% LIST_PARAMS_W_PK %} | |
-- Example: | |
-- p_col1 IN table.col1%TYPE, | |
-- p_col2 IN table.col2%TYPE, | |
-- p_col3 IN table.col3%TYPE, | |
-- ... | |
----------------------------------------------------------------------------- | |
FUNCTION list_params_w_pk RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
FOR i IN g_columns.first .. g_columns.last LOOP | |
IF g_columns(i).is_excluded_yn = 'N' | |
AND g_columns(i).audit_type IS NULL | |
AND g_columns(i).row_version_expression IS NULL | |
AND check_identity_visibility(i) | |
THEN | |
v_result(v_result.count + 1) := | |
CASE | |
WHEN g_template_options.padding IS NOT NULL THEN | |
rpad(' ', g_template_options.padding) | |
ELSE | |
' ' | |
END || | |
util_get_parameter_name(g_columns(i).column_name, g_status.rpad_columns) || | |
' IN ' || util_double_quote(g_params.table_name) || '.' || | |
CASE | |
WHEN g_params.enable_column_defaults AND g_template_options.use_column_defaults THEN | |
rpad( util_double_quote(g_columns(i).column_name) || '%TYPE', g_status.rpad_columns + 6) | |
ELSE | |
util_double_quote(g_columns(i).column_name) || '%TYPE' | |
END || | |
CASE | |
WHEN g_columns(i).is_pk_yn = 'Y' | |
AND NOT g_status.pk_is_multi_column | |
AND (g_columns(i).data_default IS NULL OR g_columns(i).identity_type IS NOT NULL) THEN | |
' DEFAULT NULL' | |
WHEN g_params.enable_column_defaults | |
AND g_template_options.use_column_defaults THEN | |
CASE | |
WHEN g_columns(i).data_default IS NOT NULL THEN | |
' DEFAULT ' || g_columns(i).data_default | |
WHEN g_columns(i).is_nullable_yn = 'Y' THEN | |
' DEFAULT NULL' | |
ELSE | |
' ' | |
END | |
END || get_column_comment(i) || c_list_delimiter; | |
END IF; | |
END LOOP; | |
trim_list(v_result); | |
RETURN v_result; | |
END list_params_w_pk; | |
----------------------------------------------------------------------------- | |
-- A parameter list with column defaults: | |
-- {% LIST_PARAMS_W_PK_CUST_DEFAULTS %} | |
-- Example: | |
-- p_employee_id IN employees.employee_id%TYPE DEFAULT get_a_row()."EMPLOYEE_ID", | |
-- p_first_name IN employees.first_name%TYPE DEFAULT get_a_row()."FIRST_NAME", | |
-- p_last_name IN employees.last_name%TYPE DEFAULT get_a_row()."LAST_NAME", | |
-- ... | |
----------------------------------------------------------------------------- | |
FUNCTION list_params_w_pk_cust_defaults RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
FOR i IN g_columns.first .. g_columns.last LOOP | |
IF g_columns(i).is_excluded_yn = 'N' | |
AND g_columns(i).audit_type IS NULL | |
AND g_columns(i).row_version_expression IS NULL | |
AND check_identity_visibility(i) | |
THEN | |
v_result(v_result.count + 1) := | |
' ' || | |
util_get_parameter_name(g_columns(i).column_name, g_status.rpad_columns) || | |
' IN ' || util_double_quote(g_params.table_name) || '.' || | |
rpad(util_double_quote(g_columns(i).column_name) || '%TYPE', g_status.rpad_columns + 7) || | |
' DEFAULT get_a_row().' || util_double_quote(g_columns(i).column_name) || | |
get_column_comment(i) || c_list_delimiter; | |
END IF; | |
END LOOP; | |
trim_list(v_result); | |
RETURN v_result; | |
END list_params_w_pk_cust_defaults; | |
----------------------------------------------------------------------------- | |
-- Columns as parameter IN OUT definition for read_row with PK: | |
-- {% LIST_PARAMS_W_PK_IO %} | |
-- Example: | |
-- p_col1 IN table.col1%TYPE, | |
-- p_col2 IN OUT NOCOPY table.col2%TYPE, | |
-- p_col3 IN OUT NOCOPY table.col3%TYPE, | |
-- ... | |
----------------------------------------------------------------------------- | |
FUNCTION list_params_w_pk_io RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
FOR i IN g_columns.first .. g_columns.last LOOP | |
v_result(v_result.count + 1) := ' ' || | |
util_get_parameter_name(g_columns(i).column_name, g_status.rpad_columns) || | |
CASE | |
WHEN g_columns(i).is_pk_yn = 'Y' THEN | |
' IN ' | |
ELSE | |
' OUT NOCOPY ' | |
END || util_double_quote(g_params.table_name) || '.' || | |
util_double_quote(g_columns(i).column_name) || '%TYPE' || | |
get_column_comment(i) || c_list_delimiter; | |
END LOOP; | |
trim_list(v_result); | |
RETURN v_result; | |
END list_params_w_pk_io; | |
----------------------------------------------------------------------------- | |
-- Map :new values to parameter for IOIUD-Trigger with PK: | |
-- {% LIST_MAP_PAR_EQ_NEWCOL_W_PK %} | |
-- Example: | |
-- p_col1 => :new.col1, | |
-- p_col2 => :new.col2, | |
-- p_col3 => :new.col3, | |
-- ... | |
----------------------------------------------------------------------------- | |
FUNCTION list_map_par_eq_newcol_w_pk RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
FOR i IN g_columns.first .. g_columns.last LOOP | |
IF g_columns(i).is_excluded_yn = 'N' | |
AND g_columns(i).audit_type IS NULL | |
AND g_columns(i).row_version_expression IS NULL | |
AND check_identity_visibility(i) | |
THEN | |
v_result(v_result.count + 1) := | |
' ' || | |
util_get_parameter_name(g_columns(i).column_name, g_status.rpad_columns) || | |
' => :new.' || util_double_quote(g_columns(i).column_name) || | |
get_column_comment(i) || c_list_delimiter; | |
END IF; | |
END LOOP; | |
trim_list(v_result); | |
RETURN v_result; | |
END list_map_par_eq_newcol_w_pk; | |
----------------------------------------------------------------------------- | |
-- Map parameter to parameter as pass-through parameter with PK: | |
-- {% LIST_MAP_PAR_EQ_PARAM_W_PK %} | |
-- Example: | |
-- p_col1 => p_col1, | |
-- p_col2 => p_col2, | |
-- p_col3 => p_col3, | |
-- ... | |
----------------------------------------------------------------------------- | |
FUNCTION list_map_par_eq_param_w_pk RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
FOR i IN g_columns.first .. g_columns.last LOOP | |
IF g_columns(i).is_excluded_yn = 'N' | |
AND g_columns(i).audit_type IS NULL | |
AND g_columns(i).row_version_expression IS NULL | |
AND check_identity_visibility(i) | |
THEN | |
v_result(v_result.count + 1) := | |
CASE WHEN g_template_options.padding IS NOT NULL | |
THEN rpad(' ', g_template_options.padding) | |
ELSE ' ' | |
END || | |
util_get_parameter_name(g_columns(i).column_name, g_status.rpad_columns) || | |
' => ' || util_get_parameter_name(g_columns(i).column_name, NULL) || | |
get_column_comment(i) || c_list_delimiter; | |
END IF; | |
END LOOP; | |
trim_list(v_result); | |
RETURN v_result; | |
END list_map_par_eq_param_w_pk; | |
----------------------------------------------------------------------------- | |
-- map rowtype columns to parameter for rowtype handling with PK: | |
-- {% LIST_MAP_PAR_EQ_ROWTYPCOL_W_PK %} | |
-- Example: | |
-- p_col1 => p_row.col1, | |
-- p_col2 => p_row.col2, | |
-- p_col3 => p_row.col3, | |
-- ... | |
----------------------------------------------------------------------------- | |
FUNCTION list_map_par_eq_rowtypcol_w_pk RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
FOR i IN g_columns.first .. g_columns.last LOOP | |
IF g_columns(i).is_excluded_yn = 'N' | |
AND g_columns(i).audit_type IS NULL | |
AND g_columns(i).row_version_expression IS NULL | |
AND check_identity_visibility(i) | |
THEN | |
v_result(v_result.count + 1) := | |
' ' || | |
util_get_parameter_name(g_columns(i).column_name, g_status.rpad_columns) || | |
' => p_row.' || util_double_quote(g_columns(i).column_name) || | |
get_column_comment(i) || c_list_delimiter; | |
END IF; | |
END LOOP; | |
trim_list(v_result); | |
RETURN v_result; | |
END list_map_par_eq_rowtypcol_w_pk; | |
----------------------------------------------------------------------------- | |
-- A column list for updating a row without PK: | |
-- {% LIST_SET_COL_EQ_PARAM_WO_PK %} | |
-- Example: | |
-- test_number = p_test_number, | |
-- test_varchar2 = p_test_varchar2, | |
-- ... | |
----------------------------------------------------------------------------- | |
FUNCTION list_set_col_eq_param_wo_pk RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
FOR i IN g_columns.first .. g_columns.last LOOP | |
IF g_columns(i).is_excluded_yn = 'N' | |
AND g_columns(i).is_pk_yn = 'N' | |
AND check_audit_visibility_update(i) | |
THEN | |
v_result(v_result.count + 1) := | |
' ' || | |
rpad(util_double_quote(g_columns(i).column_name), g_status.rpad_columns + 2) || | |
' = ' || | |
CASE | |
WHEN g_columns(i).audit_type IS NOT NULL THEN | |
get_audit_value(i) | |
WHEN g_columns(i).row_version_expression IS NOT NULL THEN | |
g_columns(i).row_version_expression | |
ELSE | |
util_get_parameter_name(g_columns(i).column_name, NULL) | |
END || | |
get_column_comment(i) || c_list_delimiter; | |
END IF; | |
END LOOP; | |
trim_list(v_result); | |
RETURN v_result; | |
END list_set_col_eq_param_wo_pk; | |
----------------------------------------------------------------------------- | |
-- A column list for updating a row without PK in bulk mode: | |
-- {% LIST_SET_COL_EQ_PAR_BULK_WO_PK %} | |
-- Example: | |
-- "FIRST_NAME" = p_rows_tab(i)."FIRST_NAME", | |
-- "LAST_NAME" = p_rows_tab(i)."LAST_NAME", | |
-- ... | |
----------------------------------------------------------------------------- | |
FUNCTION list_set_col_eq_par_bulk_wo_pk RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
FOR i IN g_columns.first .. g_columns.last LOOP | |
IF g_columns(i).is_excluded_yn = 'N' | |
AND g_columns(i).is_pk_yn = 'N' | |
AND check_audit_visibility_update(i) | |
THEN | |
v_result(v_result.count + 1) := | |
' ' || | |
rpad(util_double_quote(g_columns(i).column_name), g_status.rpad_columns + 2) || | |
' = ' || | |
CASE | |
WHEN g_columns(i).audit_type IS NOT NULL THEN | |
get_audit_value(i) | |
WHEN g_columns(i).row_version_expression IS NOT NULL THEN | |
g_columns(i).row_version_expression | |
ELSE | |
'p_rows_tab(i).' || util_double_quote(g_columns(i).column_name) | |
END || | |
get_column_comment(i) || c_list_delimiter; | |
END IF; | |
END LOOP; | |
trim_list(v_result); | |
RETURN v_result; | |
END list_set_col_eq_par_bulk_wo_pk; | |
----------------------------------------------------------------------------- | |
-- A column list without pk for setting parameter to row columns: | |
-- {% LIST_SET_PAR_EQ_ROWTYCOL_WO_PK %} | |
-- Example: | |
-- p_test_number := v_row.test_number; | |
-- p_test_varchar2 := v_row.test_varchar2; | |
-- ... | |
----------------------------------------------------------------------------- | |
FUNCTION list_set_par_eq_rowtycol_wo_pk RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
FOR i IN g_columns.first .. g_columns.last LOOP | |
IF g_columns(i).is_excluded_yn = 'N' | |
AND g_columns(i).audit_type IS NULL | |
AND g_columns(i).row_version_expression IS NULL | |
AND g_columns(i).is_pk_yn = 'N' | |
THEN | |
v_result(v_result.count + 1) := | |
' ' || | |
util_get_parameter_name(g_columns(i).column_name, g_status.rpad_columns) || | |
' := v_row.' || | |
util_double_quote(g_columns(i).column_name) || '; ' || c_lf; | |
END IF; | |
END LOOP; | |
trim_list(v_result); | |
RETURN v_result; | |
END list_set_par_eq_rowtycol_wo_pk; | |
----------------------------------------------------------------------------- | |
-- Primary key parameter definition for create_row: | |
-- {% LIST_PARAMS_PK %} | |
-- Example: | |
-- p_col1 IN table.col1%TYPE, | |
-- p_col2 IN table.col2%TYPE, | |
-- p_col3 IN table.col3%TYPE, | |
-- ... | |
----------------------------------------------------------------------------- | |
FUNCTION list_pk_params RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
FOR i IN g_pk_columns.first .. g_pk_columns.last LOOP | |
v_result(v_result.count + 1) := | |
' ' || | |
util_get_parameter_name(g_pk_columns(i).column_name, g_status.rpad_columns) || | |
' IN ' || | |
util_double_quote(g_params.table_name) || '.' || | |
util_double_quote(g_pk_columns(i).column_name) || '%TYPE /*PK*/' || | |
c_list_delimiter; | |
END LOOP; | |
trim_list(v_result); | |
RETURN v_result; | |
END list_pk_params; | |
----------------------------------------------------------------------------- | |
-- Primary key column definition for create_row: | |
-- {% LIST_PARAMS_PK %} | |
-- Example: | |
-- col1 table.col1%TYPE, | |
-- col2 table.col2%TYPE, | |
-- col3 table.col3%TYPE, | |
-- ... | |
----------------------------------------------------------------------------- | |
FUNCTION list_pk_columns RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
FOR i IN g_pk_columns.first .. g_pk_columns.last LOOP | |
v_result(v_result.count + 1) := | |
' ' || | |
util_double_quote(g_pk_columns(i).column_name) || ' ' || | |
util_double_quote(g_params.table_name) || '.' || | |
util_double_quote(g_pk_columns(i).column_name) || '%TYPE /*PK*/' || | |
c_list_delimiter; | |
END LOOP; | |
trim_list(v_result); | |
RETURN v_result; | |
END list_pk_columns; | |
----------------------------------------------------------------------------- | |
-- Primary key column definition for create_row: | |
-- {% LIST_PARAMS_PK %} | |
-- Example: | |
-- col1, | |
-- col2, | |
-- col3, | |
-- ... | |
----------------------------------------------------------------------------- | |
FUNCTION list_pk_names RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
FOR i IN g_pk_columns.first .. g_pk_columns.last LOOP | |
v_result(v_result.count + 1) := | |
' ' || util_double_quote(g_pk_columns(i).column_name) || | |
' /*PK*/' || c_list_delimiter; | |
END LOOP; | |
trim_list(v_result); | |
RETURN v_result; | |
END list_pk_names; | |
----------------------------------------------------------------------------- | |
-- Primary key columns for return clause: | |
-- {% LIST_PK_RETURN_COLUMNS %} | |
-- Example: | |
-- v_return.col1, | |
-- v_return.col2, | |
-- v_return.col3, | |
-- ... | |
----------------------------------------------------------------------------- | |
FUNCTION list_pk_return_columns RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
FOR i IN g_pk_columns.first .. g_pk_columns.last LOOP | |
v_result(v_result.count + 1) := | |
' v_return.' || | |
util_double_quote(g_pk_columns(i).column_name) || c_list_delimiter; | |
END LOOP; | |
trim_list(v_result); | |
RETURN v_result; | |
END list_pk_return_columns; | |
----------------------------------------------------------------------------- | |
-- Primary key column definition for create_rows: | |
-- {% LIST_PK_RETURN_COLUMNS_BULK %} | |
-- Example: | |
-- v_return(i).col1 := v_pk_tab.col1; | |
-- v_return(i).col2 := v_pk_tab.col2; | |
-- v_return(i).col3 := v_pk_tab.col3; | |
-- ... | |
----------------------------------------------------------------------------- | |
FUNCTION list_pk_return_columns_bulk RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
FOR i IN g_pk_columns.first .. g_pk_columns.last LOOP | |
v_result(v_result.count + 1) := | |
' v_return(i).' || | |
util_double_quote(g_pk_columns(i).column_name) || | |
' := v_pk_tab(i).' || | |
util_double_quote(g_pk_columns(i).column_name) || | |
'; /*PK*/' || c_lf; | |
END LOOP; | |
trim_list(v_result); | |
RETURN v_result; | |
END list_pk_return_columns_bulk; | |
----------------------------------------------------------------------------- | |
-- Primary key columns parameter compare for get_pk_by_unique_cols functions: | |
-- {% LIST_PK_COLUMNS_WHERE_CLAUSE %} | |
-- Example: | |
-- COALESCE( "COL1",'@@@@@@@@@@@@@@@' ) = COALESCE( p_col1,'@@@@@@@@@@@@@@@' ) | |
-- AND COALESCE( "COL2",'@@@@@@@@@@@@@@@' ) = COALESCE( p_col2,'@@@@@@@@@@@@@@@' ) | |
-- ... | |
----------------------------------------------------------------------------- | |
FUNCTION list_pk_columns_where_clause RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
FOR i IN g_pk_columns.first .. g_pk_columns.last LOOP | |
v_result(v_result.count + 1) := | |
' AND ' || | |
util_get_attribute_compare( | |
p_data_type => g_pk_columns(i).data_type, | |
p_nullable => util_string_to_bool(g_columns(g_columns_reverse_index(g_pk_columns(i).column_name)).is_nullable_yn), | |
p_first_attribute => util_double_quote(g_pk_columns(i).column_name), | |
p_second_attribute => util_get_parameter_name(g_pk_columns(i).column_name, NULL), | |
p_compare_operation => '=') || c_lf; | |
END LOOP; | |
trim_list(v_result); | |
RETURN v_result; | |
END list_pk_columns_where_clause; | |
----------------------------------------------------------------------------- | |
-- Primary key columns parameter compare for get_pk_by_unique_cols functions: | |
-- {% LIST_PK_COLUMN_BULK_COMPARE %} | |
-- Example: | |
-- COALESCE( "COL1",'@@@@@@@@@@@@@@@' ) = COALESCE( p_col1,'@@@@@@@@@@@@@@@' ) | |
-- AND COALESCE( "COL2",'@@@@@@@@@@@@@@@' ) = COALESCE( p_col2,'@@@@@@@@@@@@@@@' ) | |
-- ... | |
----------------------------------------------------------------------------- | |
FUNCTION list_pk_column_bulk_compare RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
FOR i IN g_pk_columns.first .. g_pk_columns.last LOOP | |
v_result(v_result.count + 1) := | |
' AND ' || | |
util_get_attribute_compare( | |
p_data_type => g_pk_columns(i).data_type, | |
p_nullable => util_string_to_bool(g_columns(g_columns_reverse_index(g_pk_columns(i).column_name)).is_nullable_yn), | |
p_first_attribute => util_double_quote(g_pk_columns(i).column_name), | |
p_second_attribute => 'p_rows_tab(i).' || util_double_quote(g_pk_columns(i).column_name), | |
p_compare_operation => '=') || c_lf; | |
END LOOP; | |
trim_list(v_result); | |
RETURN v_result; | |
END list_pk_column_bulk_compare; | |
----------------------------------------------------------------------------- | |
-- Primary key columns list for read_row parameters | |
-- {% LIST_PK_COLUMN_FETCH %} | |
-- Example: | |
-- p_au_id => v_pk_rec."AU_ID" | |
-- ... | |
----------------------------------------------------------------------------- | |
FUNCTION list_pk_column_fetch RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
FOR i IN g_pk_columns.first .. g_pk_columns.last LOOP | |
v_result(v_result.count + 1) := | |
', ' || | |
util_get_attribute_compare( | |
p_data_type => g_pk_columns(i).data_type, | |
p_nullable => util_string_to_bool(g_columns(g_columns_reverse_index(g_pk_columns(i).column_name)).is_nullable_yn), | |
p_first_attribute => util_get_parameter_name(g_pk_columns(i).column_name, NULL), | |
p_second_attribute => 'v_pk_rec.' || util_double_quote(g_pk_columns(i).column_name), | |
p_compare_operation => '=>'); | |
END LOOP; | |
trim_list(v_result); | |
RETURN v_result; | |
END list_pk_column_fetch; | |
----------------------------------------------------------------------------- | |
-- Primary key columns parameter compare for get_pk_by_unique_cols functions: | |
-- {% LIST_PK_COLUMN_BULK_COMPARE %} | |
-- Example: | |
-- COALESCE( "COL1",'@@@@@@@@@@@@@@@' ) = COALESCE( p_col1,'@@@@@@@@@@@@@@@' ) | |
-- AND COALESCE( "COL2",'@@@@@@@@@@@@@@@' ) = COALESCE( p_col2,'@@@@@@@@@@@@@@@' ) | |
-- ... | |
----------------------------------------------------------------------------- | |
FUNCTION list_pk_column_bulk_fetch RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
FOR i IN g_pk_columns.first .. g_pk_columns.last LOOP | |
v_result(v_result.count + 1) := | |
' AND ' || | |
util_get_attribute_compare( | |
p_data_type => g_pk_columns(i).data_type, | |
p_nullable => util_string_to_bool(g_columns(g_columns_reverse_index(g_pk_columns(i).column_name)).is_nullable_yn), | |
p_first_attribute => 'data_table.' || util_double_quote(g_pk_columns(i).column_name), | |
p_second_attribute => 'pk_collection.' || util_double_quote(g_pk_columns(i).column_name), | |
p_compare_operation => '=') || c_lf; | |
END LOOP; | |
trim_list(v_result); | |
RETURN v_result; | |
END list_pk_column_bulk_fetch; | |
----------------------------------------------------------------------------- | |
-- Primary key columns as "parameter => parameter" mapping for read_row functions: | |
-- {% LIST_PK_MAP_PARAM_EQ_PARAM %} | |
-- Example: | |
-- p_col1 => p_col1, | |
-- p_col2 => p_col2, | |
-- ... | |
----------------------------------------------------------------------------- | |
FUNCTION list_pk_map_param_eq_param RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
FOR i IN g_pk_columns.first .. g_pk_columns.last LOOP | |
v_result(v_result.count + 1) := | |
' ' || | |
util_get_parameter_name( | |
g_pk_columns(i).column_name, | |
CASE WHEN g_status.pk_is_multi_column | |
THEN g_status.rpad_pk_columns | |
ELSE NULL | |
END) || | |
' => ' || | |
util_get_parameter_name(g_pk_columns(i).column_name, NULL) || | |
c_list_delimiter; | |
END LOOP; | |
trim_list(v_result); | |
RETURN v_result; | |
END list_pk_map_param_eq_param; | |
----------------------------------------------------------------------------- | |
-- Primary key columns as "parameter => parameter" mapping for read_row functions: | |
-- {% LIST_PK_MAP_PARAM_EQ_PARAM %} | |
-- Example: | |
-- p_col1 => p_col1, | |
-- p_col2 => p_col2, | |
-- ... | |
----------------------------------------------------------------------------- | |
FUNCTION list_pk_map_param_eq_return RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
FOR i IN g_pk_columns.first .. g_pk_columns.last LOOP | |
v_result(v_result.count + 1) := | |
' ' || | |
util_get_parameter_name( | |
g_pk_columns(i).column_name, | |
CASE WHEN g_status.pk_is_multi_column | |
THEN g_status.rpad_pk_columns | |
ELSE NULL | |
END) || | |
' => v_return.' || | |
util_double_quote(g_pk_columns(i).column_name) || | |
c_list_delimiter; | |
END LOOP; | |
trim_list(v_result); | |
RETURN v_result; | |
END list_pk_map_param_eq_return; | |
----------------------------------------------------------------------------- | |
-- Primary key columns as "parameter => :old.column" mapping for DML view trigger: | |
-- {% LIST_PK_MAP_PARAM_EQ_OLDCOL %} | |
-- Example: | |
-- p_col1 => :old.col1, | |
-- p_col2 => :old.col2, | |
-- ... | |
----------------------------------------------------------------------------- | |
FUNCTION list_pk_map_param_eq_oldcol RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
FOR i IN g_pk_columns.first .. g_pk_columns.last LOOP | |
v_result(v_result.count + 1) := | |
' ' || | |
util_get_parameter_name( | |
g_pk_columns(i).column_name, | |
CASE WHEN g_status.pk_is_multi_column | |
THEN g_status.rpad_pk_columns | |
ELSE NULL | |
END) || | |
' => ' || ':old.' || | |
util_double_quote(g_pk_columns(i).column_name) || | |
c_list_delimiter; | |
END LOOP; | |
trim_list(v_result); | |
RETURN v_result; | |
END list_pk_map_param_eq_oldcol; | |
----------------------------------------------------------------------------- | |
-- Unique columns as parameter definition for get_pk_by_unique_cols/read_row functions: | |
-- {% LIST_UK_PARAMS %} | |
-- Example: | |
-- p_col1 IN table.col1%TYPE, | |
-- p_col2 IN table.col2%TYPE, | |
-- p_col3 IN table.col3%TYPE, | |
-- ... | |
----------------------------------------------------------------------------- | |
FUNCTION list_uk_params RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
FOR i IN g_uk_columns.first .. g_uk_columns.last LOOP | |
IF g_uk_columns(i).constraint_name = g_iterator.current_uk_constraint THEN | |
v_result(v_result.count + 1) := | |
' ' || | |
util_get_parameter_name(g_uk_columns(i).column_name, g_status.rpad_columns) || | |
' IN ' || util_double_quote(g_params.table_name) || '.' || | |
util_double_quote(g_uk_columns(i).column_name) || | |
'%TYPE /*UK*/' || c_list_delimiter; | |
END IF; | |
END LOOP; | |
trim_list(v_result); | |
RETURN v_result; | |
END list_uk_params; | |
----------------------------------------------------------------------------- | |
-- Unique columns parameter compare for get_pk_by_unique_cols functions: | |
-- {% LIST_UK_COLUMN_COMPARE %} | |
-- Example: | |
-- COALESCE( "COL1",'@@@@@@@@@@@@@@@' ) = COALESCE( p_COL1,'@@@@@@@@@@@@@@@' ) | |
-- AND COALESCE( "COL2",'@@@@@@@@@@@@@@@' ) = COALESCE( p_COL2,'@@@@@@@@@@@@@@@' ) | |
-- ... | |
----------------------------------------------------------------------------- | |
FUNCTION list_uk_column_compare RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
FOR i IN g_uk_columns.first .. g_uk_columns.last LOOP | |
IF g_uk_columns(i).constraint_name = g_iterator.current_uk_constraint THEN | |
v_result(v_result.count + 1) := | |
' AND ' || | |
util_get_attribute_compare( | |
p_data_type => g_uk_columns(i).data_type, | |
p_nullable => util_string_to_bool(g_columns(g_columns_reverse_index(g_uk_columns(i).column_name)).is_nullable_yn), | |
p_first_attribute => util_double_quote(g_uk_columns(i).column_name), | |
p_second_attribute => util_get_parameter_name(g_uk_columns(i).column_name, NULL), | |
p_compare_operation => '=') || c_lf; | |
END IF; | |
END LOOP; | |
trim_list(v_result); | |
RETURN v_result; | |
END list_uk_column_compare; | |
----------------------------------------------------------------------------- | |
-- Unique key columns as "parameter => parameter" mapping for read_row functions: | |
-- {% LIST_UK_MAP_PARAM_EQ_PARAM %} | |
-- Example: | |
-- p_col1 => p_col1, | |
-- p_col2 => p_col2, | |
-- ... | |
----------------------------------------------------------------------------- | |
FUNCTION list_uk_map_param_eq_param RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
FOR i IN g_uk_columns.first .. g_uk_columns.last LOOP | |
IF g_uk_columns(i).constraint_name = g_iterator.current_uk_constraint THEN | |
v_result(v_result.count + 1) := | |
' ' || | |
util_get_parameter_name( | |
g_uk_columns(i).column_name, | |
CASE WHEN g_status.pk_is_multi_column | |
THEN g_status.rpad_uk_columns | |
ELSE NULL | |
END) || | |
' => ' || | |
util_get_parameter_name(g_uk_columns(i).column_name, NULL) || | |
c_list_delimiter; | |
END IF; | |
END LOOP; | |
trim_list(v_result); | |
RETURN v_result; | |
END list_uk_map_param_eq_param; | |
----------------------------------------------------------------------------- | |
-- A list of column defaults - used in the function get_a_row: | |
-- {% LIST_ROWCOLS_W_CUST_DEFAULTS %} | |
-- Example: | |
-- v_row.employee_id := employees_seq.nextval; --generated from SEQ | |
-- v_row.first_name := 'Rowan'; | |
-- v_row.last_name := 'Atkinson'; | |
-- ... | |
----------------------------------------------------------------------------- | |
FUNCTION list_rowcols_w_cust_defaults RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
FOR i IN g_columns.first .. g_columns.last LOOP | |
IF g_columns(i).data_custom_default IS NOT NULL THEN | |
v_result(v_result.count + 1) := | |
' ' || 'v_row.' || | |
rpad(util_double_quote(g_columns(i).column_name), g_status.rpad_columns + 2) || | |
' := ' || nvl(g_columns(i).data_custom_default, g_columns(i).data_default) || | |
get_column_comment(i) || ';' || c_lf; | |
END IF; | |
END LOOP; | |
trim_list(v_result); | |
RETURN v_result; | |
END list_rowcols_w_cust_defaults; | |
----------------------------------------------------------------------------- | |
-- A list of custom column defaults - used to save the defaults in the spec: | |
-- {% LIST_SPEC_CUSTOM_DEFAULTS %} | |
-- Example: | |
-- v_row.employee_id := employees_seq.nextval; --generated from SEQ | |
-- v_row.first_name := 'Rowan'; | |
-- v_row.last_name := 'Atkinson'; | |
-- ... | |
----------------------------------------------------------------------------- | |
FUNCTION list_spec_custom_defaults RETURN t_tab_vc2_5k IS | |
v_result t_tab_vc2_5k; | |
BEGIN | |
v_result(v_result.count + 1) := '<custom_defaults>' || c_lf; | |
FOR i IN g_columns.first .. g_columns.last LOOP | |
IF g_columns(i).data_custom_default IS NOT NULL THEN | |
v_result(v_result.count + 1) := | |
' <column source="' || | |
rpad(g_columns(i).custom_default_source || '"', 8) || | |
' name="' || g_columns(i).column_name || '"><![CDATA[' || | |
g_columns(i).data_custom_default || ']]></column>' || c_lf; | |
END IF; | |
END LOOP; | |
v_result(v_result.count + 1) := ' </custom_defaults>' || c_lf; | |
IF v_result.count > 2 THEN | |
v_result(v_result.last) := rtrim(v_result(v_result.last), c_lf); | |
ELSE | |
-- no data available, only the empty <custom_defaults> element | |
v_result.delete; | |
END IF; | |
RETURN v_result; | |
END list_spec_custom_defaults; | |
----------------------------------------------------------------------------- | |
BEGIN | |
CASE p_list_name | |
WHEN 'LIST_INSERT_COLUMNS' THEN | |
RETURN list_insert_columns; | |
WHEN 'LIST_COLUMNS_W_PK_FULL' THEN | |
RETURN list_columns_w_pk_full; | |
WHEN 'LIST_ROWCOLS_W_CUST_DEFAULTS' THEN | |
RETURN list_rowcols_w_cust_defaults; | |
WHEN 'LIST_MAP_PAR_EQ_NEWCOL_W_PK' THEN | |
RETURN list_map_par_eq_newcol_w_pk; | |
WHEN 'LIST_MAP_PAR_EQ_PARAM_W_PK' THEN | |
RETURN list_map_par_eq_param_w_pk; | |
WHEN 'LIST_MAP_PAR_EQ_ROWTYPCOL_W_PK' THEN | |
RETURN list_map_par_eq_rowtypcol_w_pk; | |
WHEN 'LIST_PARAMS_W_PK' THEN | |
RETURN list_params_w_pk; | |
WHEN 'LIST_PARAMS_W_PK_IO' THEN | |
RETURN list_params_w_pk_io; | |
WHEN 'LIST_PARAMS_W_PK_CUST_DEFAULTS' THEN | |
RETURN list_params_w_pk_cust_defaults; | |
WHEN 'LIST_INSERT_PARAMS' THEN | |
RETURN list_insert_params; | |
WHEN 'LIST_INSERT_BULK_PARAMS' THEN | |
RETURN list_insert_bulk_params; | |
WHEN 'LIST_SET_COL_EQ_PARAM_WO_PK' THEN | |
RETURN list_set_col_eq_param_wo_pk; | |
WHEN 'LIST_SET_COL_EQ_PAR_BULK_WO_PK' THEN | |
RETURN list_set_col_eq_par_bulk_wo_pk; | |
WHEN 'LIST_SET_PAR_EQ_ROWTYCOL_WO_PK' THEN | |
RETURN list_set_par_eq_rowtycol_wo_pk; | |
WHEN 'LIST_PK_PARAMS' THEN | |
RETURN list_pk_params; | |
WHEN 'LIST_PK_COLUMNS' THEN | |
RETURN list_pk_columns; | |
WHEN 'LIST_PK_NAMES' THEN | |
RETURN list_pk_names; | |
WHEN 'LIST_PK_RETURN_COLUMNS' THEN | |
RETURN list_pk_return_columns; | |
WHEN 'LIST_PK_RETURN_COLUMNS_BULK' THEN | |
RETURN list_pk_return_columns_bulk; | |
WHEN 'LIST_PK_COLUMNS_WHERE_CLAUSE' THEN | |
RETURN list_pk_columns_where_clause; | |
WHEN 'LIST_PK_COLUMN_FETCH' THEN | |
RETURN list_pk_column_fetch; | |
WHEN 'LIST_PK_COLUMN_BULK_COMPARE' THEN | |
RETURN list_pk_column_bulk_compare; | |
WHEN 'LIST_PK_COLUMN_BULK_FETCH' THEN | |
RETURN list_pk_column_bulk_fetch; | |
WHEN 'LIST_PK_MAP_PARAM_EQ_PARAM' THEN | |
RETURN list_pk_map_param_eq_param; | |
WHEN 'LIST_PK_MAP_PARAM_EQ_RETURN' THEN | |
RETURN list_pk_map_param_eq_return; | |
WHEN 'LIST_PK_MAP_PARAM_EQ_OLDCOL' THEN | |
RETURN list_pk_map_param_eq_oldcol; | |
WHEN 'LIST_UK_PARAMS' THEN | |
RETURN list_uk_params; | |
WHEN 'LIST_UK_COLUMN_COMPARE' THEN | |
RETURN list_uk_column_compare; | |
WHEN 'LIST_UK_MAP_PARAM_EQ_PARAM' THEN | |
RETURN list_uk_map_param_eq_param; | |
WHEN 'LIST_SPEC_CUSTOM_DEFAULTS' THEN | |
RETURN list_spec_custom_defaults; | |
ELSE | |
raise_application_error(c_generator_error_number, 'FIXME: Bug - list ' || p_list_name || ' not defined'); | |
END CASE; | |
END; | |
----------------------------------------------------------------------------- | |
-- util_clob_append is a private helper procedure to append a varchar2 value | |
-- to an existing clob. The idea is to increase performance by avoiding the | |
-- slow DBMS_LOB.append call. Only for the final append or if the varchar | |
-- cache is fullfilled,this call is done. | |
----------------------------------------------------------------------------- | |
PROCEDURE util_clob_append | |
( | |
p_clob IN OUT NOCOPY CLOB, | |
p_clob_varchar_cache IN OUT NOCOPY VARCHAR2, | |
p_varchar_to_append IN VARCHAR2, | |
p_final_call IN BOOLEAN DEFAULT FALSE | |
) IS | |
BEGIN | |
p_clob_varchar_cache := p_clob_varchar_cache || p_varchar_to_append; | |
IF p_final_call THEN | |
IF p_clob IS NULL THEN | |
p_clob := p_clob_varchar_cache; | |
ELSE | |
dbms_lob.append(p_clob, p_clob_varchar_cache); | |
END IF; | |
-- clear cache on final call | |
p_clob_varchar_cache := NULL; | |
END IF; | |
EXCEPTION | |
WHEN value_error THEN | |
IF p_clob IS NULL THEN | |
p_clob := p_clob_varchar_cache; | |
ELSE | |
dbms_lob.append(p_clob, p_clob_varchar_cache); | |
END IF; | |
p_clob_varchar_cache := p_varchar_to_append; | |
IF p_final_call THEN | |
dbms_lob.append(p_clob, p_clob_varchar_cache); | |
-- clear cache on final call | |
p_clob_varchar_cache := NULL; | |
END IF; | |
END util_clob_append; | |
----------------------------------------------------------------------------- | |
-- util_template_replace is a private helper procedure: | |
-- * processes static or dynamic replacements | |
-- * slices the templates in blocks of code at the replacement positions | |
-- * appends the slices to the resulting clobs for spec, body, view and trigger | |
-- * uses a varchar2 cache to speed up the clob processing | |
----------------------------------------------------------------------------- | |
PROCEDURE util_template_replace( | |
p_scope IN VARCHAR2 DEFAULT NULL, | |
p_add_blank_line_before in boolean default true) IS | |
v_current_pos PLS_INTEGER := 1; | |
v_match_pos_static PLS_INTEGER := 0; | |
v_match_pos_dynamic PLS_INTEGER := 0; | |
v_match_len PLS_INTEGER := 0; | |
v_match VARCHAR2(256 CHAR); | |
v_tpl_len PLS_INTEGER; | |
v_dynamic_result t_tab_vc2_5k; | |
----------------------------------------------------------------------------- | |
PROCEDURE get_match_pos IS | |
-- finds the first position of a substitution string like | |
-- {{ TABLE_NAME }} or {% dynamic code %} | |
BEGIN | |
v_match_pos_static := instr(g_code_blocks.template, '{{', v_current_pos); | |
v_match_pos_dynamic := instr(g_code_blocks.template, '{%', v_current_pos); | |
END get_match_pos; | |
----------------------------------------------------------------------------- | |
PROCEDURE code_append(p_code_snippet VARCHAR2) IS | |
BEGIN | |
IF p_scope = 'API SPEC' THEN | |
util_clob_append(g_code_blocks.api_spec, g_code_blocks.api_spec_varchar_cache, p_code_snippet); | |
ELSIF p_scope = 'API BODY' THEN | |
util_clob_append(g_code_blocks.api_body, g_code_blocks.api_body_varchar_cache, p_code_snippet); | |
ELSIF p_scope = 'VIEW' THEN | |
util_clob_append(g_code_blocks.dml_view, g_code_blocks.dml_view_varchar_cache, p_code_snippet); | |
ELSIF p_scope = 'TRIGGER' THEN | |
util_clob_append(g_code_blocks.dml_view_trigger, g_code_blocks.dml_view_trigger_varchar_cache, p_code_snippet); | |
ELSIF p_scope = '1:1 VIEW' THEN | |
util_clob_append(g_code_blocks.one_to_one_view, g_code_blocks.one_to_one_view_varchar_cache, p_code_snippet); | |
END IF; | |
END code_append; | |
----------------------------------------------------------------------------- | |
PROCEDURE process_static_match IS | |
BEGIN | |
v_match_len := instr(g_code_blocks.template, '}}', v_match_pos_static) - v_match_pos_static - 2; | |
IF v_match_len <= 0 THEN | |
raise_application_error(c_generator_error_number, 'FIXME: Bug - static substitution not properly closed'); | |
END IF; | |
v_match := upper(TRIM(substr(g_code_blocks.template, v_match_pos_static + 2, v_match_len))); | |
-- (1) process text before the match | |
code_append(substr(g_code_blocks.template, v_current_pos, v_match_pos_static - v_current_pos)); | |
-- (2) process the match | |
CASE v_match | |
WHEN 'GENERATOR' THEN | |
code_append(c_generator); | |
WHEN 'GENERATOR_VERSION' THEN | |
code_append(c_generator_version); | |
WHEN 'GENERATOR_ACTION' THEN | |
code_append(g_status.generator_action); | |
WHEN 'GENERATOR_ERROR_NUMBER' THEN | |
code_append(c_generator_error_number); | |
WHEN 'GENERATED_AT' THEN | |
code_append(to_char(SYSDATE, 'yyyy-mm-dd hh24:mi:ss')); | |
WHEN 'GENERATED_BY' THEN | |
code_append(util_get_user_name); | |
WHEN 'SPEC_OPTIONS_MIN_LINE' THEN | |
code_append(c_spec_options_min_line); | |
WHEN 'SPEC_OPTIONS_MAX_LINE' THEN | |
code_append(c_spec_options_max_line); | |
WHEN 'OWNER' THEN | |
code_append(util_double_quote(g_params.owner)); | |
WHEN 'OWNER_XML' THEN | |
code_append(g_params.owner); | |
WHEN 'TABLE_NAME' THEN | |
code_append(util_double_quote(g_params.table_name)); | |
WHEN 'TABLE_NAME_XML' THEN | |
code_append(g_params.table_name); | |
WHEN 'SEQUENCE_NAME' THEN | |
code_append(util_double_quote(g_params.sequence_name)); | |
WHEN 'SEQUENCE_NAME_XML' THEN | |
code_append(g_params.sequence_name); | |
WHEN 'API_NAME' THEN | |
code_append(util_double_quote(g_params.api_name)); | |
WHEN 'API_NAME_XML' THEN | |
code_append(g_params.api_name); | |
WHEN 'DML_VIEW_NAME' THEN | |
code_append(util_double_quote(substr(g_params.table_name, 1, c_ora_max_name_len - 6)||'_DML_V')); | |
WHEN 'TRIGGER_NAME' THEN | |
code_append(util_double_quote(substr(g_params.table_name, 1, c_ora_max_name_len - 6)||'_IOIUD')); | |
WHEN 'ONE_TO_ONE_VIEW_NAME' THEN | |
code_append(util_double_quote(substr(g_params.table_name, 1, c_ora_max_name_len - 2)||'_V')); | |
WHEN 'IDENTITY_TYPE' THEN | |
IF g_status.identity_type IS NOT NULL THEN | |
code_append(' with column '||g_status.identity_column||' generated '||g_status.identity_type||' as identity'); | |
END IF; | |
WHEN 'COLUMN_PREFIX' THEN | |
code_append(g_status.column_prefix); | |
WHEN 'PK_COLUMN' THEN | |
code_append(util_double_quote(g_pk_columns(1).column_name)); | |
WHEN 'PARAMETER_PK_FIRST_COLUMN' THEN | |
code_append(CASE | |
WHEN NOT g_status.pk_is_multi_column THEN | |
util_get_parameter_name(g_pk_columns(1).column_name, NULL) | |
ELSE | |
NULL | |
END); | |
WHEN 'COL_PREFIX_IN_METHOD_NAMES' THEN | |
code_append(util_bool_to_string(g_params.col_prefix_in_method_names)); | |
WHEN 'ENABLE_INSERTION_OF_ROWS' THEN | |
code_append(util_bool_to_string(g_params.enable_insertion_of_rows)); | |
WHEN 'ENABLE_COLUMN_DEFAULTS' THEN | |
code_append(util_bool_to_string(g_params.enable_column_defaults)); | |
WHEN 'ENABLE_CUSTOM_DEFAULTS' THEN | |
code_append(util_bool_to_string(g_params.enable_custom_defaults)); | |
WHEN 'ENABLE_UPDATE_OF_ROWS' THEN | |
code_append(util_bool_to_string(g_params.enable_update_of_rows)); | |
WHEN 'ENABLE_DELETION_OF_ROWS' THEN | |
code_append(util_bool_to_string(g_params.enable_deletion_of_rows)); | |
WHEN 'ENABLE_DML_VIEW' THEN | |
code_append(util_bool_to_string(g_params.enable_dml_view)); | |
WHEN 'ENABLE_ONE_TO_ONE_VIEW' THEN | |
code_append(util_bool_to_string(g_params.enable_one_to_one_view)); | |
WHEN 'ENABLE_GETTER_AND_SETTER' THEN | |
code_append(util_bool_to_string(g_params.enable_getter_and_setter)); | |
WHEN 'ENABLE_PROC_WITH_OUT_PARAMS' THEN | |
code_append(util_bool_to_string(g_params.enable_proc_with_out_params)); | |
WHEN 'ENABLE_PARAMETER_PREFIXES' THEN | |
code_append(util_bool_to_string(g_params.enable_parameter_prefixes)); | |
WHEN 'RETURN_ROW_INSTEAD_OF_PK' THEN | |
code_append(util_bool_to_string(g_params.return_row_instead_of_pk)); | |
WHEN 'DOUBLE_QUOTE_NAMES' THEN | |
code_append(util_bool_to_string(g_params.double_quote_names)); | |
WHEN 'DEFAULT_BULK_LIMIT' THEN | |
code_append(to_char(g_params.default_bulk_limit)); | |
WHEN 'CUSTOM_DEFAULTS' THEN | |
code_append(CASE | |
WHEN g_params.custom_default_values IS NOT NULL THEN | |
-- We set only a placeholder to signal that column defaults are given. | |
-- Column defaults itself could be very large XML and are saved at | |
-- the end of the package spec. | |
c_custom_defaults_present_msg | |
ELSE | |
NULL | |
END); | |
WHEN 'EXCLUDE_COLUMN_LIST' THEN | |
code_append(g_params.exclude_column_list); | |
WHEN 'AUDIT_COLUMN_MAPPINGS' THEN | |
code_append(g_params.audit_column_mappings); | |
WHEN 'AUDIT_USER_EXPRESSION' THEN | |
code_append(g_params.audit_user_expression); | |
WHEN 'ROW_VERSION_COLUMN_MAPPING' THEN | |
code_append(g_params.row_version_column_mapping); | |
WHEN 'RETURN_TYPE' THEN | |
code_append(util_double_quote(g_params.table_name) || CASE | |
WHEN g_params.return_row_instead_of_pk OR g_status.pk_is_multi_column THEN | |
'%ROWTYPE' | |
ELSE | |
'.' || util_double_quote(g_pk_columns(1).column_name) || '%TYPE' | |
END); | |
WHEN 'RETURN_TYPE_PK_SINGLE_COLUMN' THEN | |
code_append('v_return' || CASE | |
WHEN g_params.return_row_instead_of_pk OR g_status.pk_is_multi_column THEN | |
'.' || util_double_quote(g_pk_columns(1).column_name) | |
ELSE | |
NULL | |
END); | |
WHEN 'RETURN_TYPE_READ_ROW' THEN | |
code_append(CASE | |
WHEN NOT g_params.return_row_instead_of_pk AND NOT g_status.pk_is_multi_column THEN | |
'.' || util_double_quote(g_pk_columns(1).column_name) | |
ELSE | |
NULL | |
END); | |
WHEN 'ROWTYPE_PARAM' THEN | |
code_append(rpad('p_row', g_status.rpad_columns + 2) || ' IN ' || util_double_quote(g_params.table_name) || '%ROWTYPE'); | |
WHEN 'BULK_LIMIT_PARAM' THEN | |
code_append(rpad('p_bulk_limit', g_status.rpad_columns + 2) || ' IN PLS_INTEGER'); | |
WHEN 'TABTYPE_PARAM' THEN | |
code_append(rpad('p_rows_tab', g_status.rpad_columns + 2) || ' IN t_rows_tab'); | |
WHEN 'REFCURSOR_PARAM' THEN | |
code_append(rpad('p_ref_cursor', g_status.rpad_columns + 2) || ' IN t_strong_ref_cursor'); | |
WHEN 'I_COLUMN_NAME' THEN | |
code_append(g_iterator.column_name); | |
WHEN 'I_METHOD_NAME' THEN | |
code_append(g_iterator.method_name); | |
WHEN 'I_PARAMETER_NAME' THEN | |
code_append(g_iterator.parameter_name); | |
WHEN 'I_OLD_VALUE' THEN | |
code_append(g_iterator.old_value); | |
WHEN 'I_NEW_VALUE' THEN | |
code_append(g_iterator.new_value); | |
WHEN 'COLUMN_DEFAULTS_SERIALIZED' THEN | |
code_append(g_params.custom_defaults_serialized); | |
ELSE | |
raise_application_error(c_generator_error_number, | |
'FIXME: Bug - static substitution ' || v_match || ' not defined'); | |
END CASE; | |
v_current_pos := v_match_pos_static + v_match_len + 4; | |
END process_static_match; | |
----------------------------------------------------------------------------- | |
PROCEDURE process_dynamic_match IS | |
BEGIN | |
v_match_len := instr(g_code_blocks.template, '%}', v_match_pos_dynamic) - v_match_pos_dynamic - 2; | |
IF v_match_len <= 0 THEN | |
raise_application_error(c_generator_error_number, 'FIXME: Bug - dynamic substitution not properly closed'); | |
END IF; | |
v_match := upper(TRIM(substr(g_code_blocks.template, v_match_pos_dynamic + 2, v_match_len))); | |
g_template_options.use_column_defaults := | |
nvl( | |
util_string_to_bool(regexp_substr( | |
srcstr => v_match, | |
pattern => 'USE_COLUMN_DEFAULTS=([A-Z]+)', | |
position => 1, | |
occurrence => 1, | |
modifier => 'i', | |
subexpression => 1)), | |
FALSE); | |
g_template_options.crud_mode := | |
regexp_substr( | |
srcstr => v_match, | |
pattern => 'CRUD_MODE=([A-Z]+)', | |
position => 1, | |
occurrence => 1, | |
modifier => 'i', | |
subexpression => 1); | |
g_template_options.padding := to_number(regexp_substr( | |
srcstr => v_match, | |
pattern => 'PADDING=([0-9]+)', | |
position => 1, | |
occurrence => 1, | |
modifier => 'i', | |
subexpression => 1)); | |
v_match := regexp_substr( | |
srcstr => v_match, | |
pattern => '^ *([A-Z_0-9]+)', | |
position => 1, | |
occurrence => 1, | |
modifier => 'i', | |
subexpression => 1); | |
-- (1) process text before the match | |
code_append(substr(g_code_blocks.template, v_current_pos, v_match_pos_dynamic - v_current_pos)); | |
-- (2) process the match | |
v_dynamic_result.delete; | |
IF v_match LIKE 'LIST%' THEN | |
v_dynamic_result := util_generate_list(v_match); | |
ELSE | |
raise_application_error(c_generator_error_number, | |
'FIXME: Bug - dynamic substitution ' || v_match || ' not defined'); | |
END IF; | |
IF v_dynamic_result.count > 0 THEN | |
FOR i IN v_dynamic_result.first .. v_dynamic_result.last LOOP | |
code_append(v_dynamic_result(i)); | |
END LOOP; | |
END IF; | |
v_current_pos := v_match_pos_dynamic + v_match_len + 4; | |
END process_dynamic_match; | |
----------------------------------------------------------------------------- | |
BEGIN | |
-- add a blank line before each template block | |
code_append(c_lf); | |
-- plus one is needed to correct difference between length and position | |
v_tpl_len := length(g_code_blocks.template) + 1; | |
get_match_pos; | |
WHILE v_current_pos < v_tpl_len LOOP | |
get_match_pos; | |
IF v_match_pos_static > 0 OR v_match_pos_dynamic > 0 THEN | |
IF v_match_pos_static > 0 AND (v_match_pos_dynamic = 0 OR v_match_pos_static < v_match_pos_dynamic) THEN | |
process_static_match; | |
ELSE | |
process_dynamic_match; | |
END IF; | |
ELSE | |
-- (3) process the rest of the text | |
code_append(substr(g_code_blocks.template, v_current_pos)); | |
v_current_pos := v_tpl_len; | |
END IF; | |
END LOOP; | |
END util_template_replace; | |
----------------------------------------------------------------------------- | |
PROCEDURE main_init | |
( | |
p_generator_action IN VARCHAR2, | |
p_table_name IN VARCHAR2, | |
p_owner IN VARCHAR2, | |
p_enable_insertion_of_rows IN BOOLEAN, | |
p_enable_column_defaults IN BOOLEAN, | |
p_enable_update_of_rows IN BOOLEAN, | |
p_enable_deletion_of_rows IN BOOLEAN, | |
p_enable_parameter_prefixes IN BOOLEAN, | |
p_enable_proc_with_out_params IN BOOLEAN, | |
p_enable_getter_and_setter IN BOOLEAN, | |
p_col_prefix_in_method_names IN BOOLEAN, | |
p_return_row_instead_of_pk IN BOOLEAN, | |
p_double_quote_names IN BOOLEAN, | |
p_default_bulk_limit IN INTEGER, | |
p_enable_dml_view IN BOOLEAN, | |
p_enable_one_to_one_view IN BOOLEAN, | |
p_api_name IN VARCHAR2, | |
p_sequence_name IN VARCHAR2, | |
p_exclude_column_list IN VARCHAR2, | |
p_audit_column_mappings IN VARCHAR2, | |
p_audit_user_expression IN VARCHAR2, | |
p_row_version_column_mapping IN VARCHAR2, | |
p_enable_custom_defaults IN BOOLEAN, | |
p_custom_default_values IN XMLTYPE | |
) IS | |
----------------------------------------------------------------------------- | |
PROCEDURE init_reset_globals IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'init_reset_globals'); | |
-- global records | |
g_params := NULL; | |
g_iterator := NULL; | |
g_code_blocks := NULL; | |
g_status := NULL; | |
-- global collections | |
g_columns.delete; | |
g_columns_reverse_index.delete; | |
g_uk_constraints.delete; | |
g_fk_constraints.delete; | |
g_pk_columns.delete; | |
g_uk_columns.delete; | |
g_fk_columns.delete; | |
util_debug_stop_one_step; | |
END init_reset_globals; | |
----------------------------------------------------------------------------- | |
PROCEDURE init_process_parameters IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'init_process_parameters'); | |
g_params.enable_insertion_of_rows := p_enable_insertion_of_rows; | |
g_params.enable_column_defaults := p_enable_column_defaults; | |
g_params.enable_update_of_rows := p_enable_update_of_rows; | |
g_params.enable_deletion_of_rows := p_enable_deletion_of_rows; | |
g_params.enable_parameter_prefixes := p_enable_parameter_prefixes; | |
g_params.enable_proc_with_out_params := p_enable_proc_with_out_params; | |
g_params.enable_getter_and_setter := p_enable_getter_and_setter; | |
g_params.col_prefix_in_method_names := p_col_prefix_in_method_names; | |
g_params.return_row_instead_of_pk := p_return_row_instead_of_pk; | |
g_params.double_quote_names := p_double_quote_names; | |
g_params.default_bulk_limit := p_default_bulk_limit; | |
g_params.enable_dml_view := p_enable_dml_view; | |
g_params.enable_one_to_one_view := p_enable_one_to_one_view; | |
g_params.api_name := util_get_substituted_name(nvl(p_api_name,'#TABLE_NAME_1_' || to_char(c_ora_max_name_len - 4) || '#_API')); | |
g_params.sequence_name := CASE WHEN p_sequence_name IS NOT NULL THEN util_get_substituted_name(p_sequence_name) ELSE NULL END; | |
g_params.exclude_column_list := p_exclude_column_list; | |
g_params.audit_column_mappings := p_audit_column_mappings; | |
g_params.audit_user_expression := p_audit_user_expression; | |
g_params.row_version_column_mapping := p_row_version_column_mapping; | |
g_params.enable_custom_defaults := p_enable_custom_defaults; | |
g_params.custom_default_values := p_custom_default_values; | |
IF g_params.custom_default_values IS NOT NULL THEN | |
g_params.custom_defaults_serialized := util_serialize_xml(g_params.custom_default_values); | |
END IF; | |
-- check for empty XML element | |
IF g_params.custom_defaults_serialized = '<defaults/>' THEN | |
g_params.custom_default_values := NULL; | |
g_params.custom_defaults_serialized := NULL; | |
END IF; | |
util_debug_stop_one_step; | |
END init_process_parameters; | |
----------------------------------------------------------------------------- | |
PROCEDURE init_check_if_table_exists IS | |
v_object_name all_objects.object_name%TYPE; | |
CURSOR v_cur IS | |
SELECT table_name | |
FROM all_tables | |
WHERE owner = g_params.owner | |
AND table_name = g_params.table_name; | |
BEGIN | |
util_debug_start_one_step(p_action => 'init_check_if_table_exists'); | |
OPEN v_cur; | |
FETCH v_cur | |
INTO v_object_name; | |
CLOSE v_cur; | |
IF (v_object_name IS NULL) THEN | |
raise_application_error(c_generator_error_number, 'Table "' || g_params.table_name || '" does not exist.'); | |
END IF; | |
util_debug_stop_one_step; | |
END init_check_if_table_exists; | |
----------------------------------------------------------------------------- | |
PROCEDURE init_check_if_api_name_exists IS | |
v_object_type all_objects.object_type%TYPE; | |
CURSOR v_cur IS | |
SELECT object_type | |
FROM all_objects | |
WHERE owner = g_params.owner | |
AND object_name = g_params.api_name | |
AND object_type NOT IN ('PACKAGE', 'PACKAGE BODY'); | |
BEGIN | |
util_debug_start_one_step(p_action => 'init_check_if_api_name_exists'); | |
OPEN v_cur; | |
FETCH v_cur | |
INTO v_object_type; | |
CLOSE v_cur; | |
IF (v_object_type IS NOT NULL) THEN | |
raise_application_error(c_generator_error_number, | |
'API name "' || g_params.api_name || '" does already exist as an object type "' || | |
v_object_type || '". Please provide a different API name.'); | |
END IF; | |
util_debug_stop_one_step; | |
END init_check_if_api_name_exists; | |
----------------------------------------------------------------------------- | |
PROCEDURE init_check_if_sequence_exists IS | |
v_object_name all_objects.object_name%TYPE; | |
CURSOR v_cur IS | |
SELECT sequence_name | |
FROM all_sequences | |
WHERE sequence_owner = g_params.owner | |
AND sequence_name = g_params.sequence_name; | |
BEGIN | |
util_debug_start_one_step(p_action => 'init_check_if_sequence_exists'); | |
OPEN v_cur; | |
FETCH v_cur | |
INTO v_object_name; | |
CLOSE v_cur; | |
IF (v_object_name IS NULL) THEN | |
raise_application_error(c_generator_error_number, | |
'Sequence ' || g_params.sequence_name || | |
' does not exist. Please provide correct sequence name or create missing sequence.'); | |
END IF; | |
util_debug_stop_one_step; | |
END init_check_if_sequence_exists; | |
----------------------------------------------------------------------------- | |
PROCEDURE init_create_temporary_lobs IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'init_create_temporary_lobs'); | |
dbms_lob.createtemporary(lob_loc => g_code_blocks.api_spec, cache => true); | |
dbms_lob.createtemporary(lob_loc => g_code_blocks.api_body, cache => true); | |
dbms_lob.createtemporary(lob_loc => g_code_blocks.dml_view, cache => true); | |
dbms_lob.createtemporary(lob_loc => g_code_blocks.dml_view_trigger, cache => true); | |
dbms_lob.createtemporary(lob_loc => g_code_blocks.one_to_one_view, cache => true); | |
util_debug_stop_one_step; | |
END init_create_temporary_lobs; | |
----------------------------------------------------------------------------- | |
PROCEDURE init_fetch_columns IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'init_fetch_columns'); | |
OPEN g_cur_columns; | |
FETCH g_cur_columns BULK COLLECT | |
INTO g_columns; | |
CLOSE g_cur_columns; | |
util_debug_stop_one_step; | |
EXCEPTION | |
WHEN OTHERS THEN | |
CLOSE g_cur_columns; | |
RAISE; | |
END init_fetch_columns; | |
----------------------------------------------------------------------------- | |
PROCEDURE init_fetch_constraints IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'init_fetch_constraints'); | |
FOR i IN (SELECT constraint_name, constraint_type | |
FROM all_constraints | |
WHERE owner = g_params.owner | |
AND table_name = g_params.table_name | |
AND constraint_type IN ('U', 'R') | |
AND status = 'ENABLED') LOOP | |
CASE i.constraint_type | |
WHEN 'U' THEN | |
g_uk_constraints(g_uk_constraints.count + 1).constraint_name := i.constraint_name; | |
WHEN 'R' THEN | |
g_fk_constraints(g_fk_constraints.count + 1).constraint_name := i.constraint_name; | |
END CASE; | |
END LOOP; | |
util_debug_stop_one_step; | |
END init_fetch_constraints; | |
----------------------------------------------------------------------------- | |
/* constraint columns | |
constraint_name | |
column_name | |
column_name_length | |
data_type */ | |
----------------------------------------------------------------------------- | |
PROCEDURE init_fetch_constraint_columns IS | |
v_idx PLS_INTEGER; | |
BEGIN | |
util_debug_start_one_step(p_action => 'init_fetch_constraint_columns'); | |
FOR i IN (WITH ac AS | |
(SELECT owner, constraint_name, constraint_type, r_owner, r_constraint_name | |
FROM all_constraints | |
WHERE owner = g_params.owner | |
AND table_name = g_params.table_name | |
AND constraint_type IN ('P', 'U', 'R') | |
AND status = 'ENABLED'), | |
acc AS | |
(SELECT acc.owner, | |
acc.constraint_name, | |
ac.constraint_type, | |
acc.table_name, | |
acc.column_name, | |
length(acc.column_name) AS column_name_length, | |
acc.position, | |
ac.r_owner, | |
ac.r_constraint_name | |
FROM ac | |
JOIN all_cons_columns acc ON ac.owner = acc.owner | |
AND ac.constraint_name = acc.constraint_name), | |
acc_r AS | |
(SELECT acc_r.owner AS r_owner, | |
acc_r.constraint_name AS r_constraint_name, | |
acc_r.table_name AS r_table_name, | |
acc_r.column_name AS r_column_name, | |
acc_r.position AS r_position | |
FROM ac | |
JOIN all_cons_columns acc_r ON ac.r_owner = acc_r.owner | |
AND ac.r_constraint_name = acc_r.constraint_name) | |
SELECT acc.owner, | |
acc.constraint_name, | |
acc.constraint_type, | |
acc.table_name, | |
acc.column_name, | |
acc.column_name_length, | |
atc.data_type, | |
acc.position, | |
acc_r.r_owner, | |
acc_r.r_constraint_name, | |
acc_r.r_table_name, | |
acc_r.r_column_name, | |
acc_r.r_position | |
FROM acc | |
JOIN all_tab_columns atc ON acc.owner = atc.owner | |
AND acc.table_name = atc.table_name | |
AND acc.column_name = atc.column_name | |
LEFT JOIN acc_r ON acc.r_owner = acc_r.r_owner | |
AND acc.r_constraint_name = acc_r.r_constraint_name | |
AND acc.position = acc_r.r_position | |
ORDER BY acc.constraint_name, acc.position) LOOP | |
CASE i.constraint_type | |
WHEN 'P' THEN | |
v_idx := g_pk_columns.count + 1; | |
g_pk_columns(v_idx).constraint_name := i.constraint_name; | |
g_pk_columns(v_idx).position := i.position; | |
g_pk_columns(v_idx).column_name := i.column_name; | |
g_pk_columns(v_idx).column_name_length := i.column_name_length; | |
g_pk_columns(v_idx).data_type := i.data_type; | |
WHEN 'U' THEN | |
v_idx := g_uk_columns.count + 1; | |
g_uk_columns(v_idx).constraint_name := i.constraint_name; | |
g_uk_columns(v_idx).position := i.position; | |
g_uk_columns(v_idx).column_name := i.column_name; | |
g_uk_columns(v_idx).column_name_length := i.column_name_length; | |
g_uk_columns(v_idx).data_type := i.data_type; | |
WHEN 'R' THEN | |
v_idx := g_fk_columns.count + 1; | |
g_fk_columns(v_idx).constraint_name := i.constraint_name; | |
g_fk_columns(v_idx).position := i.position; | |
g_fk_columns(v_idx).column_name := i.column_name; | |
g_fk_columns(v_idx).column_name_length := i.column_name_length; | |
g_fk_columns(v_idx).data_type := i.data_type; | |
g_fk_columns(v_idx).r_owner := i.r_owner; | |
g_fk_columns(v_idx).r_table_name := i.r_table_name; | |
g_fk_columns(v_idx).r_column_name := i.r_column_name; | |
END CASE; | |
END LOOP; | |
util_debug_stop_one_step; | |
END init_fetch_constraint_columns; | |
----------------------------------------------------------------------------- | |
PROCEDURE init_process_columns IS | |
v_column_prefix VARCHAR2(c_ora_max_name_len); | |
type v_varchar_tab is | |
table of VARCHAR2(c_ora_max_name_len) | |
index by VARCHAR2(c_ora_max_name_len); | |
v_column_prefix_tab v_varchar_tab; | |
BEGIN | |
util_debug_start_one_step(p_action => 'init_process_columns'); | |
-- init | |
g_status.rpad_columns := 0; | |
g_status.xmltype_column_present := FALSE; | |
FOR i IN g_columns.first .. g_columns.last LOOP | |
-- calc rpad length | |
IF length(g_columns(i).column_name) > g_status.rpad_columns THEN | |
g_status.rpad_columns := length(g_columns(i).column_name); | |
END IF; | |
-- create reverse index to get collection id by column name | |
g_columns_reverse_index(g_columns(i).column_name) := i; | |
-- check, if we have a xmltype column present (we have then to provide a XML compare function) | |
IF g_columns(i).data_type = 'XMLTYPE' THEN | |
g_status.xmltype_column_present := TRUE; | |
END IF; | |
-- check, if we have an identity column present | |
IF g_columns(i).identity_type IS NOT NULL THEN | |
g_status.identity_column := g_columns(i).column_name; | |
g_status.identity_type := g_columns(i).identity_type || | |
CASE WHEN g_columns(i).default_on_null_yn = 'Y' THEN ' ON NULL' END; | |
END IF; | |
-- Calc column prefix by saving the found prefix as tab index and count afterwards | |
-- the length of the tab: if it is greater then 1 we have NO distinct column prefix. | |
v_column_prefix := substr(g_columns(i).column_name, 1, | |
CASE WHEN instr(g_columns(i).column_name, '_') = 0 | |
THEN length(g_columns(i).column_name) | |
ELSE instr(g_columns(i).column_name, '_') - 1 | |
END); | |
v_column_prefix_tab(v_column_prefix) := v_column_prefix; | |
END LOOP; | |
IF g_params.enable_insertion_of_rows AND g_status.identity_type = 'BY DEFAULT' THEN | |
raise_application_error(c_generator_error_number, | |
'Your table '||g_params.table_name||' has an identity type BY DEFAULT.' || c_lf || | |
'We can not generate an API for this table. Please change your identity' || c_lf || | |
'type either to ALWAYS or BY DEFAULT ON NULL. For the API create methods' || c_lf || | |
'we need to decide if the parameter for your identity column should be' || c_lf || | |
'shown or not. If it is shown we need to set the default for the parameter' || c_lf || | |
'to NULL for you, so you will be able to omit the identity information' || c_lf || | |
'and the table will care about to generate one for you. You will also' || c_lf || | |
'be able to provide an own identity for e.g loading existing data.' || c_lf || | |
'Please refer to this article by Tim Hall for more informations about' || c_lf || | |
'identity columns: ' || c_lf || | |
'https://oracle-base.com/articles/12c/identity-columns-in-oracle-12cr1'); | |
END IF; | |
IF v_column_prefix_tab.count > 1 THEN | |
g_status.column_prefix := NULL; | |
ELSE | |
g_status.column_prefix := v_column_prefix_tab.first; | |
END IF; | |
IF g_params.col_prefix_in_method_names = FALSE AND g_status.column_prefix IS NULL THEN | |
raise_application_error(c_generator_error_number, | |
'The prefix of your column names (example: prefix_rest_of_column_name)' || c_lf || | |
'is not unique and you requested to cut off the prefix for getter and' || c_lf || | |
'setter method names. Please ensure either your column names have a' || c_lf || | |
'unique prefix or switch the parameter p_col_prefix_in_method_names' || c_lf || | |
'to true (SQL Developer oddgen integration: check option "Keep column' || c_lf || | |
'prefix in method names").'); | |
END IF; | |
util_debug_stop_one_step; | |
EXCEPTION | |
WHEN others THEN | |
util_debug_stop_one_step; | |
raise; | |
END init_process_columns; | |
----------------------------------------------------------------------------- | |
PROCEDURE init_process_pk_columns IS | |
v_count PLS_INTEGER; | |
v_idx PLS_INTEGER; | |
BEGIN | |
util_debug_start_one_step(p_action => 'init_process_pk_columns'); | |
v_count := g_pk_columns.count; | |
IF v_count = 0 THEN | |
raise_application_error(c_generator_error_number, | |
'Unable to generate API - no primary key present for table ' || g_params.table_name); | |
ELSIF v_count = 1 THEN | |
g_status.pk_is_multi_column := FALSE; | |
ELSIF v_count > 1 THEN | |
g_status.pk_is_multi_column := TRUE; | |
END IF; | |
g_status.rpad_pk_columns := 0; | |
FOR i IN g_pk_columns.first .. g_pk_columns.last LOOP | |
v_idx := g_columns_reverse_index(g_pk_columns(i).column_name); | |
g_columns(v_idx).is_pk_yn := 'Y'; | |
g_columns(v_idx).is_nullable_yn := 'N'; | |
IF g_pk_columns(i).column_name_length > g_status.rpad_pk_columns THEN | |
g_status.rpad_pk_columns := g_pk_columns(i).column_name_length; | |
END IF; | |
END LOOP; | |
util_debug_stop_one_step; | |
END init_process_pk_columns; | |
----------------------------------------------------------------------------- | |
PROCEDURE init_process_uk_columns IS | |
v_count PLS_INTEGER; | |
v_idx PLS_INTEGER; | |
BEGIN | |
util_debug_start_one_step(p_action => 'init_process_uk_columns'); | |
v_count := g_uk_columns.count; | |
IF v_count > 0 THEN | |
g_status.rpad_uk_columns := 0; | |
FOR i IN g_uk_columns.first .. g_uk_columns.last LOOP | |
v_idx := g_columns_reverse_index(g_uk_columns(i).column_name); | |
g_columns(v_idx).is_uk_yn := 'Y'; | |
IF g_uk_columns(i).column_name_length > g_status.rpad_uk_columns THEN | |
g_status.rpad_uk_columns := g_uk_columns(i).column_name_length; | |
END IF; | |
END LOOP; | |
END IF; | |
util_debug_stop_one_step; | |
END init_process_uk_columns; | |
----------------------------------------------------------------------------- | |
PROCEDURE init_process_fk_columns IS | |
v_count PLS_INTEGER; | |
v_idx PLS_INTEGER; | |
BEGIN | |
util_debug_start_one_step(p_action => 'init_process_fk_columns'); | |
v_count := g_fk_columns.count; | |
IF v_count > 0 THEN | |
FOR i IN g_fk_columns.first .. g_fk_columns.last LOOP | |
v_idx := g_columns_reverse_index(g_fk_columns(i).column_name); | |
g_columns(v_idx).is_fk_yn := 'Y'; | |
g_columns(v_idx).r_owner := g_fk_columns(i).r_owner; | |
g_columns(v_idx).r_table_name := g_fk_columns(i).r_table_name; | |
g_columns(v_idx).r_column_name := g_fk_columns(i).r_column_name; | |
END LOOP; | |
END IF; | |
util_debug_stop_one_step; | |
END init_process_fk_columns; | |
----------------------------------------------------------------------------- | |
PROCEDURE init_process_audit_columns IS | |
PROCEDURE process_audit_type( | |
p_audit_type VARCHAR2) | |
is | |
v_idx PLS_INTEGER; | |
v_column_name all_tab_cols.column_name%TYPE; | |
BEGIN | |
v_column_name := regexp_substr( | |
g_params.audit_column_mappings, | |
p_audit_type || '="?([^,"]*)"?',1,1,'i',1); | |
IF v_column_name IS NOT NULL THEN | |
v_column_name := replace(v_column_name, '#PREFIX#', g_status.column_prefix); | |
BEGIN | |
v_idx := g_columns_reverse_index(v_column_name); | |
g_columns(v_idx).audit_type := p_audit_type; | |
EXCEPTION | |
WHEN no_data_found THEN NULL; | |
WHEN others THEN raise; | |
END; | |
END IF; | |
END; | |
BEGIN | |
IF instr(g_params.audit_column_mappings, '#PREFIX#') > 0 AND g_status.column_prefix IS NULL THEN | |
raise_application_error(c_generator_error_number, | |
'The prefix of your column names (example: prefix_rest_of_column_name)' || c_lf || | |
'is not unique and you used the placeholder #PREFIX# in the parameter' || c_lf || | |
'p_audit_column_mappings. Please ensure either your column names have a' || c_lf || | |
'unique prefix or do not use the placeholder #PREFIX# in the parameter' || c_lf || | |
'p_audit_column_mappings.'); | |
ELSE | |
util_debug_start_one_step(p_action => 'init_process_audit_columns'); | |
process_audit_type('CREATED'); | |
process_audit_type('CREATED_BY'); | |
process_audit_type('UPDATED'); | |
process_audit_type('UPDATED_BY'); | |
util_debug_stop_one_step; | |
END IF; | |
END init_process_audit_columns; | |
----------------------------------------------------------------------------- | |
PROCEDURE init_process_row_version_column IS | |
v_idx PLS_INTEGER; | |
v_column_name all_tab_cols.column_name%TYPE; | |
v_expression VARCHAR2(4000 char); | |
BEGIN | |
IF instr(g_params.row_version_column_mapping, '#PREFIX#') > 0 AND g_status.column_prefix IS NULL THEN | |
raise_application_error(c_generator_error_number, | |
'The prefix of your column names (example: prefix_rest_of_column_name)' || c_lf || | |
'is not unique and you used the placeholder #PREFIX# in the parameter' || c_lf || | |
'p_row_version_column_mapping. Please ensure either your column names' || c_lf || | |
'have a unique prefix or do not use the placeholder #PREFIX# in the' || c_lf || | |
'parameter p_row_version_column_mapping.'); | |
ELSE | |
util_debug_start_one_step(p_action => 'init_process_row_version_column'); | |
v_idx := instr(g_params.row_version_column_mapping, '='); | |
IF v_idx > 0 THEN | |
v_column_name := trim(substr(g_params.row_version_column_mapping, 1, v_idx - 1)); | |
v_expression := trim(substr(g_params.row_version_column_mapping, v_idx + 1)); | |
v_column_name := replace(v_column_name, '#PREFIX#', g_status.column_prefix); | |
IF v_column_name IS NULL OR v_expression IS NULL THEN | |
raise_application_error(c_generator_error_number, | |
'Invalid parameter p_row_version_column_mapping - the resulting' || c_lf || | |
'column name or SQL expression is null. Please have a look in' || c_lf || | |
'the docs and provide a valid string e.g.' || c_lf || | |
'#PREFIX#_MY_COLUMN_NAME=my_version_sequence.nextval'); | |
END IF; | |
BEGIN | |
v_idx := g_columns_reverse_index(v_column_name); | |
g_columns(v_idx).row_version_expression := v_expression; | |
EXCEPTION | |
WHEN no_data_found THEN NULL; | |
WHEN others THEN raise; | |
END; | |
IF v_idx IS NULL THEN | |
raise_application_error(c_generator_error_number, | |
'Invalid column name provided in the parameter' || c_lf || | |
'p_row_version_column_mapping.' || c_lf || | |
'#PREFIX#_MY_COLUMN_NAME=my_version_sequence.nextval'); | |
END IF; | |
util_debug_stop_one_step; | |
END IF; | |
END IF; | |
END init_process_row_version_column; | |
----------------------------------------------------------------------------- | |
PROCEDURE init_count_column_types IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'init_count_column_types'); | |
g_status.number_of_data_columns := 0; | |
g_status.number_of_pk_columns := 0; | |
g_status.number_of_uk_columns := 0; | |
g_status.number_of_fk_columns := 0; | |
FOR i IN g_columns.first .. g_columns.last LOOP | |
IF g_columns(i).is_pk_yn = 'N' | |
AND g_columns(i).is_excluded_yn = 'N' | |
AND g_columns(i).audit_type IS NULL | |
AND g_columns(i).row_version_expression IS NULL THEN | |
g_status.number_of_data_columns := g_status.number_of_data_columns + 1; | |
END IF; | |
IF g_columns(i).is_pk_yn = 'Y' THEN | |
g_status.number_of_pk_columns := g_status.number_of_pk_columns + 1; | |
END IF; | |
IF g_columns(i).is_uk_yn = 'Y' THEN | |
g_status.number_of_uk_columns := g_status.number_of_uk_columns + 1; | |
END IF; | |
IF g_columns(i).is_fk_yn = 'Y' THEN | |
g_status.number_of_fk_columns := g_status.number_of_fk_columns + 1; | |
END IF; | |
END LOOP; | |
util_debug_stop_one_step; | |
END init_count_column_types; | |
----------------------------------------------------------------------------- | |
PROCEDURE init_process_custom_defaults IS | |
v_index INTEGER; | |
BEGIN | |
util_debug_start_one_step(p_action => 'init_process_custom_defaults'); | |
-- process user provided custom defaults | |
IF g_params.custom_default_values IS NOT NULL THEN | |
FOR i IN (SELECT x.column_name AS column_name, x.data_default AS data_default | |
FROM xmltable('for $i in /custom_defaults/column return $i' passing g_params.custom_default_values | |
columns -- | |
column_name VARCHAR2(200) path '@name', -- | |
data_default VARCHAR2(4000) path 'text()') x) LOOP | |
BEGIN | |
v_index := g_columns_reverse_index(i.column_name); | |
IF v_index IS NOT NULL THEN | |
g_columns(v_index).data_custom_default := i.data_default; | |
g_columns(v_index).custom_default_source := 'USER'; | |
END IF; | |
EXCEPTION | |
WHEN no_data_found THEN | |
NULL; | |
END; | |
END LOOP; | |
END IF; | |
-- generate standard custom defaults for the users convenience... | |
FOR i IN g_columns.first .. g_columns.last LOOP | |
IF g_columns(i).data_custom_default IS NULL -- do not override users defaults from the processing step above | |
AND g_columns(i).is_excluded_yn = 'N' | |
AND g_columns(i).identity_type IS NULL | |
AND g_columns(i).audit_type IS NULL | |
AND g_columns(i).row_version_expression IS NULL | |
THEN | |
IF g_columns(i).data_default IS NOT NULL THEN | |
g_columns(i).data_custom_default := g_columns(i).data_default; | |
g_columns(i).custom_default_source := 'TABLE'; | |
ELSE | |
g_columns(i).data_custom_default := | |
CASE | |
WHEN g_columns(i).is_pk_yn = 'Y' AND NOT g_status.pk_is_multi_column AND | |
g_params.sequence_name IS NOT NULL THEN | |
'"' || g_params.sequence_name || '"' || '.nextval' | |
WHEN g_columns(i).is_fk_yn = 'Y' THEN | |
util_get_fk_value(p_table_name => g_columns(i).r_table_name, | |
p_column_name => g_columns(i).r_column_name, | |
p_owner => g_columns(i).r_owner) | |
WHEN g_columns(i).data_type IN ('NUMBER', 'FLOAT') THEN | |
'round(dbms_random.value(0, ' || | |
rpad('9', least(nvl(g_columns(i).data_precision, 12), 24) - nvl(g_columns(i).data_scale, 0), '9') || | |
CASE | |
WHEN nvl(g_columns(i).data_scale, 0) > 0 THEN | |
'.' || rpad('9', g_columns(i).data_scale, '9') | |
ELSE | |
NULL | |
END || '), ' || | |
CASE | |
WHEN g_columns(i).data_type = 'NUMBER' THEN | |
to_char(nvl(g_columns(i).data_scale, 0)) | |
WHEN g_columns(i).data_type = 'FLOAT' THEN | |
to_char(least(g_columns(i).data_precision / 2, 12)) | |
END || ')' | |
WHEN g_columns(i).data_type LIKE '%CHAR%' THEN | |
CASE | |
WHEN lower(g_columns(i).column_name) LIKE '%mail%' THEN | |
q'£dbms_random.string('L', round(dbms_random.value(6, £' || to_char(least(g_columns(i).char_length - 18, 24)) || ')))' || | |
q'£ || '@' || £' || | |
q'£dbms_random.string('L', round(dbms_random.value(6, 12)))£' || | |
q'£ || '.' || £' || | |
q'£dbms_random.string('L', round(dbms_random.value(2, 4)))£' | |
WHEN lower(g_columns(i).column_name) LIKE '%phone%' THEN | |
q'£substr('+' || £' || | |
q'£to_char(round(dbms_random.value(1, 99))) || ' ' || £' || | |
q'£to_char(round(dbms_random.value(10, 9999))) || ' ' || £' || | |
q'£to_char(round(dbms_random.value(100, 999))) || ' ' || £' || | |
q'£to_char(round(dbms_random.value(100, 9999))), 1, £' || | |
to_char(g_columns(i).char_length) || ')' | |
WHEN lower(g_columns(i).column_name) LIKE '%name%' | |
OR lower(g_columns(i).column_name) LIKE '%city%' | |
OR lower(g_columns(i).column_name) LIKE '%country%' | |
THEN | |
q'£initcap(dbms_random.string('L', round(dbms_random.value(3, £' || to_char(g_columns(i).char_length) || '))))' | |
WHEN lower(g_columns(i).column_name) LIKE '%street%' THEN | |
q'£initcap(dbms_random.string('L', round(dbms_random.value(3, £' || to_char(g_columns(i).char_length - 4) || '))))' || | |
q'£ || ' ' || £' || | |
q'£to_char(round(dbms_random.value(1, 200)))£' | |
ELSE | |
q'£dbms_random.string('A', round(dbms_random.value(1, £' || to_char(g_columns(i).char_length) || ')))' | |
END | |
WHEN g_columns(i).data_type = 'DATE' THEN | |
q'£to_date(round(dbms_random.value(to_char(date '1900-01-01', 'j'), to_char(date '2099-12-31', 'j'))), 'j')£' | |
WHEN g_columns(i).data_type LIKE 'TIMESTAMP%' THEN | |
'systimestamp' | |
WHEN g_columns(i).data_type = 'CLOB' THEN | |
q'£to_clob('Dummy clob for API method get_a_row: ' || dbms_random.string('A', round(dbms_random.value(30, 100))))£' | |
WHEN g_columns(i).data_type = 'BLOB' THEN | |
q'£to_blob(utl_raw.cast_to_raw('Dummy clob for API method get_a_row: ' || dbms_random.string('A', round(dbms_random.value(30, 100)))))£' | |
WHEN g_columns(i).data_type = 'XMLTYPE' THEN | |
q'£xmltype('<dummy>Dummy XML for API method get_a_row: ' || dbms_random.string('A', round(dbms_random.value(30, 100))) || '</dummy>')£' | |
ELSE | |
'NULL' | |
END; | |
g_columns(i).custom_default_source := 'TAPIGEN'; | |
END IF; | |
END IF; | |
END LOOP; | |
util_debug_stop_one_step; | |
END init_process_custom_defaults; | |
----------------------------------------------------------------------------- | |
BEGIN | |
init_reset_globals; | |
g_status.generator_action := p_generator_action; | |
g_params.owner := p_owner; | |
g_params.table_name := p_table_name; | |
init_check_if_table_exists; | |
init_process_parameters; | |
IF g_params.api_name IS NOT NULL THEN | |
init_check_if_api_name_exists; | |
END IF; | |
IF g_params.sequence_name IS NOT NULL THEN | |
init_check_if_sequence_exists; | |
END IF; | |
init_create_temporary_lobs; | |
init_fetch_columns; | |
init_fetch_constraints; | |
init_fetch_constraint_columns; | |
init_process_columns; | |
init_process_pk_columns; | |
init_process_uk_columns; | |
init_process_fk_columns; | |
IF g_params.audit_column_mappings IS NOT NULL THEN | |
init_process_audit_columns; | |
END IF; | |
IF g_params.row_version_column_mapping IS NOT NULL THEN | |
init_process_row_version_column; | |
END IF; | |
init_count_column_types; | |
IF g_params.enable_custom_defaults THEN | |
init_process_custom_defaults; | |
END IF; | |
END main_init; | |
----------------------------------------------------------------------------- | |
PROCEDURE main_generate_code IS | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_header IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_header'); | |
g_code_blocks.template := ' | |
CREATE OR REPLACE PACKAGE {{ OWNER }}.{{ API_NAME }} IS | |
/* | |
This is the API for the table {{ TABLE_NAME }}{{ IDENTITY_TYPE }}. | |
GENERATION OPTIONS | |
- Must be in the lines {{ SPEC_OPTIONS_MIN_LINE }}-{{ SPEC_OPTIONS_MAX_LINE }} to be reusable by the generator | |
- DO NOT TOUCH THIS until you know what you do | |
- Read the docs under github.com/OraMUC/table-api-generator ;-) | |
<options | |
generator="{{ GENERATOR }}" | |
generator_version="{{ GENERATOR_VERSION }}" | |
generator_action="{{ GENERATOR_ACTION }}" | |
generated_at="{{ GENERATED_AT }}" | |
generated_by="{{ GENERATED_BY }}" | |
p_table_name="{{ TABLE_NAME_XML }}" | |
p_owner="{{ OWNER_XML }}" | |
p_enable_insertion_of_rows="{{ ENABLE_INSERTION_OF_ROWS }}" | |
p_enable_column_defaults="{{ ENABLE_COLUMN_DEFAULTS }}" | |
p_enable_update_of_rows="{{ ENABLE_UPDATE_OF_ROWS }}" | |
p_enable_deletion_of_rows="{{ ENABLE_DELETION_OF_ROWS }}" | |
p_enable_parameter_prefixes="{{ ENABLE_PARAMETER_PREFIXES }}" | |
p_enable_proc_with_out_params="{{ ENABLE_PROC_WITH_OUT_PARAMS }}" | |
p_enable_getter_and_setter="{{ ENABLE_GETTER_AND_SETTER }}" | |
p_col_prefix_in_method_names="{{ COL_PREFIX_IN_METHOD_NAMES }}" | |
p_return_row_instead_of_pk="{{ RETURN_ROW_INSTEAD_OF_PK }}" | |
p_double_quote_names="{{ DOUBLE_QUOTE_NAMES }}" | |
p_default_bulk_limit="{{ DEFAULT_BULK_LIMIT }}" | |
p_enable_dml_view="{{ ENABLE_DML_VIEW }}" | |
p_enable_one_to_one_view="{{ ENABLE_ONE_TO_ONE_VIEW }}" | |
p_api_name="{{ API_NAME_XML }}" | |
p_sequence_name="{{ SEQUENCE_NAME_XML }}" | |
p_exclude_column_list="{{ EXCLUDE_COLUMN_LIST }}" | |
p_audit_column_mappings="{{ AUDIT_COLUMN_MAPPINGS }}" | |
p_audit_user_expression="{{ AUDIT_USER_EXPRESSION }}" | |
p_row_version_column_mapping="{{ ROW_VERSION_COLUMN_MAPPING }}" | |
p_enable_custom_defaults="{{ ENABLE_CUSTOM_DEFAULTS }}" | |
p_custom_default_values="{{ CUSTOM_DEFAULTS }}"/> | |
*/' || CASE WHEN g_status.xmltype_column_present THEN ' | |
/*this is required to handle XMLTYPE column for single row processing*/ | |
TYPE t_pk_rec IS RECORD ( | |
{% LIST_PK_COLUMNS %} );' END; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
CREATE OR REPLACE PACKAGE BODY {{ OWNER }}.{{ API_NAME }} IS | |
/* | |
This is the API for the table {{ TABLE_NAME }}{{ IDENTITY_TYPE }}. | |
- generator: {{ GENERATOR }} | |
- generator_version: {{ GENERATOR_VERSION }} | |
- generator_action: {{ GENERATOR_ACTION }} | |
- generated_at: {{ GENERATED_AT }} | |
- generated_by: {{ GENERATED_BY }} | |
*/'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_header; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_bulk_types IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_bulk_types'); | |
g_code_blocks.template := CASE WHEN g_status.xmltype_column_present THEN ' | |
/*this is required to handle XMLTYPE column for bulk processing*/ | |
TYPE t_pk_tab IS TABLE OF t_pk_rec; | |
' END || ' | |
TYPE t_rows_tab IS TABLE OF {{ TABLE_NAME }}%ROWTYPE; | |
TYPE t_strong_ref_cursor IS REF CURSOR RETURN {{ TABLE_NAME }}%ROWTYPE;'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
g_bulk_limit PLS_INTEGER := {{ DEFAULT_BULK_LIMIT }}; | |
g_bulk_completed BOOLEAN := FALSE;'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_bulk_types; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_bulk_is_complete_fnc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_bulk_is_complete_fnc'); | |
g_code_blocks.template := ' | |
FUNCTION bulk_is_complete | |
RETURN BOOLEAN;'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
FUNCTION bulk_is_complete | |
RETURN BOOLEAN IS | |
BEGIN | |
RETURN g_bulk_completed; | |
END bulk_is_complete;'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_bulk_is_complete_fnc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_get_bulk_limit_fnc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_get_bulk_limit_fnc'); | |
g_code_blocks.template := ' | |
FUNCTION get_bulk_limit | |
RETURN PLS_INTEGER;'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
FUNCTION get_bulk_limit | |
RETURN PLS_INTEGER IS | |
BEGIN | |
RETURN g_bulk_limit; | |
END get_bulk_limit;'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_get_bulk_limit_fnc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_set_bulk_limit_prc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_set_bulk_limit_prc'); | |
g_code_blocks.template := ' | |
PROCEDURE set_bulk_limit ( | |
{{ BULK_LIMIT_PARAM }} );'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
PROCEDURE set_bulk_limit ( | |
{{ BULK_LIMIT_PARAM }} ) | |
IS | |
BEGIN | |
g_bulk_limit := p_bulk_limit; | |
END set_bulk_limit;'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_set_bulk_limit_prc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_xml_compare_fnc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_xml_compare_fnc'); | |
g_code_blocks.template := q'£ | |
FUNCTION util_xml_compare ( | |
p_doc1 XMLTYPE, | |
p_doc2 XMLTYPE ) | |
RETURN NUMBER IS | |
v_return NUMBER; | |
BEGIN | |
SELECT CASE | |
WHEN XMLEXISTS( | |
'declare default element namespace "http://xmlns.oracle.com/xdb/xdiff.xsd"; /xdiff/*' | |
PASSING XMLDIFF( p_doc1, p_doc2 ) ) | |
THEN 1 | |
ELSE 0 | |
END | |
INTO v_return | |
FROM DUAL; | |
RETURN v_return; | |
END util_xml_compare;£'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_xml_compare_fnc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_row_exists_fnc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_row_exists_fnc'); | |
g_code_blocks.template := ' | |
FUNCTION row_exists ( | |
{% LIST_PK_PARAMS %} ) | |
RETURN BOOLEAN;'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
FUNCTION row_exists ( | |
{% LIST_PK_PARAMS %} ) | |
RETURN BOOLEAN | |
IS | |
v_return BOOLEAN := FALSE; | |
v_dummy PLS_INTEGER; | |
CURSOR cur_bool IS | |
SELECT 1 | |
FROM {{ TABLE_NAME }} | |
WHERE {% LIST_PK_COLUMNS_WHERE_CLAUSE %}; | |
BEGIN | |
OPEN cur_bool; | |
FETCH cur_bool INTO v_dummy; | |
IF cur_bool%FOUND THEN | |
v_return := TRUE; | |
END IF; | |
CLOSE cur_bool; | |
RETURN v_return; | |
END;'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_row_exists_fnc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_row_exists_yn_fnc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_row_exists_yn_fnc'); | |
g_code_blocks.template := ' | |
FUNCTION row_exists_yn ( | |
{% LIST_PK_PARAMS %} ) | |
RETURN VARCHAR2;'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := q'£ | |
FUNCTION row_exists_yn ( | |
{% LIST_PK_PARAMS %} ) | |
RETURN VARCHAR2 | |
IS | |
BEGIN | |
RETURN | |
CASE WHEN row_exists( {% LIST_PK_MAP_PARAM_EQ_PARAM %} ) | |
THEN 'Y' | |
ELSE 'N' | |
END; | |
END;£'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_row_exists_yn_fnc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_get_pk_by_unique_cols_fnc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_get_pk_by_unique_cols_fnc'); | |
IF g_uk_constraints.count > 0 THEN | |
FOR i IN g_uk_constraints.first .. g_uk_constraints.last LOOP | |
g_iterator.current_uk_constraint := g_uk_constraints(i).constraint_name; | |
g_code_blocks.template := ' | |
FUNCTION get_pk_by_unique_cols ( | |
{% LIST_UK_PARAMS %} ) | |
RETURN {{ RETURN_TYPE }};'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
FUNCTION get_pk_by_unique_cols ( | |
{% LIST_UK_PARAMS %} ) | |
RETURN {{ RETURN_TYPE }} IS | |
v_return {{ RETURN_TYPE }}; | |
BEGIN | |
v_return := read_row ( {% LIST_UK_MAP_PARAM_EQ_PARAM %} ){{ RETURN_TYPE_READ_ROW }}; | |
RETURN v_return; | |
END get_pk_by_unique_cols;'; | |
util_template_replace('API BODY'); | |
END LOOP; | |
END IF; | |
util_debug_stop_one_step; | |
END gen_get_pk_by_unique_cols_fnc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_create_row_fnc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_create_row_fnc'); | |
g_code_blocks.template := ' | |
FUNCTION create_row ( | |
{% LIST_PARAMS_W_PK use_column_defaults=true crud_mode=create %} ) | |
RETURN {{ RETURN_TYPE }};'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
FUNCTION create_row ( | |
{% LIST_PARAMS_W_PK use_column_defaults=true crud_mode=create %} ) | |
RETURN {{ RETURN_TYPE }} IS | |
v_return {{ RETURN_TYPE }}; ' || CASE WHEN g_status.xmltype_column_present | |
AND g_params.return_row_instead_of_pk THEN ' | |
/*this is required to handle column of datatype XMLTYPE for single row processing*/ | |
v_pk_rec t_pk_rec;' END || ' | |
BEGIN | |
INSERT INTO {{ TABLE_NAME }} ( | |
{% LIST_INSERT_COLUMNS crud_mode=create %} ) | |
VALUES ( | |
{% LIST_INSERT_PARAMS crud_mode=create %} ) | |
RETURN ' || CASE WHEN (g_params.return_row_instead_of_pk OR g_status.pk_is_multi_column) | |
AND NOT g_status.xmltype_column_present THEN ' | |
{% LIST_COLUMNS_W_PK_FULL %} | |
INTO | |
v_return; ' WHEN (g_params.return_row_instead_of_pk OR g_status.pk_is_multi_column) | |
AND g_status.xmltype_column_present THEN ' | |
{% LIST_PK_NAMES %} | |
INTO | |
{% LIST_PK_RETURN_COLUMNS %} | |
/* return clause does not support XMLTYPE column, so we have to do here an extra fetch */ | |
v_return := read_row ( | |
{% LIST_PK_MAP_PARAM_EQ_RETURN %} ); ' | |
ELSE ' | |
{{ PK_COLUMN }} | |
INTO | |
v_return;' END || ' | |
RETURN v_return; | |
END create_row;'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_create_row_fnc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_create_row_prc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_create_row_prc'); | |
g_code_blocks.template := ' | |
PROCEDURE create_row ( | |
{% LIST_PARAMS_W_PK use_column_defaults=true crud_mode=create %} );'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
PROCEDURE create_row ( | |
{% LIST_PARAMS_W_PK use_column_defaults=true crud_mode=create %} ) | |
IS | |
v_return {{ RETURN_TYPE }}; | |
BEGIN | |
v_return := create_row ( | |
{% LIST_MAP_PAR_EQ_PARAM_W_PK crud_mode=create %} ); | |
END create_row;'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_create_row_prc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_create_rowtype_fnc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_create_rowtype_fnc'); | |
g_code_blocks.template := ' | |
FUNCTION create_row ( | |
{{ ROWTYPE_PARAM }} ) | |
RETURN {{ RETURN_TYPE }};'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
FUNCTION create_row ( | |
{{ ROWTYPE_PARAM }} ) | |
RETURN {{ RETURN_TYPE }} IS | |
v_return {{ RETURN_TYPE }}; | |
BEGIN | |
v_return := create_row ( | |
{% LIST_MAP_PAR_EQ_ROWTYPCOL_W_PK crud_mode=create %} ); | |
RETURN v_return; | |
END create_row;'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_create_rowtype_fnc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_create_rowtype_prc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_create_rowtype_prc'); | |
g_code_blocks.template := ' | |
PROCEDURE create_row ( | |
{{ ROWTYPE_PARAM }} );'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
PROCEDURE create_row ( | |
{{ ROWTYPE_PARAM }} ) | |
IS | |
v_return {{ RETURN_TYPE }}; | |
BEGIN | |
v_return := create_row ( | |
{% LIST_MAP_PAR_EQ_ROWTYPCOL_W_PK crud_mode=create %} ); | |
END create_row;'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_create_rowtype_prc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_create_rows_bulk_fnc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_create_rows_bulk_fnc'); | |
g_code_blocks.template := ' | |
FUNCTION create_rows ( | |
{{ TABTYPE_PARAM }} ) | |
RETURN t_rows_tab;'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
FUNCTION create_rows ( | |
{{ TABTYPE_PARAM }} ) | |
RETURN t_rows_tab IS | |
v_return t_rows_tab;' || CASE WHEN g_status.xmltype_column_present THEN ' | |
/*This is required to handle column of datatype XMLTYPE for bulk processing*/ | |
v_pk_tab t_pk_tab; | |
v_strong_ref_cursor t_strong_ref_cursor;' END || ' | |
BEGIN | |
FORALL i IN INDICES OF p_rows_tab | |
INSERT INTO {{ TABLE_NAME }} ( | |
{% LIST_INSERT_COLUMNS crud_mode=create %} ) | |
VALUES ( | |
{% LIST_INSERT_BULK_PARAMS crud_mode=create %} ) | |
RETURN ' || CASE WHEN NOT g_status.xmltype_column_present THEN ' | |
{% LIST_COLUMNS_W_PK_FULL %} | |
BULK COLLECT INTO v_return;' | |
ELSE ' | |
{% LIST_PK_NAMES %} | |
BULK COLLECT INTO v_pk_tab; | |
/*records have to be bulk-fetched again, because XMLType column can not be returned*/ | |
OPEN v_strong_ref_cursor FOR | |
SELECT | |
data_table.* | |
FROM | |
{{ TABLE_NAME }} data_table | |
INNER JOIN TABLE(v_pk_tab) pk_collection | |
ON {% LIST_PK_COLUMN_BULK_FETCH %}; | |
/*no loop required here, because maximum bulk limit already given by the size of p_rows_tab*/ | |
v_return := read_rows ( | |
p_ref_cursor => v_strong_ref_cursor ); | |
CLOSE v_strong_ref_cursor;' END || ' | |
RETURN v_return; | |
END create_rows;'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_create_rows_bulk_fnc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_create_rows_bulk_prc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_create_rows_bulk_prc'); | |
g_code_blocks.template := ' | |
PROCEDURE create_rows ( | |
{{ TABTYPE_PARAM }} );'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
PROCEDURE create_rows ( | |
{{ TABTYPE_PARAM }} ) | |
IS | |
v_return t_rows_tab; | |
BEGIN | |
v_return := create_rows(p_rows_tab => p_rows_tab); | |
END create_rows;'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_create_rows_bulk_prc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_read_row_fnc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_read_row_fnc'); | |
g_code_blocks.template := ' | |
FUNCTION read_row ( | |
{% LIST_PK_PARAMS %} ) | |
RETURN {{ TABLE_NAME }}%ROWTYPE;'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
FUNCTION read_row ( | |
{% LIST_PK_PARAMS %} ) | |
RETURN {{ TABLE_NAME }}%ROWTYPE IS | |
v_row {{ TABLE_NAME }}%ROWTYPE; | |
CURSOR cur_row IS | |
SELECT * | |
FROM {{ TABLE_NAME }} | |
WHERE {% LIST_PK_COLUMNS_WHERE_CLAUSE %}; | |
BEGIN | |
OPEN cur_row; | |
FETCH cur_row INTO v_row; | |
CLOSE cur_row; | |
RETURN v_row; | |
END read_row;'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_read_row_fnc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_read_rows_bulk_fnc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_read_rows_bulk_fnc'); | |
g_code_blocks.template := ' | |
FUNCTION read_rows ( | |
{{ REFCURSOR_PARAM }} ) | |
RETURN t_rows_tab;'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
FUNCTION read_rows ( | |
{{ REFCURSOR_PARAM }} ) | |
RETURN t_rows_tab | |
IS | |
v_return t_rows_tab; | |
BEGIN | |
IF (p_ref_cursor%ISOPEN) THEN | |
g_bulk_completed := FALSE; | |
FETCH p_ref_cursor BULK COLLECT INTO v_return LIMIT g_bulk_limit; | |
IF (v_return.COUNT < g_bulk_limit) THEN | |
g_bulk_completed := TRUE; | |
END IF; | |
END IF; | |
RETURN v_return; | |
END read_rows;'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_read_rows_bulk_fnc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_read_row_prc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_read_row_prc'); | |
g_code_blocks.template := ' | |
PROCEDURE read_row ( | |
{% LIST_PARAMS_W_PK_IO %} );'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
PROCEDURE read_row ( | |
{% LIST_PARAMS_W_PK_IO %} ) | |
IS | |
v_row {{ TABLE_NAME }}%ROWTYPE; | |
BEGIN | |
v_row := read_row ( {% LIST_PK_MAP_PARAM_EQ_PARAM %} ); | |
{% LIST_SET_PAR_EQ_ROWTYCOL_WO_PK %} | |
END read_row;'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_read_row_prc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_read_row_by_uk_fnc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_read_row_by_uk_fnc'); | |
IF g_uk_constraints.count > 0 THEN | |
FOR i IN g_uk_constraints.first .. g_uk_constraints.last LOOP | |
g_iterator.current_uk_constraint := g_uk_constraints(i).constraint_name; | |
g_code_blocks.template := ' | |
FUNCTION read_row ( | |
{% LIST_UK_PARAMS %} ) | |
RETURN {{ TABLE_NAME }}%ROWTYPE;'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
FUNCTION read_row ( | |
{% LIST_UK_PARAMS %} ) | |
RETURN {{ TABLE_NAME }}%ROWTYPE IS | |
v_row {{ TABLE_NAME }}%ROWTYPE; | |
CURSOR cur_row IS | |
SELECT * | |
FROM {{ TABLE_NAME }} | |
WHERE {% LIST_UK_COLUMN_COMPARE %}; | |
BEGIN | |
OPEN cur_row; | |
FETCH cur_row INTO v_row; | |
CLOSE cur_row; | |
RETURN v_row; | |
END;'; | |
util_template_replace('API BODY'); | |
END LOOP; | |
END IF; | |
util_debug_stop_one_step; | |
END gen_read_row_by_uk_fnc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_update_row_prc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_update_row_prc'); | |
g_code_blocks.template := ' | |
PROCEDURE update_row ( | |
{% LIST_PARAMS_W_PK %} );'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
PROCEDURE update_row ( | |
{% LIST_PARAMS_W_PK %} ) | |
IS | |
BEGIN' || CASE WHEN g_status.number_of_data_columns > 0 THEN ' | |
UPDATE {{ TABLE_NAME }} | |
SET {% LIST_SET_COL_EQ_PARAM_WO_PK %} | |
WHERE {% LIST_PK_COLUMNS_WHERE_CLAUSE %};' | |
ELSE ' | |
/* | |
There is no column anymore to update! All remaining columns are part of the | |
primary key, audit columns or excluded via exclude column list | |
*/ | |
NULL;' END || ' | |
END update_row;'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_update_row_prc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_update_rowtype_prc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_update_rowtype_prc'); | |
g_code_blocks.template := ' | |
PROCEDURE update_row ( | |
{{ ROWTYPE_PARAM }} );'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
PROCEDURE update_row ( | |
{{ ROWTYPE_PARAM }} ) | |
IS | |
BEGIN | |
update_row( | |
{% LIST_MAP_PAR_EQ_ROWTYPCOL_W_PK %} ); | |
END update_row;'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_update_rowtype_prc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_update_rows_bulk_prc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_update_rows_bulk_prc'); | |
g_code_blocks.template := ' | |
PROCEDURE update_rows ( | |
{{ TABTYPE_PARAM }} );'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
PROCEDURE update_rows ( | |
{{ TABTYPE_PARAM }} ) | |
IS | |
BEGIN' || CASE WHEN g_status.number_of_data_columns > 0 THEN ' | |
FORALL i IN INDICES OF p_rows_tab | |
UPDATE {{ TABLE_NAME }} | |
SET {% LIST_SET_COL_EQ_PAR_BULK_WO_PK %} | |
WHERE {% LIST_PK_COLUMN_BULK_COMPARE %};' | |
ELSE ' | |
/* | |
There is no column anymore to update! All remaining columns are part of the | |
primary key, audit columns or excluded via exclude column list. | |
*/ | |
NULL;' END || ' | |
END update_rows;'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_update_rows_bulk_prc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_createorupdate_row_fnc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_createorupdate_row_fnc'); | |
g_code_blocks.template := ' | |
FUNCTION create_or_update_row ( | |
{% LIST_PARAMS_W_PK %} ) | |
RETURN {{ RETURN_TYPE }};'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
FUNCTION create_or_update_row ( | |
{% LIST_PARAMS_W_PK %} ) | |
RETURN {{ RETURN_TYPE }} IS | |
v_return {{ RETURN_TYPE }}; | |
BEGIN | |
IF row_exists( {% LIST_PK_MAP_PARAM_EQ_PARAM %} ) THEN | |
update_row( | |
{% LIST_MAP_PAR_EQ_PARAM_W_PK padding=8 %} ); | |
v_return := read_row ( {% LIST_PK_MAP_PARAM_EQ_PARAM %} ){{ RETURN_TYPE_READ_ROW }}; | |
ELSE | |
v_return := create_row ( | |
{% LIST_MAP_PAR_EQ_PARAM_W_PK crud_mode=create padding=8 %} ); | |
END IF; | |
RETURN v_return; | |
END create_or_update_row;'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_createorupdate_row_fnc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_createorupdate_row_prc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_createorupdate_row_prc'); | |
g_code_blocks.template := ' | |
PROCEDURE create_or_update_row ( | |
{% LIST_PARAMS_W_PK %} );'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
PROCEDURE create_or_update_row ( | |
{% LIST_PARAMS_W_PK %} ) | |
IS | |
v_return {{ RETURN_TYPE }}; | |
BEGIN | |
v_return := create_or_update_row( | |
{% LIST_MAP_PAR_EQ_PARAM_W_PK %} ); | |
END create_or_update_row;'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_createorupdate_row_prc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_createorupdate_rowtype_fnc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_createorupdate_rowtype_fnc'); | |
g_code_blocks.template := ' | |
FUNCTION create_or_update_row ( | |
{{ ROWTYPE_PARAM }} ) | |
RETURN {{ RETURN_TYPE }};'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
FUNCTION create_or_update_row ( | |
{{ ROWTYPE_PARAM }} ) | |
RETURN {{ RETURN_TYPE }} IS | |
v_return {{ RETURN_TYPE }}; | |
BEGIN | |
v_return := create_or_update_row( | |
{% LIST_MAP_PAR_EQ_ROWTYPCOL_W_PK %} ); | |
RETURN v_return; | |
END create_or_update_row;'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_createorupdate_rowtype_fnc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_createorupdate_rowtype_prc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_createorupdate_rowtype_prc'); | |
g_code_blocks.template := ' | |
PROCEDURE create_or_update_row ( | |
{{ ROWTYPE_PARAM }} );'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
PROCEDURE create_or_update_row ( | |
{{ ROWTYPE_PARAM }} ) | |
IS | |
v_return {{ RETURN_TYPE }}; | |
BEGIN | |
v_return := create_or_update_row( | |
{% LIST_MAP_PAR_EQ_ROWTYPCOL_W_PK %} ); | |
END create_or_update_row;'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_createorupdate_rowtype_prc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_delete_row_prc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_delete_row_prc'); | |
g_code_blocks.template := ' | |
PROCEDURE delete_row ( | |
{% LIST_PK_PARAMS %} );'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
PROCEDURE delete_row ( | |
{% LIST_PK_PARAMS %} ) | |
IS | |
BEGIN | |
DELETE FROM {{ TABLE_NAME }} | |
WHERE {% LIST_PK_COLUMNS_WHERE_CLAUSE %};' || ' | |
END delete_row;'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_delete_row_prc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_delete_rows_bulk_prc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_delete_row_prc'); | |
g_code_blocks.template := ' | |
PROCEDURE delete_rows ( | |
{{ TABTYPE_PARAM }} );'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
PROCEDURE delete_rows ( | |
{{ TABTYPE_PARAM }} ) | |
IS | |
BEGIN | |
FORALL i IN INDICES OF p_rows_tab | |
DELETE FROM {{ TABLE_NAME }} | |
WHERE {% LIST_PK_COLUMN_BULK_COMPARE %}; | |
END delete_rows;'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_delete_rows_bulk_prc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_getter_functions IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_getter_functions'); | |
FOR i IN g_columns.first .. g_columns.last LOOP | |
IF g_columns(i).is_pk_yn = 'N' THEN | |
g_iterator.column_name := util_double_quote(g_columns(i).column_name); | |
g_iterator.method_name := util_get_method_name(g_columns(i).column_name); | |
g_code_blocks.template := ' | |
FUNCTION get_{{ I_METHOD_NAME }}( | |
{% LIST_PK_PARAMS %} ) | |
RETURN {{ TABLE_NAME }}.{{ I_COLUMN_NAME }}%TYPE;'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
FUNCTION get_{{ I_METHOD_NAME }}( | |
{% LIST_PK_PARAMS %} ) | |
RETURN {{ TABLE_NAME }}.{{ I_COLUMN_NAME }}%TYPE IS | |
BEGIN | |
RETURN read_row ( {% LIST_PK_MAP_PARAM_EQ_PARAM %} ).{{ I_COLUMN_NAME }}; | |
END get_{{ I_METHOD_NAME }};'; | |
util_template_replace('API BODY'); | |
END IF; | |
END LOOP; | |
util_debug_stop_one_step; | |
END gen_getter_functions; | |
------------------------------------------------------------------------ | |
PROCEDURE gen_setter_procedures IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_setter_procedures'); | |
FOR i IN g_columns.first .. g_columns.last LOOP | |
IF g_columns(i).is_excluded_yn = 'N' | |
AND g_columns(i).is_pk_yn = 'N' | |
AND g_columns(i).audit_type IS NULL | |
AND g_columns(i).row_version_expression IS NULL THEN | |
g_iterator.column_name := util_double_quote(g_columns(i).column_name); | |
g_iterator.method_name := util_get_method_name(g_columns(i).column_name); | |
g_iterator.parameter_name := util_get_parameter_name(g_columns(i).column_name, g_status.rpad_columns); | |
g_iterator.old_value := util_get_vc2_4000_operation(p_data_type => g_columns(i).data_type, | |
p_attribute_name => 'v_row.' || util_double_quote(g_columns(i).column_name)); | |
g_iterator.new_value := util_get_vc2_4000_operation(p_data_type => g_columns(i).data_type, | |
p_attribute_name => g_iterator.parameter_name); | |
g_code_blocks.template := ' | |
PROCEDURE set_{{ I_METHOD_NAME }} ( | |
{% LIST_PK_PARAMS %}, | |
{{ I_PARAMETER_NAME }} IN {{ TABLE_NAME }}.{{ I_COLUMN_NAME }}%TYPE );'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
PROCEDURE set_{{ I_METHOD_NAME }} ( | |
{% LIST_PK_PARAMS %}, | |
{{ I_PARAMETER_NAME }} IN {{ TABLE_NAME }}.{{ I_COLUMN_NAME }}%TYPE ) | |
IS | |
v_row {{ TABLE_NAME }}%ROWTYPE; | |
BEGIN | |
UPDATE {{ TABLE_NAME }} | |
SET {{ I_COLUMN_NAME }} = {{ I_PARAMETER_NAME }} | |
WHERE {% LIST_PK_COLUMNS_WHERE_CLAUSE %};' || ' | |
END set_{{ I_METHOD_NAME }};'; | |
util_template_replace('API BODY'); | |
END IF; | |
END LOOP; | |
util_debug_stop_one_step; | |
END gen_setter_procedures; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_get_a_row_fnc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_get_a_row_fnc'); | |
g_code_blocks.template := ' | |
FUNCTION get_a_row | |
RETURN {{ TABLE_NAME }}%ROWTYPE; | |
/* | |
Helper mainly for testing and dummy data generation purposes. | |
Returns a row with (hopefully) complete default data. | |
*/'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
FUNCTION get_a_row | |
RETURN {{ TABLE_NAME }}%ROWTYPE IS | |
v_row {{ TABLE_NAME }}%ROWTYPE; | |
BEGIN | |
{% LIST_ROWCOLS_W_CUST_DEFAULTS %} | |
return v_row; | |
END get_a_row;'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_get_a_row_fnc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_create_a_row_fnc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_create_a_row_fnc'); | |
g_code_blocks.template := ' | |
FUNCTION create_a_row ( | |
{% LIST_PARAMS_W_PK_CUST_DEFAULTS crud_mode=create %} ) | |
RETURN {{ RETURN_TYPE }}; | |
/* | |
Helper mainly for testing and dummy data generation purposes. | |
Create a new row without (hopefully) providing any parameters. | |
*/'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
FUNCTION create_a_row ( | |
{% LIST_PARAMS_W_PK_CUST_DEFAULTS crud_mode=create %} ) | |
RETURN {{ RETURN_TYPE }} IS | |
v_return {{ RETURN_TYPE }}; | |
BEGIN | |
v_return := create_row ( | |
{% LIST_MAP_PAR_EQ_PARAM_W_PK crud_mode=create %} ); | |
RETURN v_return; | |
END create_a_row;'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_create_a_row_fnc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_create_a_row_prc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_create_a_row_prc'); | |
g_code_blocks.template := ' | |
PROCEDURE create_a_row ( | |
{% LIST_PARAMS_W_PK_CUST_DEFAULTS crud_mode=create %} ); | |
/* | |
Helper mainly for testing and dummy data generation purposes. | |
Create a new row without (hopefully) providing any parameters. | |
*/'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
PROCEDURE create_a_row ( | |
{% LIST_PARAMS_W_PK_CUST_DEFAULTS crud_mode=create %} ) | |
IS | |
v_return {{ RETURN_TYPE }}; | |
BEGIN | |
v_return := create_row ( | |
{% LIST_MAP_PAR_EQ_PARAM_W_PK crud_mode=create %} ); | |
END create_a_row;'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_create_a_row_prc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_read_a_row_fnc IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_read_a_row_fnc'); | |
g_code_blocks.template := ' | |
FUNCTION read_a_row | |
RETURN {{ TABLE_NAME }}%ROWTYPE; | |
/* | |
Helper mainly for testing and dummy data generation purposes. | |
Fetch one row (the first the database delivers) without providing | |
a primary key parameter. | |
*/'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
FUNCTION read_a_row | |
RETURN {{ TABLE_NAME }}%ROWTYPE IS | |
v_row {{ TABLE_NAME }}%ROWTYPE; | |
CURSOR cur_row IS SELECT * FROM {{ TABLE_NAME }}; | |
BEGIN | |
OPEN cur_row; | |
FETCH cur_row INTO v_row; | |
CLOSE cur_row; | |
RETURN v_row; | |
END read_a_row;'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_read_a_row_fnc; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_footer IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_footer'); | |
g_code_blocks.template := CASE WHEN g_params.enable_custom_defaults THEN ' | |
/* | |
You can simply copy over the defaults to your generator call - the attribute "source" is ignored then. | |
{% LIST_SPEC_CUSTOM_DEFAULTS %} | |
*/' END || ' | |
END {{ API_NAME }};'; | |
util_template_replace('API SPEC'); | |
g_code_blocks.template := ' | |
END {{ API_NAME }};'; | |
util_template_replace('API BODY'); | |
util_debug_stop_one_step; | |
END gen_footer; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_dml_view IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_dml_view'); | |
g_code_blocks.template := ' | |
CREATE OR REPLACE VIEW {{ OWNER }}.{{ DML_VIEW_NAME }} AS | |
SELECT {% LIST_COLUMNS_W_PK_FULL %} | |
FROM {{ TABLE_NAME }} | |
/* | |
This is the DML view for the table {{ TABLE_NAME }}. | |
- Generator: {{ GENERATOR }} | |
- Generator version: {{ GENERATOR_VERSION }} | |
- Generator action: {{ GENERATOR_ACTION }} | |
- Generated at: {{ GENERATED_AT }} | |
- Generated by: {{ GENERATED_BY }} | |
*/ | |
'; | |
util_template_replace('VIEW'); | |
util_debug_stop_one_step; | |
END gen_dml_view; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_dml_view_trigger IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_dml_view_trigger'); | |
g_code_blocks.template := ' | |
CREATE OR REPLACE TRIGGER {{ OWNER }}.{{ TRIGGER_NAME }} | |
INSTEAD OF INSERT OR UPDATE OR DELETE | |
ON {{ DML_VIEW_NAME }} | |
FOR EACH ROW | |
/* | |
This is the instead of trigger for the DML view of the table {{ TABLE_NAME }}. | |
- Generator: {{ GENERATOR }} | |
- Generator version: {{ GENERATOR_VERSION }} | |
- Generator action: {{ GENERATOR_ACTION }} | |
- Generated at: {{ GENERATED_AT }} | |
- Generated by: {{ GENERATED_BY }} | |
*/ | |
BEGIN | |
IF INSERTING THEN' || CASE WHEN g_params.enable_insertion_of_rows THEN ' | |
{{ API_NAME }}.create_row ( | |
{% LIST_MAP_PAR_EQ_NEWCOL_W_PK crud_mode=create %} );' | |
ELSE ' | |
raise_application_error ({{ GENERATOR_ERROR_NUMBER }}, ''Insertion of a row is not allowed.'');' | |
END || ' | |
ELSIF UPDATING THEN' || CASE WHEN g_params.enable_update_of_rows THEN ' | |
{{ API_NAME }}.update_row ( | |
{% LIST_MAP_PAR_EQ_NEWCOL_W_PK %} );' | |
ELSE ' | |
raise_application_error ({{ GENERATOR_ERROR_NUMBER }}, ''Update of a row is not allowed.'');' | |
END || ' | |
ELSIF DELETING THEN' || CASE WHEN g_params.enable_deletion_of_rows THEN ' | |
{{ API_NAME }}.delete_row ( | |
{% LIST_PK_MAP_PARAM_EQ_OLDCOL %} );' | |
ELSE ' | |
raise_application_error ({{ GENERATOR_ERROR_NUMBER }}, ''Deletion of a row is not allowed.'');' | |
END || ' | |
END IF; | |
END {{ TRIGGER_NAME }};'; | |
util_template_replace('TRIGGER'); | |
util_debug_stop_one_step; | |
END gen_dml_view_trigger; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_one_to_one_view IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_one_to_one_view'); | |
g_code_blocks.template := ' | |
CREATE OR REPLACE VIEW {{ OWNER }}.{{ ONE_TO_ONE_VIEW_NAME }} AS | |
SELECT {% LIST_COLUMNS_W_PK_FULL %} | |
FROM {{ TABLE_NAME }} | |
WITH READ ONLY | |
/* | |
This is the 1:1 view for the table {{ TABLE_NAME }}. | |
- Generator: {{ GENERATOR }} | |
- Generator version: {{ GENERATOR_VERSION }} | |
- Generator action: {{ GENERATOR_ACTION }} | |
- Generated at: {{ GENERATED_AT }} | |
- Generated by: {{ GENERATED_BY }} | |
*/ | |
'; | |
util_template_replace('1:1 VIEW'); | |
util_debug_stop_one_step; | |
END gen_one_to_one_view; | |
----------------------------------------------------------------------------- | |
PROCEDURE gen_finalize_clob_vc2_caching IS | |
BEGIN | |
util_debug_start_one_step(p_action => 'gen_finalize_clob_vc2_caching'); | |
util_clob_append(p_clob => g_code_blocks.api_spec, | |
p_clob_varchar_cache => g_code_blocks.api_spec_varchar_cache, | |
p_varchar_to_append => NULL, | |
p_final_call => TRUE); | |
util_clob_append(p_clob => g_code_blocks.api_body, | |
p_clob_varchar_cache => g_code_blocks.api_body_varchar_cache, | |
p_varchar_to_append => NULL, | |
p_final_call => TRUE); | |
IF g_params.enable_dml_view THEN | |
util_clob_append(p_clob => g_code_blocks.dml_view, | |
p_clob_varchar_cache => g_code_blocks.dml_view_varchar_cache, | |
p_varchar_to_append => NULL, | |
p_final_call => TRUE); | |
util_clob_append(p_clob => g_code_blocks.dml_view_trigger, | |
p_clob_varchar_cache => g_code_blocks.dml_view_trigger_varchar_cache, | |
p_varchar_to_append => NULL, | |
p_final_call => TRUE); | |
END IF; | |
IF g_params.enable_one_to_one_view THEN | |
util_clob_append(p_clob => g_code_blocks.one_to_one_view, | |
p_clob_varchar_cache => g_code_blocks.one_to_one_view_varchar_cache, | |
p_varchar_to_append => NULL, | |
p_final_call => TRUE); | |
END IF; | |
util_debug_stop_one_step; | |
END gen_finalize_clob_vc2_caching; | |
BEGIN | |
gen_header; | |
-- bulk header if choosen | |
gen_bulk_types; | |
gen_bulk_is_complete_fnc; | |
gen_set_bulk_limit_prc; | |
gen_get_bulk_limit_fnc; | |
IF g_status.xmltype_column_present THEN | |
gen_xml_compare_fnc; | |
END IF; | |
gen_row_exists_fnc; | |
gen_row_exists_yn_fnc; | |
-- GET_PK_BY_UNIQUE_COLS methods only if no multi row pk is present | |
-- use overloaded READ_ROW methods with unique params instead | |
IF NOT g_status.pk_is_multi_column THEN | |
gen_get_pk_by_unique_cols_fnc; | |
END IF; | |
-- CREATE methods | |
IF g_params.enable_insertion_of_rows THEN | |
gen_create_row_fnc; | |
gen_create_row_prc; | |
gen_create_rowtype_fnc; | |
gen_create_rowtype_prc; | |
gen_create_rows_bulk_fnc; | |
gen_create_rows_bulk_prc; | |
END IF; | |
-- READ methods | |
gen_read_row_fnc; | |
gen_read_row_by_uk_fnc; | |
IF g_params.enable_proc_with_out_params THEN | |
gen_read_row_prc; | |
END IF; | |
gen_read_rows_bulk_fnc; | |
-- UPDATE methods | |
IF g_params.enable_update_of_rows THEN | |
gen_update_row_prc; | |
gen_update_rowtype_prc; | |
gen_update_rows_bulk_prc; | |
END IF; | |
-- DELETE methods | |
IF g_params.enable_deletion_of_rows THEN | |
gen_delete_row_prc; | |
gen_delete_rows_bulk_prc; | |
END IF; | |
-- CREATE or UPDATE methods | |
IF g_params.enable_insertion_of_rows AND g_params.enable_update_of_rows THEN | |
gen_createorupdate_row_fnc; | |
gen_createorupdate_row_prc; | |
gen_createorupdate_rowtype_fnc; | |
gen_createorupdate_rowtype_prc; | |
END IF; | |
-- GETTER methods | |
IF g_params.enable_getter_and_setter THEN | |
gen_getter_functions; | |
END IF; | |
-- SETTER methods | |
IF g_params.enable_update_of_rows AND g_params.enable_getter_and_setter THEN | |
gen_setter_procedures; | |
END IF; | |
-- Some special stuff for the testing folks - thanks to Jacek Gębal ;-) | |
IF g_params.enable_custom_defaults THEN | |
gen_get_a_row_fnc; | |
gen_create_a_row_fnc; | |
gen_create_a_row_prc; | |
gen_read_a_row_fnc; | |
END IF; | |
gen_footer; | |
-- DML View and Trigger | |
IF g_params.enable_dml_view THEN | |
gen_dml_view; | |
gen_dml_view_trigger; | |
END IF; | |
-- 1:1 View | |
IF g_params.enable_one_to_one_view THEN | |
gen_one_to_one_view; | |
END IF; | |
gen_finalize_clob_vc2_caching; | |
END main_generate_code; | |
----------------------------------------------------------------------------- | |
PROCEDURE main_compile_code IS | |
BEGIN | |
-- compile package spec | |
util_debug_start_one_step(p_action => 'compile_spec'); | |
BEGIN | |
util_execute_sql(g_code_blocks.api_spec); | |
EXCEPTION | |
WHEN OTHERS THEN | |
NULL; | |
END; | |
util_debug_stop_one_step; | |
-- compile package body | |
util_debug_start_one_step(p_action => 'compile_body'); | |
BEGIN | |
util_execute_sql(g_code_blocks.api_body); | |
EXCEPTION | |
WHEN OTHERS THEN | |
NULL; | |
END; | |
util_debug_stop_one_step; | |
IF g_params.enable_dml_view THEN | |
-- compile DML view | |
util_debug_start_one_step(p_action => 'compile_dml_view'); | |
BEGIN | |
util_execute_sql(g_code_blocks.dml_view); | |
EXCEPTION | |
WHEN OTHERS THEN | |
NULL; | |
END; | |
util_debug_stop_one_step; | |
-- compile DML view trigger | |
util_debug_start_one_step(p_action => 'compile_dml_view_trigger'); | |
BEGIN | |
util_execute_sql(g_code_blocks.dml_view_trigger); | |
EXCEPTION | |
WHEN OTHERS THEN | |
NULL; | |
END; | |
util_debug_stop_one_step; | |
END IF; | |
IF g_params.enable_one_to_one_view THEN | |
-- compile DML view | |
util_debug_start_one_step(p_action => 'compile_one_to_one_view'); | |
BEGIN | |
util_execute_sql(g_code_blocks.one_to_one_view); | |
EXCEPTION | |
WHEN OTHERS THEN | |
NULL; | |
END; | |
util_debug_stop_one_step; | |
END IF; | |
END main_compile_code; | |
----------------------------------------------------------------------------- | |
FUNCTION main_return_code RETURN CLOB IS | |
terminator VARCHAR2(10 CHAR) := c_lf || '/' || c_lflf; | |
BEGIN | |
RETURN | |
g_code_blocks.api_spec || terminator || | |
g_code_blocks.api_body || terminator || | |
CASE WHEN g_params.enable_dml_view THEN | |
g_code_blocks.dml_view || terminator || | |
g_code_blocks.dml_view_trigger || terminator | |
END || | |
CASE WHEN g_params.enable_one_to_one_view THEN | |
g_code_blocks.one_to_one_view || terminator | |
END; | |
END main_return_code; | |
----------------------------------------------------------------------------- | |
PROCEDURE compile_api | |
( | |
p_table_name IN VARCHAR2, | |
p_owner IN VARCHAR2 DEFAULT USER, | |
p_enable_insertion_of_rows IN BOOLEAN DEFAULT TRUE, | |
p_enable_column_defaults IN BOOLEAN DEFAULT FALSE, | |
p_enable_update_of_rows IN BOOLEAN DEFAULT TRUE, | |
p_enable_deletion_of_rows IN BOOLEAN DEFAULT FALSE, | |
p_enable_parameter_prefixes IN BOOLEAN DEFAULT TRUE, | |
p_enable_proc_with_out_params IN BOOLEAN DEFAULT TRUE, | |
p_enable_getter_and_setter IN BOOLEAN DEFAULT TRUE, | |
p_col_prefix_in_method_names IN BOOLEAN DEFAULT TRUE, | |
p_return_row_instead_of_pk IN BOOLEAN DEFAULT FALSE, | |
p_double_quote_names IN BOOLEAN DEFAULT TRUE, | |
p_default_bulk_limit IN INTEGER DEFAULT 1000, | |
p_enable_dml_view IN BOOLEAN DEFAULT FALSE, | |
p_enable_one_to_one_view IN BOOLEAN DEFAULT FALSE, | |
p_api_name IN VARCHAR2 DEFAULT NULL, | |
p_sequence_name IN VARCHAR2 DEFAULT NULL, | |
p_exclude_column_list IN VARCHAR2 DEFAULT NULL, | |
p_audit_column_mappings IN VARCHAR2 DEFAULT NULL, | |
p_audit_user_expression IN VARCHAR2 DEFAULT c_audit_user_expression, | |
p_row_version_column_mapping IN VARCHAR2 DEFAULT NULL, | |
p_enable_custom_defaults IN BOOLEAN DEFAULT FALSE, | |
p_custom_default_values IN XMLTYPE DEFAULT NULL | |
) IS | |
BEGIN | |
util_debug_start_one_run(p_generator_action => 'compile API', p_table_name => p_table_name, p_owner => p_owner); | |
main_init(p_generator_action => 'COMPILE_API', | |
p_table_name => p_table_name, | |
p_owner => p_owner, | |
p_enable_insertion_of_rows => p_enable_insertion_of_rows, | |
p_enable_column_defaults => p_enable_column_defaults, | |
p_enable_update_of_rows => p_enable_update_of_rows, | |
p_enable_deletion_of_rows => p_enable_deletion_of_rows, | |
p_enable_parameter_prefixes => p_enable_parameter_prefixes, | |
p_enable_proc_with_out_params => p_enable_proc_with_out_params, | |
p_enable_getter_and_setter => p_enable_getter_and_setter, | |
p_col_prefix_in_method_names => p_col_prefix_in_method_names, | |
p_return_row_instead_of_pk => p_return_row_instead_of_pk, | |
p_double_quote_names => p_double_quote_names, | |
p_default_bulk_limit => p_default_bulk_limit, | |
p_enable_dml_view => p_enable_dml_view, | |
p_enable_one_to_one_view => p_enable_one_to_one_view, | |
p_api_name => p_api_name, | |
p_sequence_name => p_sequence_name, | |
p_exclude_column_list => p_exclude_column_list, | |
p_audit_column_mappings => p_audit_column_mappings, | |
p_audit_user_expression => p_audit_user_expression, | |
p_row_version_column_mapping => p_row_version_column_mapping, | |
p_enable_custom_defaults => p_enable_custom_defaults, | |
p_custom_default_values => p_custom_default_values); | |
main_generate_code; | |
main_compile_code; | |
util_debug_stop_one_run; | |
END compile_api; | |
----------------------------------------------------------------------------- | |
FUNCTION compile_api_and_get_code | |
( | |
p_table_name IN VARCHAR2, | |
p_owner IN VARCHAR2 DEFAULT USER, | |
p_enable_insertion_of_rows IN BOOLEAN DEFAULT TRUE, | |
p_enable_column_defaults IN BOOLEAN DEFAULT FALSE, | |
p_enable_update_of_rows IN BOOLEAN DEFAULT TRUE, | |
p_enable_deletion_of_rows IN BOOLEAN DEFAULT FALSE, | |
p_enable_parameter_prefixes IN BOOLEAN DEFAULT TRUE, | |
p_enable_proc_with_out_params IN BOOLEAN DEFAULT TRUE, | |
p_enable_getter_and_setter IN BOOLEAN DEFAULT TRUE, | |
p_col_prefix_in_method_names IN BOOLEAN DEFAULT TRUE, | |
p_return_row_instead_of_pk IN BOOLEAN DEFAULT FALSE, | |
p_double_quote_names IN BOOLEAN DEFAULT TRUE, | |
p_default_bulk_limit IN INTEGER DEFAULT 1000, | |
p_enable_dml_view IN BOOLEAN DEFAULT FALSE, | |
p_enable_one_to_one_view IN BOOLEAN DEFAULT FALSE, | |
p_api_name IN VARCHAR2 DEFAULT NULL, | |
p_sequence_name IN VARCHAR2 DEFAULT NULL, | |
p_exclude_column_list IN VARCHAR2 DEFAULT NULL, | |
p_audit_column_mappings IN VARCHAR2 DEFAULT NULL, | |
p_audit_user_expression IN VARCHAR2 DEFAULT c_audit_user_expression, | |
p_row_version_column_mapping IN VARCHAR2 DEFAULT NULL, | |
p_enable_custom_defaults IN BOOLEAN DEFAULT FALSE, | |
p_custom_default_values IN XMLTYPE DEFAULT NULL | |
) RETURN CLOB IS | |
BEGIN | |
util_debug_start_one_run(p_generator_action => 'compile API, get code', | |
p_table_name => p_table_name, | |
p_owner => p_owner); | |
main_init(p_generator_action => 'COMPILE_API_AND_GET_CODE', | |
p_table_name => p_table_name, | |
p_owner => p_owner, | |
p_enable_insertion_of_rows => p_enable_insertion_of_rows, | |
p_enable_column_defaults => p_enable_column_defaults, | |
p_enable_update_of_rows => p_enable_update_of_rows, | |
p_enable_deletion_of_rows => p_enable_deletion_of_rows, | |
p_enable_parameter_prefixes => p_enable_parameter_prefixes, | |
p_enable_proc_with_out_params => p_enable_proc_with_out_params, | |
p_enable_getter_and_setter => p_enable_getter_and_setter, | |
p_col_prefix_in_method_names => p_col_prefix_in_method_names, | |
p_return_row_instead_of_pk => p_return_row_instead_of_pk, | |
p_double_quote_names => p_double_quote_names, | |
p_default_bulk_limit => p_default_bulk_limit, | |
p_enable_dml_view => p_enable_dml_view, | |
p_enable_one_to_one_view => p_enable_one_to_one_view, | |
p_api_name => p_api_name, | |
p_sequence_name => p_sequence_name, | |
p_exclude_column_list => p_exclude_column_list, | |
p_audit_column_mappings => p_audit_column_mappings, | |
p_audit_user_expression => p_audit_user_expression, | |
p_row_version_column_mapping => p_row_version_column_mapping, | |
p_enable_custom_defaults => p_enable_custom_defaults, | |
p_custom_default_values => p_custom_default_values); | |
main_generate_code; | |
main_compile_code; | |
util_debug_stop_one_run; | |
RETURN main_return_code; | |
END compile_api_and_get_code; | |
----------------------------------------------------------------------------- | |
FUNCTION get_code | |
( | |
p_table_name IN VARCHAR2, | |
p_owner IN VARCHAR2 DEFAULT USER, | |
p_enable_insertion_of_rows IN BOOLEAN DEFAULT TRUE, | |
p_enable_column_defaults IN BOOLEAN DEFAULT FALSE, | |
p_enable_update_of_rows IN BOOLEAN DEFAULT TRUE, | |
p_enable_deletion_of_rows IN BOOLEAN DEFAULT FALSE, | |
p_enable_parameter_prefixes IN BOOLEAN DEFAULT TRUE, | |
p_enable_proc_with_out_params IN BOOLEAN DEFAULT TRUE, | |
p_enable_getter_and_setter IN BOOLEAN DEFAULT TRUE, | |
p_col_prefix_in_method_names IN BOOLEAN DEFAULT TRUE, | |
p_return_row_instead_of_pk IN BOOLEAN DEFAULT FALSE, | |
p_double_quote_names IN BOOLEAN DEFAULT TRUE, | |
p_default_bulk_limit IN INTEGER DEFAULT 1000, | |
p_enable_dml_view IN BOOLEAN DEFAULT FALSE, | |
p_enable_one_to_one_view IN BOOLEAN DEFAULT FALSE, | |
p_api_name IN VARCHAR2 DEFAULT NULL, | |
p_sequence_name IN VARCHAR2 DEFAULT NULL, | |
p_exclude_column_list IN VARCHAR2 DEFAULT NULL, | |
p_audit_column_mappings IN VARCHAR2 DEFAULT NULL, | |
p_audit_user_expression IN VARCHAR2 DEFAULT c_audit_user_expression, | |
p_row_version_column_mapping IN VARCHAR2 DEFAULT NULL, | |
p_enable_custom_defaults IN BOOLEAN DEFAULT FALSE, | |
p_custom_default_values IN XMLTYPE DEFAULT NULL | |
) RETURN CLOB IS | |
BEGIN | |
util_debug_start_one_run(p_generator_action => 'get code', p_table_name => p_table_name, p_owner => p_owner); | |
main_init(p_generator_action => 'GET_CODE', | |
p_table_name => p_table_name, | |
p_owner => p_owner, | |
p_enable_insertion_of_rows => p_enable_insertion_of_rows, | |
p_enable_column_defaults => p_enable_column_defaults, | |
p_enable_update_of_rows => p_enable_update_of_rows, | |
p_enable_deletion_of_rows => p_enable_deletion_of_rows, | |
p_enable_parameter_prefixes => p_enable_parameter_prefixes, | |
p_enable_proc_with_out_params => p_enable_proc_with_out_params, | |
p_enable_getter_and_setter => p_enable_getter_and_setter, | |
p_col_prefix_in_method_names => p_col_prefix_in_method_names, | |
p_return_row_instead_of_pk => p_return_row_instead_of_pk, | |
p_double_quote_names => p_double_quote_names, | |
p_default_bulk_limit => p_default_bulk_limit, | |
p_enable_dml_view => p_enable_dml_view, | |
p_enable_one_to_one_view => p_enable_one_to_one_view, | |
p_api_name => p_api_name, | |
p_sequence_name => p_sequence_name, | |
p_exclude_column_list => p_exclude_column_list, | |
p_audit_column_mappings => p_audit_column_mappings, | |
p_audit_user_expression => p_audit_user_expression, | |
p_row_version_column_mapping => p_row_version_column_mapping, | |
p_enable_custom_defaults => p_enable_custom_defaults, | |
p_custom_default_values => p_custom_default_values); | |
main_generate_code; | |
util_debug_stop_one_run; | |
RETURN main_return_code; | |
END get_code; | |
----------------------------------------------------------------------------- | |
FUNCTION view_existing_apis | |
( | |
p_table_name VARCHAR2 DEFAULT NULL, | |
p_owner VARCHAR2 DEFAULT USER | |
) RETURN t_tab_existing_apis | |
PIPELINED IS | |
v_tab t_tab_existing_apis; | |
v_row t_rec_existing_apis; | |
BEGIN | |
-- I was not able to compile without execute immediate - got a strange ORA-03113. | |
-- Direct execution of the statement in SQL tool works :-( | |
EXECUTE IMMEDIATE q'£ | |
-- ATTENTION: query columns need to match the global row definition om_tapigen.g_row_existing_apis. | |
-- Creating a cursor was not possible - database throws an error | |
WITH api_names AS ( | |
SELECT owner, | |
NAME AS api_name | |
FROM all_source | |
WHERE owner = :p_owner | |
AND TYPE = 'PACKAGE' | |
AND line BETWEEN :spec_options_min_line | |
AND :spec_options_max_line | |
AND INSTR (text,'generator="OM_TAPIGEN"') > 0 | |
) -- select * from api_names; | |
, sources AS ( | |
SELECT owner, | |
package_name, | |
XMLTYPE ( | |
NVL (REGEXP_SUBSTR (REPLACE (source_code, '*', NULL), -- replace needed for backward compatibility of old comment style | |
'<options.*>', | |
1, | |
1, | |
'ni'), | |
'<no_data_found/>')) | |
AS options | |
FROM (SELECT owner, | |
NAME AS package_name, | |
LISTAGG (text, ' ') | |
WITHIN GROUP (ORDER BY NAME, line) | |
OVER (PARTITION BY NAME) | |
AS source_code | |
FROM all_source | |
WHERE owner = :p_owner | |
AND name IN (SELECT api_name FROM api_names) | |
AND TYPE = 'PACKAGE' | |
AND line BETWEEN :spec_options_min_line | |
AND :spec_options_max_line) | |
GROUP BY owner, package_name, source_code | |
) -- select * from sources; | |
, apis AS ( | |
SELECT t.owner, | |
x.p_table_name AS table_name, | |
t.package_name, | |
x.generator, | |
x.generator_version, | |
x.generator_action, | |
TO_DATE (x.generated_at,'yyyy-mm-dd hh24:mi:ss') AS generated_at, | |
x.generated_by, | |
x.p_owner, | |
x.p_table_name, | |
x.p_enable_insertion_of_rows, | |
x.p_enable_column_defaults, | |
x.p_enable_update_of_rows, | |
x.p_enable_deletion_of_rows, | |
x.p_enable_parameter_prefixes, | |
x.p_enable_proc_with_out_params, | |
x.p_enable_getter_and_setter, | |
x.p_col_prefix_in_method_names, | |
x.p_return_row_instead_of_pk, | |
x.p_double_quote_names, | |
x.p_default_bulk_limit, | |
x.p_enable_dml_view, | |
x.p_enable_one_to_one_view, | |
x.p_api_name, | |
x.p_sequence_name, | |
x.p_exclude_column_list, | |
x.p_audit_column_mappings, | |
x.p_audit_user_expression, | |
x.p_row_version_column_mapping, | |
x.p_enable_custom_defaults, | |
x.p_custom_default_values | |
FROM sources t | |
CROSS JOIN | |
XMLTABLE ( | |
'/options' | |
PASSING options | |
COLUMNS generator VARCHAR2 (30 CHAR) PATH '@generator', | |
generator_version VARCHAR2 (10 CHAR) PATH '@generator_version', | |
generator_action VARCHAR2 (30 CHAR) PATH '@generator_action', | |
generated_at VARCHAR2 (30 CHAR) PATH '@generated_at', | |
generated_by VARCHAR2 (128 CHAR) PATH '@generated_by', | |
p_owner VARCHAR2 (128 CHAR) PATH '@p_owner', | |
p_table_name VARCHAR2 (128 CHAR) PATH '@p_table_name', | |
p_enable_insertion_of_rows VARCHAR2 (5 CHAR) PATH '@p_enable_insertion_of_rows', | |
p_enable_column_defaults VARCHAR2 (5 CHAR) PATH '@p_enable_column_defaults', | |
p_enable_update_of_rows VARCHAR2 (5 CHAR) PATH '@p_enable_update_of_rows', | |
p_enable_deletion_of_rows VARCHAR2 (5 CHAR) PATH '@p_enable_deletion_of_rows', | |
p_enable_parameter_prefixes VARCHAR2 (5 CHAR) PATH '@p_enable_parameter_prefixes', | |
p_enable_proc_with_out_params VARCHAR2 (5 CHAR) PATH '@p_enable_proc_with_out_params', | |
p_enable_getter_and_setter VARCHAR2 (5 CHAR) PATH '@p_enable_getter_and_setter', | |
p_col_prefix_in_method_names VARCHAR2 (5 CHAR) PATH '@p_col_prefix_in_method_names', | |
p_return_row_instead_of_pk VARCHAR2 (5 CHAR) PATH '@p_return_row_instead_of_pk', | |
p_double_quote_names VARCHAR2 (5 CHAR) PATH '@p_double_quote_names', | |
p_default_bulk_limit INTEGER PATH '@p_default_bulk_limit', | |
p_enable_dml_view VARCHAR2 (5 CHAR) PATH '@p_enable_dml_view', | |
p_enable_one_to_one_view VARCHAR2 (5 CHAR) PATH '@p_enable_one_to_one_view', | |
p_api_name VARCHAR2 (128 CHAR) PATH '@p_api_name', | |
p_sequence_name VARCHAR2 (128 CHAR) PATH '@p_sequence_name', | |
p_exclude_column_list VARCHAR2 (4000 CHAR) PATH '@p_exclude_column_list', | |
p_audit_column_mappings VARCHAR2 (4000 CHAR) PATH '@p_audit_column_mappings', | |
p_audit_user_expression VARCHAR2 (4000 CHAR) PATH '@p_audit_user_expression', | |
p_row_version_column_mapping VARCHAR2 (4000 CHAR) PATH '@p_row_version_column_mapping', | |
p_enable_custom_defaults VARCHAR2 (5 CHAR) PATH '@p_enable_custom_defaults', | |
p_custom_default_values VARCHAR2 (30 CHAR) PATH '@p_custom_default_values') x | |
) -- select * from apis; | |
, objects AS ( | |
SELECT specs.object_name AS package_name, | |
specs.status AS spec_status, | |
specs.last_ddl_time AS spec_last_ddl_time, | |
bodys.status AS body_status, | |
bodys.last_ddl_time AS body_last_ddl_time | |
FROM (SELECT object_name, | |
object_type, | |
status, | |
last_ddl_time | |
FROM all_objects | |
WHERE owner = :p_owner | |
AND object_type = 'PACKAGE' | |
AND object_name IN (SELECT api_name FROM api_names)) | |
specs | |
LEFT JOIN | |
(SELECT object_name, | |
object_type, | |
status, | |
last_ddl_time | |
FROM all_objects | |
WHERE owner = :p_owner | |
AND object_type = 'PACKAGE BODY' | |
AND object_name IN (SELECT api_name FROM api_names)) | |
bodys | |
ON specs.object_name = bodys.object_name | |
AND specs.object_type || ' BODY' = bodys.object_type | |
) -- select * from objects; | |
SELECT NULL AS errors, | |
apis.owner, | |
apis.table_name, | |
objects.package_name, | |
objects.spec_status, | |
objects.spec_last_ddl_time, | |
objects.body_status, | |
objects.body_last_ddl_time, | |
apis.generator, | |
apis.generator_version, | |
apis.generator_action, | |
apis.generated_at, | |
apis.generated_by, | |
apis.p_owner, | |
apis.p_table_name, | |
apis.p_enable_insertion_of_rows, | |
apis.p_enable_column_defaults, | |
apis.p_enable_update_of_rows, | |
apis.p_enable_deletion_of_rows, | |
apis.p_enable_parameter_prefixes, | |
apis.p_enable_proc_with_out_params, | |
apis.p_enable_getter_and_setter, | |
apis.p_col_prefix_in_method_names, | |
apis.p_return_row_instead_of_pk, | |
apis.p_double_quote_names, | |
apis.p_default_bulk_limit, | |
apis.p_enable_dml_view, | |
apis.p_enable_one_to_one_view, | |
apis.p_api_name, | |
apis.p_sequence_name, | |
apis.p_exclude_column_list, | |
apis.p_audit_column_mappings, | |
apis.p_audit_user_expression, | |
apis.p_row_version_column_mapping, | |
apis.p_enable_custom_defaults, | |
apis.p_custom_default_values | |
FROM apis JOIN objects ON apis.package_name = objects.package_name | |
WHERE table_name = NVL ( :p_table_name, table_name) | |
£' | |
BULK COLLECT | |
INTO v_tab | |
USING p_owner, c_spec_options_min_line, c_spec_options_max_line, p_owner, c_spec_options_min_line, c_spec_options_max_line, p_owner, p_owner, p_table_name; | |
IF v_tab.count > 0 THEN | |
FOR i IN v_tab.first .. v_tab.last LOOP | |
PIPE ROW(v_tab(i)); | |
END LOOP; | |
END IF; | |
EXCEPTION | |
WHEN OTHERS THEN | |
v_row.errors := substr('Incomplete resultset! ' || | |
'This is the last correct proccessed row from the pipelined function. ' || | |
'Did you change the params XML in one of the API packages? Original error message: ' || | |
c_lflf || SQLERRM || c_lflf || dbms_utility.format_error_backtrace, | |
1, | |
4000); | |
PIPE ROW(v_row); | |
END view_existing_apis; | |
----------------------------------------------------------------------------- | |
FUNCTION view_naming_conflicts(p_owner VARCHAR2 DEFAULT USER) RETURN t_tab_naming_conflicts | |
PIPELINED IS | |
BEGIN | |
FOR i IN ( | |
WITH | |
ut AS ( | |
SELECT | |
table_name, | |
(SELECT om_tapigen.util_get_ora_max_name_len FROM dual) AS max_name_len | |
FROM | |
all_tables | |
WHERE | |
owner = p_owner | |
), | |
temp AS ( | |
SELECT substr(table_name, 1, max_name_len - 4) || '_API' AS object_name FROM ut | |
UNION ALL | |
SELECT substr(table_name, 1, max_name_len - 6) || '_DML_V' FROM ut | |
UNION ALL | |
SELECT substr(table_name, 1, max_name_len - 6) || '_IOIUD' FROM ut | |
UNION ALL | |
SELECT substr(table_name, 1, max_name_len - 2) || '_V' FROM ut | |
) | |
SELECT | |
uo.object_name, | |
uo.object_type, | |
uo.status, | |
uo.last_ddl_time | |
FROM | |
all_objects uo | |
WHERE | |
owner = p_owner | |
AND uo.object_name IN (SELECT object_name FROM temp) | |
ORDER BY | |
uo.object_name | |
) LOOP | |
PIPE ROW(i); | |
END LOOP; | |
END view_naming_conflicts; | |
END om_tapigen; | |
/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment