Merge pull request #3 from ogobrecht/development

New version from development branch
This commit is contained in:
Ottmar Gobrecht 2019-12-30 21:38:51 +01:00 committed by GitHub
commit 69c2cfbbea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 6663 additions and 3082 deletions

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
*.sql linguist-language=PLSQL

8
.gitignore vendored
View File

@ -1,7 +1,3 @@
node_modules
temp
demo.sql
L_XE*.sql
*.zip
plex_install_SYS.bat
plex_install_APEX_190100.bat
node_modules
test_export

189
README.md
View File

@ -1,4 +1,4 @@
<!-- DO NOT EDIT THIS FILE DIRECTLY - it is generated from source file PLEX.pks -->
<!-- DO NOT EDIT THIS FILE DIRECTLY - it is generated from source file src/PLEX.pks -->
PL/SQL Export Utilities
=======================
@ -8,6 +8,7 @@ PL/SQL Export Utilities
- [Procedure add_query](#add_query)
- [Function queries_to_csv](#queries_to_csv)
- [Function to_zip](#to_zip)
- [Function to_base64](#to_base64)
- [Function view_error_log](#view_error_log)
- [Function view_runtime_log](#view_runtime_log)
@ -15,9 +16,9 @@ PL/SQL Export Utilities
<h2><a id="plex"></a>Package PLEX</h2>
<!----------------------------------->
PLEX was created to be able to quickstart version control for existing (APEX) apps and has currently two main functions called **BackApp** and **Queries_to_CSV**. Queries_to_CSV is used by BackApp as a helper function, but its functionality is also useful standalone.
PLEX was created to be able to quickstart version control for existing Oracle DB projects and has currently two main functions called **BackApp** and **Queries_to_CSV**. Queries_to_CSV is used by BackApp as a helper function, but its functionality is also useful standalone.
See also this resources for more information:
Also see this resources for more information:
- [Blog post on how to getting started](https://ogobrecht.github.io/posts/2018-08-26-plex-plsql-export-utilities)
- [PLEX project page on GitHub](https://github.com/ogobrecht/plex)
@ -29,7 +30,8 @@ DEPENDENCIES
The package itself is independend, but functionality varies on the following conditions:
- For APEX app export: APEX >= 5.1.4 installed
- NOT YET IMPLEMENTED: For ORDS REST service export: ORDS >= FIXME installed
- For ORDS modules export: ORDS >= 18.3 installed (I think package ords_export is included since this version, but I don't know it)
- ATTENTION: There seems to be a bug in ORDS 19.2 which prevents you to export ORDS modules via the package ords_export: https://community.oracle.com/thread/4292776; please see plex_error_log.md, if you miss your ORDS modules after an export - this is no problem of PLEX
INSTALLATION
@ -43,6 +45,16 @@ INSTALLATION
CHANGELOG
- 2.1.0 (2019-12-30)
- Function BackApp:
- New parameter to include ORDS modules (p_include_ords_modules)
- New parameter to remove the outer column list on views, which is added by the compiler (p_object_view_remove_col_list); this was done in the past implicitly and can now be switched off; thanks to twitter.com/JKaschuba for the hint
- Object DDL: Comments for tables and views are now included
- Script templates: Improved export speed by using a base64 encoded zip file instead of a global temporary table to unload the files
- Fixed: Unable to export JAVA objects on systems with 30 character object names; thanks to twitter.com/JKaschuba for the hint
- Fixed: Views appears two times in resulting collection, each double file is postfixed with "_2" and empty
- Fixed: Tables and indices of materialized view definitions are exported (should be hidden)
- New function to_base64: convert BLOB into base64 encoded CLOB - this is helpful to download a BLOB file (like a zip file) with SQL*Plus
- 2.0.2 (2019-08-16)
- Fixed: Function BackApp throws error on large APEX UI install files (ORA-06502: PL/SQL: numeric or value error: character string buffer too small)
- 2.0.1 (2019-07-09)
@ -50,16 +62,17 @@ CHANGELOG
- 2.0.0 (2019-06-20)
- Package is now independend from APEX to be able to export schema object DDL and table data without an APEX installation
- ATTENTION: The return type of functions BackApp and Queries_to_CSV has changed from `apex_t_export_files` to `plex.tab_export_files`
- Function BackApp:
- New parameters to filter for object types
- New parameters to change base paths for backend, frontend and data
- 1.2.1 (2019-03-13)
- Fix script templates: Change old parameters in plex.backapp call
- Fixed: Script templates for function BackApp used old/invalid parameters
- Add install and uninstall scripts for PLEX itself
- 1.2.0 (2018-10-31)
- New: All like/not like parameters are now translated internally with the escape character set to backslash like so `... like 'YourExpression' escape '\'`
- Fixed: Binary data type columns (raw, long_raw, blob, bfile) should no longer break the export data to CSV functionality
- Function BackApp: All like/not like parameters are now translated internally with the escape character set to backslash like so `... like 'YourExpression' escape '\'`
- Function Queries_to_CSV: Binary data type columns (raw, long_raw, blob, bfile) should no longer break the export
- 1.1.0 (2018-09-23)
- Change filter parameter from regular expression to list of like expressions for easier handling
- Function BackApp: Change filter parameter from regular expression to list of like expressions for easier handling
- 1.0.0 (2018-08-26)
- First public release
@ -68,7 +81,7 @@ SIGNATURE
```sql
PACKAGE PLEX AUTHID current_user IS
c_plex_name CONSTANT VARCHAR2(30 CHAR) := 'PLEX - PL/SQL Export Utilities';
c_plex_version CONSTANT VARCHAR2(10 CHAR) := '2.0.2';
c_plex_version CONSTANT VARCHAR2(10 CHAR) := '2.1.0';
c_plex_url CONSTANT VARCHAR2(40 CHAR) := 'https://github.com/ogobrecht/plex';
c_plex_license CONSTANT VARCHAR2(10 CHAR) := 'MIT';
c_plex_license_url CONSTANT VARCHAR2(60 CHAR) := 'https://github.com/ogobrecht/plex/blob/master/LICENSE.txt';
@ -93,9 +106,11 @@ DECLARE
l_file_collection plex.tab_export_files;
BEGIN
l_file_collection := plex.backapp(
p_app_id => 100, -- parameter only available when APEX installed
p_app_id => 100, -- parameter only available when APEX is installed
p_include_ords_modules => true, -- parameter only available when ORDS is installed
p_include_object_ddl => false,
p_include_data => false);
p_include_data => false,
p_include_templates => false);
-- do something with the file collection
FOR i IN 1..l_file_collection.count LOOP
@ -114,9 +129,11 @@ DECLARE
l_zip_file BLOB;
BEGIN
l_zip_file := plex.to_zip(plex.backapp(
p_app_id => 100, -- parameter only available when APEX installed
p_app_id => 100, -- parameter only available when APEX is installed
p_include_ords_modules => true, -- parameter only available when ORDS is installed
p_include_object_ddl => true,
p_include_data => false));
p_include_data => false,
p_include_templates => true));
-- do something with the zip file
-- Your code here...
END;
@ -132,50 +149,50 @@ WITH
FUNCTION backapp RETURN BLOB IS
BEGIN
RETURN plex.to_zip(plex.backapp(
-- All parameters are optional and shown with their defaults
-- App related options (only available, when APEX is installed):
p_app_id => NULL,
p_app_date => true,
p_app_public_reports => true,
p_app_private_reports => false,
p_app_notifications => false,
p_app_translations => true,
p_app_pkg_app_mapping => false,
p_app_original_ids => false,
p_app_subscriptions => true,
p_app_comments => true,
p_app_supporting_objects => NULL,
p_app_include_single_file => false,
p_app_build_status_run_only => false,
-- Object related options:
p_include_object_ddl => false,
p_object_type_like => NULL,
p_object_type_not_like => NULL,
p_object_name_like => NULL,
p_object_name_not_like => NULL,
-- Data related options:
p_app_id => 100, -- parameter only available when APEX is installed
p_include_ords_modules => true, -- parameter only available when ORDS is installed
p_include_object_ddl => true,
p_include_data => false,
p_data_as_of_minutes_ago => 0,
p_data_max_rows => 1000,
p_data_table_name_like => NULL,
p_data_table_name_not_like => NULL,
-- Miscellaneous options:
p_include_templates => true,
p_include_runtime_log => true,
p_include_error_log => true,
p_base_path_backend => 'app_backend',
p_base_path_frontend => 'app_frontend',
p_base_path_data => 'app_data'));
p_include_templates => true));
END backapp;
SELECT backapp FROM dual;
```
EXAMPLE ZIP FILE SQL*Plus
```sql
-- SQL*Plus can only handle CLOBs, no BLOBs - so we are forced to create a CLOB
-- for spooling the content to the client disk. You need to decode the base64
-- encoded file before you are able to unzip the content. Also see this blog
-- post how to do this on the different operating systems:
-- https://www.igorkromin.net/index.php/2017/04/26/base64-encode-or-decode-on-the-command-line-without-installing-extra-tools-on-linux-windows-or-macos/
-- Example Windows: certutil -decode app_100.zip.base64 app_100.zip
-- Example Mac: base64 -D -i app_100.zip.base64 -o app_100.zip
-- Example Linux: base64 -d app_100.zip.base64 > app_100.zip
set verify off feedback off heading off termout off
set trimout on trimspool on pagesize 0 linesize 5000 long 100000000 longchunksize 32767
whenever sqlerror exit sql.sqlcode rollback
variable contents clob
BEGIN
:contents := plex.to_base64(plex.to_zip(plex.backapp(
p_app_id => 100, -- parameter only available when APEX is installed
p_include_ords_modules => true, -- parameter only available when ORDS is installed
p_include_object_ddl => true,
p_include_data => false,
p_include_templates => true)));
END;
/
spool "app_100.zip.base64"
print contents
spool off
```
SIGNATURE
```sql
FUNCTION backapp (
$if $$apex_installed $then
-- App related options:
-- APEX App:
p_app_id IN NUMBER DEFAULT null, -- If null, we simply skip the APEX app export.
p_app_date IN BOOLEAN DEFAULT true, -- If true, include export date and time in the result.
p_app_public_reports IN BOOLEAN DEFAULT true, -- If true, include public reports that a user saved.
@ -190,25 +207,31 @@ FUNCTION backapp (
p_app_include_single_file IN BOOLEAN DEFAULT false, -- If true, the single sql install file is also included beside the splitted files.
p_app_build_status_run_only IN BOOLEAN DEFAULT false, -- If true, the build status of the app will be overwritten to RUN_ONLY.
$end
-- Object related options:
$if $$ords_installed $then
-- ORDS Modules:
p_include_ords_modules IN BOOLEAN DEFAULT false, -- If true, include ORDS modules of current user/schema.
$end
-- Schema Objects:
p_include_object_ddl IN BOOLEAN DEFAULT false, -- If true, include DDL of current user/schema and all its objects.
p_object_type_like IN VARCHAR2 DEFAULT null, -- A comma separated list of like expressions to filter the objects - example: '%BODY,JAVA%' will be translated to: ... from user_objects where ... and (object_type like '%BODY' escape '\' or object_type like 'JAVA%' escape '\').
p_object_type_not_like IN VARCHAR2 DEFAULT null, -- A comma separated list of not like expressions to filter the objects - example: '%BODY,JAVA%' will be translated to: ... from user_objects where ... and (object_type not like '%BODY' escape '\' and object_type not like 'JAVA%' escape '\').
p_object_name_like IN VARCHAR2 DEFAULT null, -- A comma separated list of like expressions to filter the objects - example: 'EMP%,DEPT%' will be translated to: ... from user_objects where ... and (object_name like 'EMP%' escape '\' or object_name like 'DEPT%' escape '\').
p_object_name_not_like IN VARCHAR2 DEFAULT null, -- A comma separated list of not like expressions to filter the objects - example: 'EMP%,DEPT%' will be translated to: ... from user_objects where ... and (object_name not like 'EMP%' escape '\' and object_name not like 'DEPT%' escape '\').
-- Data related options:
p_object_view_remove_col_list IN BOOLEAN DEFAULT true, -- If true, the outer column list, added by Oracle on views during compilation, is removed
-- Table Data:
p_include_data IN BOOLEAN DEFAULT false, -- If true, include CSV data of each table.
p_data_as_of_minutes_ago IN NUMBER DEFAULT 0, -- Read consistent data with the resulting timestamp(SCN).
p_data_max_rows IN NUMBER DEFAULT 1000, -- Maximum number of rows per table.
p_data_table_name_like IN VARCHAR2 DEFAULT null, -- A comma separated list of like expressions to filter the tables - example: 'EMP%,DEPT%' will be translated to: where ... and (table_name like 'EMP%' escape '\' or table_name like 'DEPT%' escape '\').
p_data_table_name_not_like IN VARCHAR2 DEFAULT null, -- A comma separated list of not like expressions to filter the tables - example: 'EMP%,DEPT%' will be translated to: where ... and (table_name not like 'EMP%' escape '\' and table_name not like 'DEPT%' escape '\').
-- Miscellaneous options:
-- General Options:
p_include_templates IN BOOLEAN DEFAULT true, -- If true, include templates for README.md, export and install scripts.
p_include_runtime_log IN BOOLEAN DEFAULT true, -- If true, generate file plex_runtime_log.md with detailed runtime infos.
p_include_error_log IN BOOLEAN DEFAULT true, -- If true, generate file plex_error_log.md with detailed error messages.
p_base_path_backend IN VARCHAR2 DEFAULT 'app_backend', -- The base path in the project root for the database DDL files.
p_base_path_frontend IN VARCHAR2 DEFAULT 'app_frontend', -- The base path in the project root for the APEX UI install files.
p_base_path_data IN VARCHAR2 DEFAULT 'app_data') -- The base path in the project root for the data files.
p_base_path_backend IN VARCHAR2 DEFAULT 'app_backend', -- The base path in the project root for the Schema objects.
p_base_path_frontend IN VARCHAR2 DEFAULT 'app_frontend', -- The base path in the project root for the APEX app.
p_base_path_web_services IN VARCHAR2 DEFAULT 'app_web_services', -- The base path in the project root for the ORDS modules.
p_base_path_data IN VARCHAR2 DEFAULT 'app_data') -- The base path in the project root for the table data.
RETURN tab_export_files;
```
@ -270,7 +293,7 @@ END;
/
```
EXPORT EXPORT ZIP FILE PL/SQL
EXAMPLE EXPORT ZIP FILE PL/SQL
```sql
DECLARE
@ -312,6 +335,39 @@ WITH
SELECT queries_to_csv_zip FROM dual;
```
EXAMPLE ZIP FILE SQL*Plus
```sql
-- SQL*Plus can only handle CLOBs, no BLOBs - so we are forced to create a CLOB
-- for spooling the content to the client disk. You need to decode the base64
-- encoded file before you are able to unzip the content. Also see this blog
-- post how to do this on the different operating systems:
-- https://www.igorkromin.net/index.php/2017/04/26/base64-encode-or-decode-on-the-command-line-without-installing-extra-tools-on-linux-windows-or-macos/
-- Example Windows: certutil -decode metadata.zip.base64 metadata.zip
-- Example Mac: base64 -D -i metadata.zip.base64 -o metadata.zip
-- Example Linux: base64 -d metadata.zip.base64 > metadata.zip
set verify off feedback off heading off termout off
set trimout on trimspool on pagesize 0 linesize 5000 long 100000000 longchunksize 32767
whenever sqlerror exit sql.sqlcode rollback
variable contents clob
BEGIN
--fill the queries array
plex.add_query(
p_query => 'select * from user_tables',
p_file_name => 'user_tables');
plex.add_query(
p_query => 'select * from user_tab_columns',
p_file_name => 'user_tab_columns',
p_max_rows => 10000);
-- process the queries
:contents := plex.to_base64(plex.to_zip(plex.queries_to_csv));
END;
/
spool "metadata.zip.base64"
print contents
spool off
```
SIGNATURE
```sql
@ -352,6 +408,31 @@ RETURN BLOB;
```
<h2><a id="to_base64"></a>Function to_base64</h2>
<!---------------------------------------------->
Encodes a BLOB into a Base64 CLOB for transfers over a network (like with SQL*Plus). For encoding on the client side see [this blog article](https://www.igorkromin.net/index.php/2017/04/26/base64-encode-or-decode-on-the-command-line-without-installing-extra-tools-on-linux-windows-or-macos/).
```sql
DECLARE
l_clob CLOB;
BEGIN
l_clob := plex.to_base64(plex.to_zip(plex.backapp(
p_app_id => 100,
p_include_object_ddl => true)));
-- do something with the clob...
END;
```
SIGNATURE
```sql
FUNCTION to_base64(
p_blob IN BLOB) -- The BLOB to convert.
RETURN CLOB;
```
<h2><a id="view_error_log"></a>Function view_error_log</h2>
<!-------------------------------------------------------->

82
package-lock.json generated
View File

@ -542,7 +542,8 @@
},
"ansi-regex": {
"version": "2.1.1",
"bundled": true
"bundled": true,
"optional": true
},
"aproba": {
"version": "1.2.0",
@ -560,11 +561,13 @@
},
"balanced-match": {
"version": "1.0.0",
"bundled": true
"bundled": true,
"optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -577,15 +580,18 @@
},
"code-point-at": {
"version": "1.1.0",
"bundled": true
"bundled": true,
"optional": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true
"bundled": true,
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true
"bundled": true,
"optional": true
},
"core-util-is": {
"version": "1.0.2",
@ -688,7 +694,8 @@
},
"inherits": {
"version": "2.0.3",
"bundled": true
"bundled": true,
"optional": true
},
"ini": {
"version": "1.3.5",
@ -698,6 +705,7 @@
"is-fullwidth-code-point": {
"version": "1.0.0",
"bundled": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@ -710,17 +718,20 @@
"minimatch": {
"version": "3.0.4",
"bundled": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "0.0.8",
"bundled": true
"bundled": true,
"optional": true
},
"minipass": {
"version": "2.3.5",
"bundled": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@ -737,6 +748,7 @@
"mkdirp": {
"version": "0.5.1",
"bundled": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@ -809,7 +821,8 @@
},
"number-is-nan": {
"version": "1.0.1",
"bundled": true
"bundled": true,
"optional": true
},
"object-assign": {
"version": "4.1.1",
@ -819,6 +832,7 @@
"once": {
"version": "1.4.0",
"bundled": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@ -894,7 +908,8 @@
},
"safe-buffer": {
"version": "5.1.2",
"bundled": true
"bundled": true,
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
@ -924,6 +939,7 @@
"string-width": {
"version": "1.0.2",
"bundled": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@ -941,6 +957,7 @@
"strip-ansi": {
"version": "3.0.1",
"bundled": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@ -979,11 +996,13 @@
},
"wrappy": {
"version": "1.0.2",
"bundled": true
"bundled": true,
"optional": true
},
"yallist": {
"version": "3.0.3",
"bundled": true
"bundled": true,
"optional": true
}
}
},
@ -1327,9 +1346,9 @@
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
},
"mixin-deep": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
"integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==",
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
"integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
"requires": {
"for-in": "^1.0.2",
"is-extendable": "^1.0.1"
@ -1640,9 +1659,9 @@
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
},
"set-value": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz",
"integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
"integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
"requires": {
"extend-shallow": "^2.0.1",
"is-extendable": "^0.1.1",
@ -1893,35 +1912,14 @@
}
},
"union-value": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
"integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
"integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
"requires": {
"arr-union": "^3.1.0",
"get-value": "^2.0.6",
"is-extendable": "^0.1.1",
"set-value": "^0.4.3"
},
"dependencies": {
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"requires": {
"is-extendable": "^0.1.0"
}
},
"set-value": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
"integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
"requires": {
"extend-shallow": "^2.0.1",
"is-extendable": "^0.1.1",
"is-plain-object": "^2.0.1",
"to-object-path": "^0.3.0"
}
}
"set-value": "^2.0.1"
}
},
"unset-value": {

View File

@ -6,8 +6,10 @@
"url": "https://github.com/ogobrecht/plex.git"
},
"scripts": {
"build:docs": "npx ploc --in PLEX.pks --out README.md",
"watch:docs": "chokidar PLEX.pks package.json --initial -c \"npm run build:docs\""
"prebuild": "npx ploc --in src/PLEX.pks --out README.md",
"build": "node src/build.js",
"postbuild": "echo exit | sqlplus -S demo/oracle@localhost:1521/xepdb1 @plex_install.sql",
"watch": "chokidar src/PLEX.pks src/PLEX.pkb src/plex_install.sql --initial -c \"npm run build\""
},
"dependencies": {
"chokidar-cli": "^1.2.2",

File diff suppressed because it is too large Load Diff

812
PLEX.pkb → src/PLEX.pkb Executable file → Normal file

File diff suppressed because it is too large Load Diff

181
PLEX.pks → src/PLEX.pks Executable file → Normal file
View File

@ -1,6 +1,6 @@
CREATE OR REPLACE PACKAGE PLEX AUTHID current_user IS
c_plex_name CONSTANT VARCHAR2(30 CHAR) := 'PLEX - PL/SQL Export Utilities';
c_plex_version CONSTANT VARCHAR2(10 CHAR) := '2.0.2';
c_plex_version CONSTANT VARCHAR2(10 CHAR) := '2.1.0';
c_plex_url CONSTANT VARCHAR2(40 CHAR) := 'https://github.com/ogobrecht/plex';
c_plex_license CONSTANT VARCHAR2(10 CHAR) := 'MIT';
c_plex_license_url CONSTANT VARCHAR2(60 CHAR) := 'https://github.com/ogobrecht/plex/blob/master/LICENSE.txt';
@ -9,9 +9,9 @@ c_plex_author CONSTANT VARCHAR2(20 CHAR) := 'Ottmar Gobrecht';
PL/SQL Export Utilities
=======================
PLEX was created to be able to quickstart version control for existing (APEX) apps and has currently two main functions called **BackApp** and **Queries_to_CSV**. Queries_to_CSV is used by BackApp as a helper function, but its functionality is also useful standalone.
PLEX was created to be able to quickstart version control for existing Oracle DB projects and has currently two main functions called **BackApp** and **Queries_to_CSV**. Queries_to_CSV is used by BackApp as a helper function, but its functionality is also useful standalone.
See also this resources for more information:
Also see this resources for more information:
- [Blog post on how to getting started](https://ogobrecht.github.io/posts/2018-08-26-plex-plsql-export-utilities)
- [PLEX project page on GitHub](https://github.com/ogobrecht/plex)
@ -23,7 +23,8 @@ DEPENDENCIES
The package itself is independend, but functionality varies on the following conditions:
- For APEX app export: APEX >= 5.1.4 installed
- NOT YET IMPLEMENTED: For ORDS REST service export: ORDS >= FIXME installed
- For ORDS modules export: ORDS >= 18.3 installed (I think package ords_export is included since this version, but I don't know it)
- ATTENTION: There seems to be a bug in ORDS 19.2 which prevents you to export ORDS modules via the package ords_export: https://community.oracle.com/thread/4292776; please see plex_error_log.md, if you miss your ORDS modules after an export - this is no problem of PLEX
INSTALLATION
@ -37,6 +38,16 @@ INSTALLATION
CHANGELOG
- 2.1.0 (2019-12-30)
- Function BackApp:
- New parameter to include ORDS modules (p_include_ords_modules)
- New parameter to remove the outer column list on views, which is added by the compiler (p_object_view_remove_col_list); this was done in the past implicitly and can now be switched off; thanks to twitter.com/JKaschuba for the hint
- Object DDL: Comments for tables and views are now included
- Script templates: Improved export speed by using a base64 encoded zip file instead of a global temporary table to unload the files
- Fixed: Unable to export JAVA objects on systems with 30 character object names; thanks to twitter.com/JKaschuba for the hint
- Fixed: Views appears two times in resulting collection, each double file is postfixed with "_2" and empty
- Fixed: Tables and indices of materialized view definitions are exported (should be hidden)
- New function to_base64: convert BLOB into base64 encoded CLOB - this is helpful to download a BLOB file (like a zip file) with SQL*Plus
- 2.0.2 (2019-08-16)
- Fixed: Function BackApp throws error on large APEX UI install files (ORA-06502: PL/SQL: numeric or value error: character string buffer too small)
- 2.0.1 (2019-07-09)
@ -44,16 +55,17 @@ CHANGELOG
- 2.0.0 (2019-06-20)
- Package is now independend from APEX to be able to export schema object DDL and table data without an APEX installation
- ATTENTION: The return type of functions BackApp and Queries_to_CSV has changed from `apex_t_export_files` to `plex.tab_export_files`
- Function BackApp:
- New parameters to filter for object types
- New parameters to change base paths for backend, frontend and data
- 1.2.1 (2019-03-13)
- Fix script templates: Change old parameters in plex.backapp call
- Fixed: Script templates for function BackApp used old/invalid parameters
- Add install and uninstall scripts for PLEX itself
- 1.2.0 (2018-10-31)
- New: All like/not like parameters are now translated internally with the escape character set to backslash like so `... like 'YourExpression' escape '\'`
- Fixed: Binary data type columns (raw, long_raw, blob, bfile) should no longer break the export data to CSV functionality
- Function BackApp: All like/not like parameters are now translated internally with the escape character set to backslash like so `... like 'YourExpression' escape '\'`
- Function Queries_to_CSV: Binary data type columns (raw, long_raw, blob, bfile) should no longer break the export
- 1.1.0 (2018-09-23)
- Change filter parameter from regular expression to list of like expressions for easier handling
- Function BackApp: Change filter parameter from regular expression to list of like expressions for easier handling
- 1.0.0 (2018-08-26)
- First public release
**/
@ -98,7 +110,7 @@ TYPE tab_vc1k IS TABLE OF VARCHAR2(1024) INDEX BY BINARY_INTEGER;
FUNCTION backapp (
$if $$apex_installed $then
-- App related options:
-- APEX App:
p_app_id IN NUMBER DEFAULT null, -- If null, we simply skip the APEX app export.
p_app_date IN BOOLEAN DEFAULT true, -- If true, include export date and time in the result.
p_app_public_reports IN BOOLEAN DEFAULT true, -- If true, include public reports that a user saved.
@ -113,25 +125,31 @@ FUNCTION backapp (
p_app_include_single_file IN BOOLEAN DEFAULT false, -- If true, the single sql install file is also included beside the splitted files.
p_app_build_status_run_only IN BOOLEAN DEFAULT false, -- If true, the build status of the app will be overwritten to RUN_ONLY.
$end
-- Object related options:
$if $$ords_installed $then
-- ORDS Modules:
p_include_ords_modules IN BOOLEAN DEFAULT false, -- If true, include ORDS modules of current user/schema.
$end
-- Schema Objects:
p_include_object_ddl IN BOOLEAN DEFAULT false, -- If true, include DDL of current user/schema and all its objects.
p_object_type_like IN VARCHAR2 DEFAULT null, -- A comma separated list of like expressions to filter the objects - example: '%BODY,JAVA%' will be translated to: ... from user_objects where ... and (object_type like '%BODY' escape '\' or object_type like 'JAVA%' escape '\').
p_object_type_not_like IN VARCHAR2 DEFAULT null, -- A comma separated list of not like expressions to filter the objects - example: '%BODY,JAVA%' will be translated to: ... from user_objects where ... and (object_type not like '%BODY' escape '\' and object_type not like 'JAVA%' escape '\').
p_object_name_like IN VARCHAR2 DEFAULT null, -- A comma separated list of like expressions to filter the objects - example: 'EMP%,DEPT%' will be translated to: ... from user_objects where ... and (object_name like 'EMP%' escape '\' or object_name like 'DEPT%' escape '\').
p_object_name_not_like IN VARCHAR2 DEFAULT null, -- A comma separated list of not like expressions to filter the objects - example: 'EMP%,DEPT%' will be translated to: ... from user_objects where ... and (object_name not like 'EMP%' escape '\' and object_name not like 'DEPT%' escape '\').
-- Data related options:
p_object_view_remove_col_list IN BOOLEAN DEFAULT true, -- If true, the outer column list, added by Oracle on views during compilation, is removed
-- Table Data:
p_include_data IN BOOLEAN DEFAULT false, -- If true, include CSV data of each table.
p_data_as_of_minutes_ago IN NUMBER DEFAULT 0, -- Read consistent data with the resulting timestamp(SCN).
p_data_max_rows IN NUMBER DEFAULT 1000, -- Maximum number of rows per table.
p_data_table_name_like IN VARCHAR2 DEFAULT null, -- A comma separated list of like expressions to filter the tables - example: 'EMP%,DEPT%' will be translated to: where ... and (table_name like 'EMP%' escape '\' or table_name like 'DEPT%' escape '\').
p_data_table_name_not_like IN VARCHAR2 DEFAULT null, -- A comma separated list of not like expressions to filter the tables - example: 'EMP%,DEPT%' will be translated to: where ... and (table_name not like 'EMP%' escape '\' and table_name not like 'DEPT%' escape '\').
-- Miscellaneous options:
-- General Options:
p_include_templates IN BOOLEAN DEFAULT true, -- If true, include templates for README.md, export and install scripts.
p_include_runtime_log IN BOOLEAN DEFAULT true, -- If true, generate file plex_runtime_log.md with detailed runtime infos.
p_include_error_log IN BOOLEAN DEFAULT true, -- If true, generate file plex_error_log.md with detailed error messages.
p_base_path_backend IN VARCHAR2 DEFAULT 'app_backend', -- The base path in the project root for the database DDL files.
p_base_path_frontend IN VARCHAR2 DEFAULT 'app_frontend', -- The base path in the project root for the APEX UI install files.
p_base_path_data IN VARCHAR2 DEFAULT 'app_data') -- The base path in the project root for the data files.
p_base_path_backend IN VARCHAR2 DEFAULT 'app_backend', -- The base path in the project root for the Schema objects.
p_base_path_frontend IN VARCHAR2 DEFAULT 'app_frontend', -- The base path in the project root for the APEX app.
p_base_path_web_services IN VARCHAR2 DEFAULT 'app_web_services', -- The base path in the project root for the ORDS modules.
p_base_path_data IN VARCHAR2 DEFAULT 'app_data') -- The base path in the project root for the table data.
RETURN tab_export_files;
/**
Get a file collection of an APEX application (or the current user/schema only) including:
@ -148,9 +166,11 @@ DECLARE
l_file_collection plex.tab_export_files;
BEGIN
l_file_collection := plex.backapp(
p_app_id => 100, -- parameter only available when APEX installed
p_app_id => 100, -- parameter only available when APEX is installed
p_include_ords_modules => true, -- parameter only available when ORDS is installed
p_include_object_ddl => false,
p_include_data => false);
p_include_data => false,
p_include_templates => false);
-- do something with the file collection
FOR i IN 1..l_file_collection.count LOOP
@ -169,9 +189,11 @@ DECLARE
l_zip_file BLOB;
BEGIN
l_zip_file := plex.to_zip(plex.backapp(
p_app_id => 100, -- parameter only available when APEX installed
p_app_id => 100, -- parameter only available when APEX is installed
p_include_ords_modules => true, -- parameter only available when ORDS is installed
p_include_object_ddl => true,
p_include_data => false));
p_include_data => false,
p_include_templates => true));
-- do something with the zip file
-- Your code here...
END;
@ -187,43 +209,43 @@ WITH
FUNCTION backapp RETURN BLOB IS
BEGIN
RETURN plex.to_zip(plex.backapp(
-- All parameters are optional and shown with their defaults
-- App related options (only available, when APEX is installed):
p_app_id => NULL,
p_app_date => true,
p_app_public_reports => true,
p_app_private_reports => false,
p_app_notifications => false,
p_app_translations => true,
p_app_pkg_app_mapping => false,
p_app_original_ids => false,
p_app_subscriptions => true,
p_app_comments => true,
p_app_supporting_objects => NULL,
p_app_include_single_file => false,
p_app_build_status_run_only => false,
-- Object related options:
p_include_object_ddl => false,
p_object_type_like => NULL,
p_object_type_not_like => NULL,
p_object_name_like => NULL,
p_object_name_not_like => NULL,
-- Data related options:
p_app_id => 100, -- parameter only available when APEX is installed
p_include_ords_modules => true, -- parameter only available when ORDS is installed
p_include_object_ddl => true,
p_include_data => false,
p_data_as_of_minutes_ago => 0,
p_data_max_rows => 1000,
p_data_table_name_like => NULL,
p_data_table_name_not_like => NULL,
-- Miscellaneous options:
p_include_templates => true,
p_include_runtime_log => true,
p_include_error_log => true,
p_base_path_backend => 'app_backend',
p_base_path_frontend => 'app_frontend',
p_base_path_data => 'app_data'));
p_include_templates => true));
END backapp;
SELECT backapp FROM dual;
```
EXAMPLE ZIP FILE SQL*Plus
```sql
-- SQL*Plus can only handle CLOBs, no BLOBs - so we are forced to create a CLOB
-- for spooling the content to the client disk. You need to decode the base64
-- encoded file before you are able to unzip the content. Also see this blog
-- post how to do this on the different operating systems:
-- https://www.igorkromin.net/index.php/2017/04/26/base64-encode-or-decode-on-the-command-line-without-installing-extra-tools-on-linux-windows-or-macos/
-- Example Windows: certutil -decode app_100.zip.base64 app_100.zip
-- Example Mac: base64 -D -i app_100.zip.base64 -o app_100.zip
-- Example Linux: base64 -d app_100.zip.base64 > app_100.zip
set verify off feedback off heading off termout off
set trimout on trimspool on pagesize 0 linesize 5000 long 100000000 longchunksize 32767
whenever sqlerror exit sql.sqlcode rollback
variable contents clob
BEGIN
:contents := plex.to_base64(plex.to_zip(plex.backapp(
p_app_id => 100, -- parameter only available when APEX is installed
p_include_ords_modules => true, -- parameter only available when ORDS is installed
p_include_object_ddl => true,
p_include_data => false,
p_include_templates => true)));
END;
{{/}}
spool "app_100.zip.base64"
print contents
spool off
```
**/
@ -285,7 +307,7 @@ END;
{{/}}
```
EXPORT EXPORT ZIP FILE PL/SQL
EXAMPLE EXPORT ZIP FILE PL/SQL
```sql
DECLARE
@ -326,6 +348,39 @@ WITH
END queries_to_csv_zip;
SELECT queries_to_csv_zip FROM dual;
```
EXAMPLE ZIP FILE SQL*Plus
```sql
-- SQL*Plus can only handle CLOBs, no BLOBs - so we are forced to create a CLOB
-- for spooling the content to the client disk. You need to decode the base64
-- encoded file before you are able to unzip the content. Also see this blog
-- post how to do this on the different operating systems:
-- https://www.igorkromin.net/index.php/2017/04/26/base64-encode-or-decode-on-the-command-line-without-installing-extra-tools-on-linux-windows-or-macos/
-- Example Windows: certutil -decode metadata.zip.base64 metadata.zip
-- Example Mac: base64 -D -i metadata.zip.base64 -o metadata.zip
-- Example Linux: base64 -d metadata.zip.base64 > metadata.zip
set verify off feedback off heading off termout off
set trimout on trimspool on pagesize 0 linesize 5000 long 100000000 longchunksize 32767
whenever sqlerror exit sql.sqlcode rollback
variable contents clob
BEGIN
--fill the queries array
plex.add_query(
p_query => 'select * from user_tables',
p_file_name => 'user_tables');
plex.add_query(
p_query => 'select * from user_tab_columns',
p_file_name => 'user_tab_columns',
p_max_rows => 10000);
-- process the queries
:contents := plex.to_base64(plex.to_zip(plex.queries_to_csv));
END;
{{/}}
spool "metadata.zip.base64"
print contents
spool off
```
**/
@ -348,7 +403,25 @@ BEGIN
-- do something with the zip file...
END;
```
***/
**/
FUNCTION to_base64(
p_blob IN BLOB) -- The BLOB to convert.
RETURN CLOB;
/**
Encodes a BLOB into a Base64 CLOB for transfers over a network (like with SQL*Plus). For encoding on the client side see [this blog article](https://www.igorkromin.net/index.php/2017/04/26/base64-encode-or-decode-on-the-command-line-without-installing-extra-tools-on-linux-windows-or-macos/).
```sql
DECLARE
l_clob CLOB;
BEGIN
l_clob := plex.to_base64(plex.to_zip(plex.backapp(
p_app_id => 100,
p_include_object_ddl => true)));
-- do something with the clob...
END;
```
**/
FUNCTION view_error_log RETURN tab_error_log PIPELINED;
/**

17
src/build.js Normal file
View File

@ -0,0 +1,17 @@
var fs = require('fs');
var spec =
fs.writeFileSync(
'plex_install.sql',
fs.readFileSync('src/plex_install.sql', 'utf8')
.replace('@plex.pks', function(){return fs.readFileSync('src/plex.pks', 'utf8')})
.replace('@plex.pkb', function(){return fs.readFileSync('src/plex.pkb', 'utf8')})
// Read what this function thing is doing, without it we get wrong results.
// We have dollar signs in our package body text - the last answer explains:
// https://stackoverflow.com/questions/9423722/string-replace-weird-behavior-when-using-dollar-sign-as-replacement
);
fs.copyFileSync(
'src/plex_uninstall.sql',
'plex_uninstall.sql'
);

48
src/plex_install.sql Normal file
View File

@ -0,0 +1,48 @@
set define off feedback off
whenever sqlerror exit sql.sqlcode rollback
prompt
prompt Installing PL/SQL Export Utilities
prompt ==================================
prompt Set compiler flags
DECLARE
v_apex_installed VARCHAR2(5) := 'FALSE'; -- Do not change (is set dynamically).
v_ords_installed VARCHAR2(5) := 'FALSE'; -- Do not change (is set dynamically).
v_utils_public VARCHAR2(5) := 'FALSE'; -- Make utilities public available (for testing or other usages).
v_debug_on VARCHAR2(5) := 'FALSE'; -- Object DDL: extract only one object per type to find problematic ones and save time in big schemas like APEX_XXX.
BEGIN
FOR i IN (SELECT *
FROM all_objects
WHERE object_type = 'SYNONYM'
AND object_name = 'APEX_EXPORT') LOOP
v_apex_installed := 'TRUE';
END LOOP;
FOR i IN (SELECT *
FROM all_objects
WHERE object_type = 'SYNONYM'
AND object_name = 'ORDS_EXPORT') LOOP
v_ords_installed := 'TRUE';
END LOOP;
-- Show unset compiler flags as errors (results for example in errors like "PLW-06003: unknown inquiry directive '$$UTILS_PUBLIC'")
EXECUTE IMMEDIATE 'alter session set plsql_warnings = ''ENABLE:6003''';
-- Finally set compiler flags
EXECUTE IMMEDIATE 'alter session set plsql_ccflags = '''
|| 'apex_installed:' || v_apex_installed || ','
|| 'ords_installed:' || v_ords_installed || ','
|| 'utils_public:' || v_utils_public || ','
|| 'debug_on:' || v_debug_on || '''';
END;
/
prompt Compile package plex (spec)
@plex.pks
show errors
prompt Compile package plex (body)
@plex.pkb
show errors
prompt ==================================
prompt Installation Done
prompt

View File

@ -0,0 +1,57 @@
set define off feedback off
whenever sqlerror exit sql.sqlcode rollback
prompt
prompt Installing PL/SQL Export Utilities
prompt ==================================
prompt Show unset compiler flags as errors (results for example in errors like "PLW-06003: unknown inquiry directive '$$UTILS_PUBLIC'"
alter session set plsql_warnings = 'ENABLE:6003';
prompt ---
prompt Set compiler flags to apex_installed:false, ords_installed:false, utils_public:false, debug_on:false
alter session set plsql_ccflags = 'apex_installed:false, ords_installed:false, utils_public:false, debug_on:false';
prompt Compile package plex (spec)
@plex.pks
show errors
prompt Compile package plex (body)
@plex.pkb
show errors
prompt ---
prompt Set compiler flags: apex_installed:true, ords_installed:false, utils_public:false, debug_on:false
alter session set plsql_ccflags = 'apex_installed:true, ords_installed:false, utils_public:false, debug_on:false';
prompt Compile package plex (spec)
@plex.pks
show errors
prompt Compile package plex (body)
@plex.pkb
show errors
prompt ---
prompt Set compiler flags: apex_installed:false, ords_installed:true, utils_public:false, debug_on:false
alter session set plsql_ccflags = 'apex_installed:false, ords_installed:true, utils_public:false, debug_on:false';
prompt Compile package plex (spec)
@plex.pks
show errors
prompt Compile package plex (body)
@plex.pkb
show errors
prompt ---
prompt Set compiler flags: apex_installed:true, ords_installed:true, utils_public:false, debug_on:false
alter session set plsql_ccflags = 'apex_installed:true, ords_installed:true, utils_public:false, debug_on:false';
prompt Compile package plex (spec)
@plex.pks
show errors
prompt Compile package plex (body)
@plex.pkb
show errors
prompt ==================================
prompt Installation Done
prompt

18
src/plex_test.sql Normal file
View File

@ -0,0 +1,18 @@
-- Inline function because of boolean parameters (needs Oracle 12c or higher).
-- Alternative create a helper function and call that in a SQL context.
WITH
FUNCTION backapp RETURN BLOB IS
BEGIN
RETURN plex.to_zip(plex.backapp(
p_app_id => 100,
p_include_object_ddl => true,
p_include_ords_modules => true,
p_include_data => true,
p_include_templates => true));
END backapp;
SELECT backapp FROM dual;
/
select * from table(plex.view_runtime_log);

30
src/plex_uninstall.sql Normal file
View File

@ -0,0 +1,30 @@
SET DEFINE OFF FEEDBACK OFF
WHENEVER SQLERROR EXIT sql.sqlcode ROLLBACK
prompt
prompt Uninstalling PL/SQL Export Utilities
prompt ====================================
prompt Drop package plex if exists (body)
BEGIN
FOR i IN (SELECT object_type,
object_name
FROM user_objects
WHERE object_type = 'PACKAGE BODY'
AND object_name = 'PLEX') LOOP
EXECUTE IMMEDIATE 'DROP ' || i.object_type || ' ' || i.object_name;
END LOOP;
END;
/
prompt Drop package plex if exists (spec)
BEGIN
FOR i IN (SELECT object_type,
object_name
FROM user_objects
WHERE object_type = 'PACKAGE'
AND object_name = 'PLEX') LOOP
EXECUTE IMMEDIATE 'DROP ' || i.object_type || ' ' || i.object_name;
END LOOP;
END;
/
prompt ====================================
prompt Uninstallation Done
prompt