Compare commits
7 Commits
main
...
developmen
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
349d6c4545 | ||
|
|
2476fdea95 | ||
|
|
802781e7fc | ||
|
|
6e8e3f0603 | ||
|
|
5958ff16cd | ||
|
|
46bab05f5d | ||
|
|
16ae48af6d |
@ -1,5 +1,9 @@
|
||||
# Changelog
|
||||
|
||||
## 2.5.0 (2022-xx-xx)
|
||||
|
||||
- Add file download procedure
|
||||
|
||||
## 2.4.2 (2021-01-05)
|
||||
|
||||
- Function BackApp:
|
||||
|
||||
20
LICENSE.md
Normal file
20
LICENSE.md
Normal file
@ -0,0 +1,20 @@
|
||||
# MIT License
|
||||
|
||||
Copyright (c) 2018 Ottmar Gobrecht
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
21
LICENSE.txt
21
LICENSE.txt
@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018 Ottmar Gobrecht
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
698
README.md
698
README.md
@ -1,7 +1,7 @@
|
||||
<!-- DO NOT EDIT THIS FILE DIRECTLY - it is generated from source file src/PLEX.pks -->
|
||||
<!-- markdownlint-disable MD003 MD012 MD033 -->
|
||||
|
||||
PL/SQL Export Utilities
|
||||
PL/SQL Export Utilities
|
||||
=======================
|
||||
|
||||
- [Package PLEX](#plex)
|
||||
@ -10,6 +10,8 @@ PL/SQL Export Utilities
|
||||
- [Function queries_to_csv](#queries_to_csv)
|
||||
- [Function to_zip](#to_zip)
|
||||
- [Function to_base64](#to_base64)
|
||||
- [Procedure download](#download)
|
||||
- [Procedure download](#download)
|
||||
- [Function view_error_log](#view_error_log)
|
||||
- [Function view_runtime_log](#view_runtime_log)
|
||||
|
||||
@ -17,40 +19,40 @@ PL/SQL Export Utilities
|
||||
<h2><a id="plex"></a>Package PLEX</h2>
|
||||
<!----------------------------------->
|
||||
|
||||
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.
|
||||
|
||||
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)
|
||||
- [Changelog](https://github.com/ogobrecht/plex/blob/master/CHANGELOG.md)
|
||||
- [Give feedback](https://github.com/ogobrecht/plex/issues/new)
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
The package itself is independend, but functionality varies on the following conditions:
|
||||
|
||||
- For APEX app export: APEX >= 5.1.4 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](https://community.oracle.com/thread/4292776) which prevents you to export ORDS modules via the package ords_export. Please see plex_error_log.md, if you miss your ORDS modules after an export - this is no problem of PLEX.
|
||||
|
||||
INSTALLATION
|
||||
|
||||
- Download the [latest version](https://github.com/ogobrecht/plex/releases/latest)
|
||||
- Unzip it, open a shell and go into the root directory
|
||||
- Start SQL*Plus (or another tool which can run SQL scripts)
|
||||
- To install PLEX run the provided install script `plex_install.sql` (script provides compiler flags)
|
||||
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.
|
||||
|
||||
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)
|
||||
- [Changelog](https://github.com/ogobrecht/plex/blob/master/CHANGELOG.md)
|
||||
- [Give feedback](https://github.com/ogobrecht/plex/issues/new)
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
The package itself is independend, but functionality varies on the following conditions:
|
||||
|
||||
- For APEX app export: APEX >= 5.1.4 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](https://community.oracle.com/thread/4292776) which prevents you to export ORDS modules via the package ords_export. Please see plex_error_log.md, if you miss your ORDS modules after an export - this is no problem of PLEX.
|
||||
|
||||
INSTALLATION
|
||||
|
||||
- Download the [latest version](https://github.com/ogobrecht/plex/releases/latest)
|
||||
- Unzip it, open a shell and go into the root directory
|
||||
- Start SQL*Plus (or another tool which can run SQL scripts)
|
||||
- To install PLEX run the provided install script `plex_install.sql` (script provides compiler flags)
|
||||
- To uninstall PLEX run the provided script `plex_uninstall.sql` or drop the package manually
|
||||
|
||||
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.4.2';
|
||||
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';
|
||||
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.4.2';
|
||||
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';
|
||||
c_plex_author CONSTANT VARCHAR2(20 CHAR) := 'Ottmar Gobrecht';
|
||||
```
|
||||
|
||||
@ -58,154 +60,154 @@ c_plex_author CONSTANT VARCHAR2(20 CHAR) := 'Ottmar Gobrecht';
|
||||
<h2><a id="backapp"></a>Function backapp</h2>
|
||||
<!------------------------------------------>
|
||||
|
||||
Get a file collection of an APEX application (or the current user/schema only) including:
|
||||
|
||||
- The app export SQL files splitted ready to use for version control and deployment
|
||||
- Optional the DDL scripts for all objects and grants
|
||||
- Optional the data in CSV files (this option was implemented to track catalog tables, can be used as logical backup, has the typical CSV limitations...)
|
||||
- Everything in a (hopefully) nice directory structure
|
||||
|
||||
EXAMPLE BASIC USAGE
|
||||
|
||||
```sql
|
||||
DECLARE
|
||||
l_file_collection plex.tab_export_files;
|
||||
BEGIN
|
||||
l_file_collection := 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 => false,
|
||||
p_include_data => false,
|
||||
p_include_templates => false);
|
||||
|
||||
-- do something with the file collection
|
||||
FOR i IN 1..l_file_collection.count LOOP
|
||||
dbms_output.put_line(i || ' | '
|
||||
|| lpad(round(length(l_file_collection(i).contents) / 1024), 3) || ' kB' || ' | '
|
||||
|| l_file_collection(i).name);
|
||||
END LOOP;
|
||||
END;
|
||||
/
|
||||
```
|
||||
|
||||
EXAMPLE ZIP FILE PL/SQL
|
||||
|
||||
```sql
|
||||
DECLARE
|
||||
l_zip_file BLOB;
|
||||
BEGIN
|
||||
l_zip_file := 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));
|
||||
-- do something with the zip file
|
||||
-- Your code here...
|
||||
END;
|
||||
/
|
||||
```
|
||||
|
||||
EXAMPLE ZIP FILE SQL
|
||||
|
||||
```sql
|
||||
-- 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, -- 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 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 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
|
||||
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;
|
||||
/
|
||||
set termout off
|
||||
spool "app_100.zip.base64"
|
||||
print contents
|
||||
spool off
|
||||
set termout on
|
||||
Get a file collection of an APEX application (or the current user/schema only) including:
|
||||
|
||||
- The app export SQL files splitted ready to use for version control and deployment
|
||||
- Optional the DDL scripts for all objects and grants
|
||||
- Optional the data in CSV files (this option was implemented to track catalog tables, can be used as logical backup, has the typical CSV limitations...)
|
||||
- Everything in a (hopefully) nice directory structure
|
||||
|
||||
EXAMPLE BASIC USAGE
|
||||
|
||||
```sql
|
||||
DECLARE
|
||||
l_file_collection plex.tab_export_files;
|
||||
BEGIN
|
||||
l_file_collection := 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 => false,
|
||||
p_include_data => false,
|
||||
p_include_templates => false);
|
||||
|
||||
-- do something with the file collection
|
||||
FOR i IN 1..l_file_collection.count LOOP
|
||||
dbms_output.put_line(i || ' | '
|
||||
|| lpad(round(length(l_file_collection(i).contents) / 1024), 3) || ' kB' || ' | '
|
||||
|| l_file_collection(i).name);
|
||||
END LOOP;
|
||||
END;
|
||||
/
|
||||
```
|
||||
|
||||
EXAMPLE ZIP FILE PL/SQL
|
||||
|
||||
```sql
|
||||
DECLARE
|
||||
l_zip_file BLOB;
|
||||
BEGIN
|
||||
l_zip_file := 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));
|
||||
-- do something with the zip file
|
||||
-- Your code here...
|
||||
END;
|
||||
/
|
||||
```
|
||||
|
||||
EXAMPLE ZIP FILE SQL
|
||||
|
||||
```sql
|
||||
-- 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, -- 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 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 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
|
||||
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;
|
||||
/
|
||||
set termout off
|
||||
spool "app_100.zip.base64"
|
||||
print contents
|
||||
spool off
|
||||
set termout on
|
||||
```
|
||||
|
||||
SIGNATURE
|
||||
|
||||
```sql
|
||||
FUNCTION backapp (
|
||||
$if $$apex_installed $then
|
||||
-- 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.
|
||||
p_app_private_reports IN BOOLEAN DEFAULT false, -- If true, include private reports that a user saved.
|
||||
p_app_notifications IN BOOLEAN DEFAULT false, -- If true, include report notifications.
|
||||
p_app_translations IN BOOLEAN DEFAULT true, -- If true, include application translation mappings and all text from the translation repository.
|
||||
p_app_pkg_app_mapping IN BOOLEAN DEFAULT false, -- If true, export installed packaged applications with references to the packaged application definition. If FALSE, export them as normal applications.
|
||||
p_app_original_ids IN BOOLEAN DEFAULT false, -- If true, export with the IDs as they were when the application was imported.
|
||||
p_app_subscriptions IN BOOLEAN DEFAULT true, -- If true, components contain subscription references.
|
||||
p_app_comments IN BOOLEAN DEFAULT true, -- If true, include developer comments.
|
||||
p_app_supporting_objects IN VARCHAR2 DEFAULT null, -- If 'Y', export supporting objects. If 'I', automatically install on import. If 'N', do not export supporting objects. If null, the application's include in export deployment value is used.
|
||||
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
|
||||
$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 '\').
|
||||
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 '\').
|
||||
p_data_format IN VARCHAR2 DEFAULT 'csv', -- A comma separated list of formats - currently supported formats are CSV and INSERT - example: 'csv,insert' will export for each table a csv file and a sql file with insert statements. For insert you can also give the number of rows per "insert all" statement (defaults to 20) - example: 'csv,insert:10' or 'insert:5'.
|
||||
-- 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 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.
|
||||
p_base_path_docs IN VARCHAR2 DEFAULT 'docs', -- The base path in the project root for the docs.
|
||||
p_base_path_tests IN VARCHAR2 DEFAULT 'tests', -- The base path in the project root for the tests.
|
||||
p_base_path_scripts IN VARCHAR2 DEFAULT 'scripts', -- The base path in the project root for the generated deploy scripts.
|
||||
p_base_path_script_logs IN VARCHAR2 DEFAULT 'scripts/logs', -- The base path in the project root for the deploy script log files.
|
||||
p_scripts_working_directory IN VARCHAR2 DEFAULT 'scripts') -- The working directory of the shell (relative to the project root) where deploy scripts will be called. Set this to null if you run the deploy scripts from the project root.
|
||||
FUNCTION backapp (
|
||||
$if $$apex_installed $then
|
||||
-- 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.
|
||||
p_app_private_reports IN BOOLEAN DEFAULT false, -- If true, include private reports that a user saved.
|
||||
p_app_notifications IN BOOLEAN DEFAULT false, -- If true, include report notifications.
|
||||
p_app_translations IN BOOLEAN DEFAULT true, -- If true, include application translation mappings and all text from the translation repository.
|
||||
p_app_pkg_app_mapping IN BOOLEAN DEFAULT false, -- If true, export installed packaged applications with references to the packaged application definition. If FALSE, export them as normal applications.
|
||||
p_app_original_ids IN BOOLEAN DEFAULT false, -- If true, export with the IDs as they were when the application was imported.
|
||||
p_app_subscriptions IN BOOLEAN DEFAULT true, -- If true, components contain subscription references.
|
||||
p_app_comments IN BOOLEAN DEFAULT true, -- If true, include developer comments.
|
||||
p_app_supporting_objects IN VARCHAR2 DEFAULT null, -- If 'Y', export supporting objects. If 'I', automatically install on import. If 'N', do not export supporting objects. If null, the application's include in export deployment value is used.
|
||||
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
|
||||
$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 '\').
|
||||
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 '\').
|
||||
p_data_format IN VARCHAR2 DEFAULT 'csv', -- A comma separated list of formats - currently supported formats are CSV and INSERT - example: 'csv,insert' will export for each table a csv file and a sql file with insert statements. For insert you can also give the number of rows per "insert all" statement (defaults to 20) - example: 'csv,insert:10' or 'insert:5'.
|
||||
-- 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 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.
|
||||
p_base_path_docs IN VARCHAR2 DEFAULT 'docs', -- The base path in the project root for the docs.
|
||||
p_base_path_tests IN VARCHAR2 DEFAULT 'tests', -- The base path in the project root for the tests.
|
||||
p_base_path_scripts IN VARCHAR2 DEFAULT 'scripts', -- The base path in the project root for the generated deploy scripts.
|
||||
p_base_path_script_logs IN VARCHAR2 DEFAULT 'scripts/logs', -- The base path in the project root for the deploy script log files.
|
||||
p_scripts_working_directory IN VARCHAR2 DEFAULT 'scripts') -- The working directory of the shell (relative to the project root) where deploy scripts will be called. Set this to null if you run the deploy scripts from the project root.
|
||||
RETURN tab_export_files;
|
||||
```
|
||||
|
||||
@ -213,25 +215,25 @@ RETURN tab_export_files;
|
||||
<h2><a id="add_query"></a>Procedure add_query</h2>
|
||||
<!----------------------------------------------->
|
||||
|
||||
Add a query to be processed by the method queries_to_csv. You can add as many queries as you like.
|
||||
|
||||
EXAMPLE
|
||||
|
||||
```sql
|
||||
BEGIN
|
||||
plex.add_query(
|
||||
p_query => 'select * from user_tables',
|
||||
p_file_name => 'user_tables');
|
||||
END;
|
||||
/
|
||||
Add a query to be processed by the method queries_to_csv. You can add as many queries as you like.
|
||||
|
||||
EXAMPLE
|
||||
|
||||
```sql
|
||||
BEGIN
|
||||
plex.add_query(
|
||||
p_query => 'select * from user_tables',
|
||||
p_file_name => 'user_tables');
|
||||
END;
|
||||
/
|
||||
```
|
||||
|
||||
SIGNATURE
|
||||
|
||||
```sql
|
||||
PROCEDURE add_query (
|
||||
p_query IN VARCHAR2, -- The query itself
|
||||
p_file_name IN VARCHAR2, -- File name like 'Path/to/your/file-without-extension'.
|
||||
PROCEDURE add_query (
|
||||
p_query IN VARCHAR2, -- The query itself
|
||||
p_file_name IN VARCHAR2, -- File name like 'Path/to/your/file-without-extension'.
|
||||
p_max_rows IN NUMBER DEFAULT 1000); -- The maximum number of rows to be included in your file.
|
||||
```
|
||||
|
||||
@ -239,118 +241,118 @@ PROCEDURE add_query (
|
||||
<h2><a id="queries_to_csv"></a>Function queries_to_csv</h2>
|
||||
<!-------------------------------------------------------->
|
||||
|
||||
Export one or more queries as CSV data within a file collection.
|
||||
|
||||
EXAMPLE BASIC USAGE
|
||||
|
||||
```sql
|
||||
DECLARE
|
||||
l_file_collection plex.tab_export_files;
|
||||
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
|
||||
l_file_collection := plex.queries_to_csv;
|
||||
-- do something with the file collection
|
||||
FOR i IN 1..l_file_collection.count LOOP
|
||||
dbms_output.put_line(i || ' | '
|
||||
|| lpad(round(length(l_file_collection(i).contents) / 1024), 3) || ' kB' || ' | '
|
||||
|| l_file_collection(i).name);
|
||||
END LOOP;
|
||||
END;
|
||||
/
|
||||
```
|
||||
|
||||
EXAMPLE EXPORT ZIP FILE PL/SQL
|
||||
|
||||
```sql
|
||||
DECLARE
|
||||
l_zip_file BLOB;
|
||||
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
|
||||
l_zip_file := plex.to_zip(plex.queries_to_csv);
|
||||
-- do something with the zip file
|
||||
-- Your code here...
|
||||
END;
|
||||
/
|
||||
```
|
||||
|
||||
EXAMPLE EXPORT ZIP FILE SQL
|
||||
|
||||
```sql
|
||||
WITH
|
||||
FUNCTION queries_to_csv_zip RETURN BLOB IS
|
||||
v_return BLOB;
|
||||
BEGIN
|
||||
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);
|
||||
v_return := plex.to_zip(plex.queries_to_csv);
|
||||
RETURN v_return;
|
||||
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
|
||||
Export one or more queries as CSV data within a file collection.
|
||||
|
||||
EXAMPLE BASIC USAGE
|
||||
|
||||
```sql
|
||||
DECLARE
|
||||
l_file_collection plex.tab_export_files;
|
||||
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
|
||||
l_file_collection := plex.queries_to_csv;
|
||||
-- do something with the file collection
|
||||
FOR i IN 1..l_file_collection.count LOOP
|
||||
dbms_output.put_line(i || ' | '
|
||||
|| lpad(round(length(l_file_collection(i).contents) / 1024), 3) || ' kB' || ' | '
|
||||
|| l_file_collection(i).name);
|
||||
END LOOP;
|
||||
END;
|
||||
/
|
||||
```
|
||||
|
||||
EXAMPLE EXPORT ZIP FILE PL/SQL
|
||||
|
||||
```sql
|
||||
DECLARE
|
||||
l_zip_file BLOB;
|
||||
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
|
||||
l_zip_file := plex.to_zip(plex.queries_to_csv);
|
||||
-- do something with the zip file
|
||||
-- Your code here...
|
||||
END;
|
||||
/
|
||||
```
|
||||
|
||||
EXAMPLE EXPORT ZIP FILE SQL
|
||||
|
||||
```sql
|
||||
WITH
|
||||
FUNCTION queries_to_csv_zip RETURN BLOB IS
|
||||
v_return BLOB;
|
||||
BEGIN
|
||||
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);
|
||||
v_return := plex.to_zip(plex.queries_to_csv);
|
||||
RETURN v_return;
|
||||
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
|
||||
```
|
||||
|
||||
SIGNATURE
|
||||
|
||||
```sql
|
||||
FUNCTION queries_to_csv (
|
||||
p_delimiter IN VARCHAR2 DEFAULT ',', -- The column delimiter.
|
||||
p_quote_mark IN VARCHAR2 DEFAULT '"', -- Used when the data contains the delimiter character.
|
||||
p_header_prefix IN VARCHAR2 DEFAULT NULL, -- Prefix the header line with this text.
|
||||
p_include_runtime_log IN BOOLEAN DEFAULT true, -- If true, generate file plex_runtime_log.md with runtime statistics.
|
||||
p_include_error_log IN BOOLEAN DEFAULT true) -- If true, generate file plex_error_log.md with detailed error messages.
|
||||
FUNCTION queries_to_csv (
|
||||
p_delimiter IN VARCHAR2 DEFAULT ',', -- The column delimiter.
|
||||
p_quote_mark IN VARCHAR2 DEFAULT '"', -- Used when the data contains the delimiter character.
|
||||
p_header_prefix IN VARCHAR2 DEFAULT NULL, -- Prefix the header line with this text.
|
||||
p_include_runtime_log IN BOOLEAN DEFAULT true, -- If true, generate file plex_runtime_log.md with runtime statistics.
|
||||
p_include_error_log IN BOOLEAN DEFAULT true) -- If true, generate file plex_error_log.md with detailed error messages.
|
||||
RETURN tab_export_files;
|
||||
```
|
||||
|
||||
@ -358,26 +360,26 @@ RETURN tab_export_files;
|
||||
<h2><a id="to_zip"></a>Function to_zip</h2>
|
||||
<!---------------------------------------->
|
||||
|
||||
Convert a file collection to a zip file.
|
||||
|
||||
EXAMPLE
|
||||
|
||||
```sql
|
||||
DECLARE
|
||||
l_zip BLOB;
|
||||
BEGIN
|
||||
l_zip := plex.to_zip(plex.backapp(
|
||||
p_app_id => 100,
|
||||
p_include_object_ddl => true));
|
||||
-- do something with the zip file...
|
||||
END;
|
||||
Convert a file collection to a zip file.
|
||||
|
||||
EXAMPLE
|
||||
|
||||
```sql
|
||||
DECLARE
|
||||
l_zip BLOB;
|
||||
BEGIN
|
||||
l_zip := plex.to_zip(plex.backapp(
|
||||
p_app_id => 100,
|
||||
p_include_object_ddl => true));
|
||||
-- do something with the zip file...
|
||||
END;
|
||||
```
|
||||
|
||||
SIGNATURE
|
||||
|
||||
```sql
|
||||
FUNCTION to_zip (
|
||||
p_file_collection IN tab_export_files) -- The file collection to zip.
|
||||
FUNCTION to_zip (
|
||||
p_file_collection IN tab_export_files) -- The file collection to zip.
|
||||
RETURN BLOB;
|
||||
```
|
||||
|
||||
@ -385,37 +387,65 @@ 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;
|
||||
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.
|
||||
FUNCTION to_base64(
|
||||
p_blob IN BLOB) -- The BLOB to convert.
|
||||
RETURN CLOB;
|
||||
```
|
||||
|
||||
|
||||
<h2><a id="download"></a>Procedure download</h2>
|
||||
<!--------------------------------------------->
|
||||
|
||||
Download a file based on a BLOB.
|
||||
|
||||
SIGNATURE
|
||||
|
||||
```sql
|
||||
PROCEDURE download (
|
||||
p_blob IN BLOB,
|
||||
p_name IN VARCHAR2 );
|
||||
```
|
||||
|
||||
|
||||
<h2><a id="download"></a>Procedure download</h2>
|
||||
<!--------------------------------------------->
|
||||
|
||||
Download a file based on a CLOB.
|
||||
|
||||
SIGNATURE
|
||||
|
||||
```sql
|
||||
PROCEDURE download (
|
||||
p_clob IN CLOB,
|
||||
p_name IN VARCHAR2 );
|
||||
```
|
||||
|
||||
|
||||
<h2><a id="view_error_log"></a>Function view_error_log</h2>
|
||||
<!-------------------------------------------------------->
|
||||
|
||||
View the error log from the last plex run. The internal array for the error log is cleared on each call of BackApp or Queries_to_CSV.
|
||||
|
||||
EXAMPLE
|
||||
|
||||
```sql
|
||||
SELECT * FROM TABLE(plex.view_error_log);
|
||||
View the error log from the last plex run. The internal array for the error log is cleared on each call of BackApp or Queries_to_CSV.
|
||||
|
||||
EXAMPLE
|
||||
|
||||
```sql
|
||||
SELECT * FROM TABLE(plex.view_error_log);
|
||||
```
|
||||
|
||||
SIGNATURE
|
||||
@ -428,12 +458,12 @@ FUNCTION view_error_log RETURN tab_error_log PIPELINED;
|
||||
<h2><a id="view_runtime_log"></a>Function view_runtime_log</h2>
|
||||
<!------------------------------------------------------------>
|
||||
|
||||
View the runtime log from the last plex run. The internal array for the runtime log is cleared on each call of BackApp or Queries_to_CSV.
|
||||
|
||||
EXAMPLE
|
||||
|
||||
```sql
|
||||
SELECT * FROM TABLE(plex.view_runtime_log);
|
||||
View the runtime log from the last plex run. The internal array for the runtime log is cleared on each call of BackApp or Queries_to_CSV.
|
||||
|
||||
EXAMPLE
|
||||
|
||||
```sql
|
||||
SELECT * FROM TABLE(plex.view_runtime_log);
|
||||
```
|
||||
|
||||
SIGNATURE
|
||||
|
||||
1243
package-lock.json
generated
1243
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
183
plex_install.sql
183
plex_install.sql
@ -1,4 +1,10 @@
|
||||
set define off feedback off
|
||||
set define off
|
||||
set serveroutput on
|
||||
set verify off
|
||||
set feedback off
|
||||
set linesize 240
|
||||
set trimout on
|
||||
set trimspool on
|
||||
whenever sqlerror exit sql.sqlcode rollback
|
||||
|
||||
prompt
|
||||
@ -271,7 +277,6 @@ set termout on
|
||||
**/
|
||||
|
||||
|
||||
|
||||
PROCEDURE add_query (
|
||||
p_query IN VARCHAR2, -- The query itself
|
||||
p_file_name IN VARCHAR2, -- File name like 'Path/to/your/file-without-extension'.
|
||||
@ -292,7 +297,6 @@ END;
|
||||
**/
|
||||
|
||||
|
||||
|
||||
FUNCTION queries_to_csv (
|
||||
p_delimiter IN VARCHAR2 DEFAULT ',', -- The column delimiter.
|
||||
p_quote_mark IN VARCHAR2 DEFAULT '"', -- Used when the data contains the delimiter character.
|
||||
@ -406,7 +410,6 @@ spool off
|
||||
**/
|
||||
|
||||
|
||||
|
||||
FUNCTION to_zip (
|
||||
p_file_collection IN tab_export_files) -- The file collection to zip.
|
||||
RETURN BLOB;
|
||||
@ -427,6 +430,7 @@ END;
|
||||
```
|
||||
**/
|
||||
|
||||
|
||||
FUNCTION to_base64(
|
||||
p_blob IN BLOB) -- The BLOB to convert.
|
||||
RETURN CLOB;
|
||||
@ -445,6 +449,27 @@ END;
|
||||
```
|
||||
**/
|
||||
|
||||
|
||||
PROCEDURE download (
|
||||
p_blob IN BLOB,
|
||||
p_name IN VARCHAR2 );
|
||||
/**
|
||||
|
||||
Download a file based on a BLOB.
|
||||
|
||||
**/
|
||||
|
||||
|
||||
PROCEDURE download (
|
||||
p_clob IN CLOB,
|
||||
p_name IN VARCHAR2 );
|
||||
/**
|
||||
|
||||
Download a file based on a CLOB.
|
||||
|
||||
**/
|
||||
|
||||
|
||||
FUNCTION view_error_log RETURN tab_error_log PIPELINED;
|
||||
/**
|
||||
View the error log from the last plex run. The internal array for the error log is cleared on each call of BackApp or Queries_to_CSV.
|
||||
@ -581,10 +606,13 @@ PROCEDURE util_clob_query_to_csv (
|
||||
p_header_prefix IN VARCHAR2 DEFAULT NULL);
|
||||
|
||||
PROCEDURE util_clob_table_to_insert (
|
||||
p_table_name IN VARCHAR2,
|
||||
p_data_scn IN NUMBER,
|
||||
p_max_rows IN NUMBER DEFAULT 1000,
|
||||
p_insert_all_size IN NUMBER DEFAULT 10);
|
||||
p_table_name IN VARCHAR2,
|
||||
p_data_scn IN NUMBER,
|
||||
p_max_rows IN NUMBER DEFAULT 1000,
|
||||
p_insert_style IN VARCHAR2 DEFAULT 'INSERT', -- can be INSERT or OM_TAPIGEN
|
||||
p_insert_all_size IN NUMBER DEFAULT 10,
|
||||
p_exclude_columns_list IN VARCHAR2 DEFAULT NULL -- a colon separated list of columns that should be excluded for the insert operation (for example audit columns which are populated automatically) FIXME: support the auto detection of an column prefix
|
||||
);
|
||||
|
||||
PROCEDURE util_clob_create_runtime_log (p_export_files IN OUT NOCOPY tab_export_files);
|
||||
|
||||
@ -846,10 +874,13 @@ PROCEDURE util_clob_query_to_csv (
|
||||
p_header_prefix IN VARCHAR2 DEFAULT NULL);
|
||||
|
||||
PROCEDURE util_clob_table_to_insert (
|
||||
p_table_name IN VARCHAR2,
|
||||
p_data_scn IN NUMBER,
|
||||
p_max_rows IN NUMBER DEFAULT 1000,
|
||||
p_insert_all_size IN NUMBER DEFAULT 10);
|
||||
p_table_name IN VARCHAR2,
|
||||
p_data_scn IN NUMBER,
|
||||
p_max_rows IN NUMBER DEFAULT 1000,
|
||||
p_insert_style IN VARCHAR2 DEFAULT 'INSERT', -- can be INSERT or OM_TAPIGEN
|
||||
p_insert_all_size IN NUMBER DEFAULT 10,
|
||||
p_exclude_columns_list IN VARCHAR2 DEFAULT NULL -- a list of columns that should be excluded for the insert operation (for example audit columns which are populated automatically) FIXME: support the auto detection of an column prefix
|
||||
);
|
||||
|
||||
PROCEDURE util_clob_create_runtime_log (p_export_files IN OUT NOCOPY tab_export_files);
|
||||
|
||||
@ -1595,11 +1626,15 @@ END util_clob_query_to_csv;
|
||||
--------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
PROCEDURE util_clob_table_to_insert (
|
||||
p_table_name IN VARCHAR2,
|
||||
p_data_scn IN NUMBER,
|
||||
p_max_rows IN NUMBER DEFAULT 1000,
|
||||
p_insert_all_size IN NUMBER DEFAULT 10)
|
||||
p_table_name IN VARCHAR2,
|
||||
p_data_scn IN NUMBER,
|
||||
p_max_rows IN NUMBER DEFAULT 1000,
|
||||
p_insert_style IN VARCHAR2 DEFAULT 'INSERT',
|
||||
p_insert_all_size IN NUMBER DEFAULT 10,
|
||||
p_exclude_columns_list IN VARCHAR2 DEFAULT NULL)
|
||||
IS
|
||||
v_insert_style VARCHAR2(30);
|
||||
v_exclude_columns_list VARCHAR2(32767);
|
||||
v_nls rec_nls;
|
||||
v_query VARCHAR2(32767);
|
||||
v_cursor PLS_INTEGER;
|
||||
@ -1619,6 +1654,12 @@ IS
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
PROCEDURE init IS
|
||||
BEGIN
|
||||
v_insert_style := trim(upper(substr(p_insert_style,1,30)));
|
||||
v_exclude_columns_list := trim(upper(p_exclude_columns_list)) || ':';
|
||||
END;
|
||||
|
||||
PROCEDURE get_session_nls_params IS
|
||||
BEGIN
|
||||
-- Save current values.
|
||||
@ -1808,6 +1849,7 @@ IS
|
||||
where table_name = p_table_name
|
||||
and user_generated = 'YES'
|
||||
and virtual_column = 'NO'
|
||||
and instr(v_exclude_columns_list, ':'||column_name||':') = 0
|
||||
group by table_name
|
||||
) LOOP
|
||||
v_query := i.query;
|
||||
@ -1829,13 +1871,20 @@ IS
|
||||
ELSE
|
||||
dbms_sql.define_column(v_cursor, i, v_buffer_varchar2, c_vc2_max_size);
|
||||
END IF;
|
||||
v_table_insert_prefix := v_table_insert_prefix || v_desc_tab(i).col_name || ',';
|
||||
IF v_insert_style = 'INSERT' THEN
|
||||
v_table_insert_prefix := v_table_insert_prefix || v_desc_tab(i).col_name || ',';
|
||||
END IF;
|
||||
END LOOP;
|
||||
v_table_insert_prefix :=
|
||||
case when p_insert_all_size > 0
|
||||
then 'into '
|
||||
else 'insert into '
|
||||
end || p_table_name || '(' || rtrim(v_table_insert_prefix, ',' ) || ') values (';
|
||||
CASE v_insert_style
|
||||
WHEN 'INSERT' THEN
|
||||
case when p_insert_all_size > 0
|
||||
then 'into '
|
||||
else 'insert into '
|
||||
end || p_table_name || '(' || rtrim(v_table_insert_prefix, ',' ) || ') values ('
|
||||
WHEN 'OM_TAPIGEN' THEN
|
||||
lower(p_table_name) || '_api.create_or_update_row('
|
||||
END;
|
||||
v_ignore_me := dbms_sql.execute(v_cursor);
|
||||
END IF;
|
||||
END parse_query_and_describe_cols;
|
||||
@ -1849,8 +1898,10 @@ IS
|
||||
PROCEDURE create_header IS
|
||||
BEGIN
|
||||
util_clob_append('-- Script generated by PLEX version ' || c_plex_version || ' - more infos here: ' || c_plex_url || c_crlf);
|
||||
util_clob_append('-- Performance Hacks by Connor McDonald: https://connor-mcdonald.com/2019/05/17/hacking-together-faster-inserts/' || c_crlf);
|
||||
util_clob_append('-- For strange line end replacements a big thank to SQL*Plus: https://support.oracle.com/epmos/faces/DocumentDisplay?id=2377701.1 (SQL Failed With ORA-1756 In Sqlplus But Works In SQL Developer)' || c_crlf);
|
||||
if v_insert_style = 'INSERT' then
|
||||
util_clob_append('-- Performance Hacks by Connor McDonald: https://connor-mcdonald.com/2019/05/17/hacking-together-faster-inserts/' || c_crlf);
|
||||
util_clob_append('-- For strange line end replacements a big thank to SQL*Plus: https://support.oracle.com/epmos/faces/DocumentDisplay?id=2377701.1 (SQL Failed With ORA-1756 In Sqlplus But Works In SQL Developer)' || c_crlf);
|
||||
end if;
|
||||
util_clob_append('prompt - insert xxx rows into ' || p_table_name || ' (exported ' || to_char(systimestamp,'YYYY-MM-DD hh24:mi:ssxff TZR') || ')' || c_crlf);
|
||||
util_clob_append('set define off feedback off sqlblanklines on' || c_crlf);
|
||||
util_clob_append('alter session set cursor_sharing = force;' || c_crlf);
|
||||
@ -1871,12 +1922,15 @@ IS
|
||||
if v_data_count = 1 then
|
||||
create_header;
|
||||
end if;
|
||||
if p_insert_all_size > 0 and mod(v_data_count, p_insert_all_size) = 1 then
|
||||
if v_insert_style = 'INSERT' and p_insert_all_size > 0 and mod(v_data_count, p_insert_all_size) = 1 then
|
||||
util_clob_append('insert all' || c_crlf);
|
||||
end if;
|
||||
line_append(v_table_insert_prefix);
|
||||
--> process row
|
||||
FOR i IN 1..v_col_count LOOP
|
||||
IF v_insert_style = 'OM_TAPIGEN' THEN
|
||||
line_append('p_' || lower(v_desc_tab(i).col_name) || '=>');
|
||||
END IF;
|
||||
IF v_desc_tab(i).col_type = c_clob THEN
|
||||
dbms_sql.column_value(v_cursor, i, v_buffer_clob);
|
||||
process_clob_buffer;
|
||||
@ -1900,15 +1954,15 @@ IS
|
||||
process_varchar2_buffer('STRING');
|
||||
END IF;
|
||||
END IF;
|
||||
if i != v_col_count then
|
||||
if i != v_col_count then
|
||||
line_append(',');
|
||||
else
|
||||
line_append(')' || case when p_insert_all_size < 1 then ';' end);
|
||||
line_append(')' || case when v_insert_style = 'OM_TAPIGEN' or p_insert_all_size < 1 then ';' end);
|
||||
line_flush_cache;
|
||||
end if;
|
||||
END LOOP;
|
||||
--< end process row
|
||||
if p_insert_all_size > 0 and mod(v_data_count, p_insert_all_size) = 0 then
|
||||
if v_insert_style = 'INSERT' and p_insert_all_size > 0 and mod(v_data_count, p_insert_all_size) = 0 then
|
||||
util_clob_append('select * from dual;' || c_crlf);
|
||||
end if;
|
||||
|
||||
@ -1923,7 +1977,7 @@ IS
|
||||
if v_data_count = 0 then
|
||||
util_clob_append('Prompt Nothing to insert - there was no data in the source table ' || p_table_name || c_crlf);
|
||||
else
|
||||
if p_insert_all_size > 0 and mod(v_data_count, p_insert_all_size) != 0 then
|
||||
if V_insert_style = 'INSERT' and p_insert_all_size > 0 and mod(v_data_count, p_insert_all_size) != 0 then
|
||||
util_clob_append('select * from dual;' || c_crlf);
|
||||
end if;
|
||||
util_clob_append('end;' || c_crlf);
|
||||
@ -1948,6 +2002,7 @@ IS
|
||||
BEGIN
|
||||
IF p_table_name IS NOT NULL THEN
|
||||
--dbms_lob.createtemporary(v_buffer_clob, true);
|
||||
init;
|
||||
get_session_nls_params;
|
||||
parse_query_and_describe_cols;
|
||||
create_data;
|
||||
@ -2955,13 +3010,17 @@ SELECT table_name,
|
||||
v_file_path := v_path.to_data || '/' || v_rec.table_name || '.sql';
|
||||
util_log_start(v_file_path);
|
||||
util_clob_table_to_insert(
|
||||
p_table_name => v_rec.table_name,
|
||||
p_data_scn => v_data_scn,
|
||||
p_max_rows => p_data_max_rows,
|
||||
p_insert_all_size => to_number(nvl(regexp_substr(p_data_format,'insert:(\d+)',1,1,'i',1), '10')));
|
||||
p_table_name => v_rec.table_name,
|
||||
p_data_scn => v_data_scn,
|
||||
p_max_rows => p_data_max_rows,
|
||||
p_insert_style => 'INSERT',
|
||||
p_insert_all_size => to_number(nvl(regexp_substr(p_data_format,':(\d+)',1,1,'i',1), '10')),
|
||||
p_exclude_columns_list => regexp_substr(p_data_format,'(:\w+){1,}')
|
||||
);
|
||||
util_clob_add_to_export_files(
|
||||
p_export_files => v_export_files,
|
||||
p_name => v_file_path);
|
||||
p_name => v_file_path
|
||||
);
|
||||
v_files.data_(v_files.data_.count + 1) := v_file_path;
|
||||
util_log_stop;
|
||||
EXCEPTION
|
||||
@ -2969,6 +3028,31 @@ SELECT table_name,
|
||||
util_log_error(v_file_path);
|
||||
END;
|
||||
END IF;
|
||||
|
||||
-- insert with table API (OM_TAPIGEN style)
|
||||
IF upper(p_data_format) LIKE '%OM_TAPIGEN%' THEN
|
||||
BEGIN
|
||||
v_file_path := v_path.to_data || '/' || v_rec.table_name || '.api.sql';
|
||||
util_log_start(v_file_path);
|
||||
util_clob_table_to_insert(
|
||||
p_table_name => v_rec.table_name,
|
||||
p_data_scn => v_data_scn,
|
||||
p_max_rows => p_data_max_rows,
|
||||
p_insert_style => 'OM_TAPIGEN',
|
||||
p_exclude_columns_list => regexp_substr(p_data_format,'(:\w+){1,}')
|
||||
);
|
||||
util_clob_add_to_export_files(
|
||||
p_export_files => v_export_files,
|
||||
p_name => v_file_path
|
||||
);
|
||||
v_files.data_(v_files.data_.count + 1) := v_file_path;
|
||||
util_log_stop;
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
util_log_error(v_file_path);
|
||||
END;
|
||||
END IF;
|
||||
|
||||
END LOOP;
|
||||
CLOSE v_cur;
|
||||
|
||||
@ -3569,7 +3653,7 @@ BEGIN
|
||||
$end
|
||||
IF p_include_data THEN
|
||||
process_data;
|
||||
if upper(p_data_format) LIKE '%INSERT%' then
|
||||
if upper(p_data_format) LIKE '%INSERT%' or upper(p_data_format) LIKE '%OM_TAPIGEN%' then
|
||||
create_load_data_file;
|
||||
end if;
|
||||
END IF;
|
||||
@ -3710,6 +3794,37 @@ END;
|
||||
|
||||
--------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
PROCEDURE download (
|
||||
p_blob IN BLOB,
|
||||
p_name IN VARCHAR2 )
|
||||
IS
|
||||
-- we need to avoid PLS-00363: expression 'P_BLOB' cannot be used as an assignment target
|
||||
v_blob blob := p_blob;
|
||||
BEGIN
|
||||
owa_util.mime_header('application/octet', false);
|
||||
htp.p('Content-length:' || dbms_lob.getlength(v_blob));
|
||||
htp.p('Content-Disposition: attachment; filename="' || p_name || '"');
|
||||
|
||||
-- the browser should not cache the file
|
||||
htp.p('Cache-Control: must-revalidate, max-age=0');
|
||||
htp.p('Expires: Thu, 01 Jan 1970 01:00:00 CET');
|
||||
|
||||
owa_util.http_header_close;
|
||||
wpg_docload.download_file(v_blob);
|
||||
END download;
|
||||
|
||||
--------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
PROCEDURE download (
|
||||
p_clob IN CLOB,
|
||||
p_name IN VARCHAR2 )
|
||||
IS
|
||||
BEGIN
|
||||
download(util_clob_to_blob(p_clob), p_name);
|
||||
END download;
|
||||
|
||||
--------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
FUNCTION view_error_log RETURN tab_error_log PIPELINED IS
|
||||
BEGIN
|
||||
FOR i IN 1..g_errlog.count LOOP
|
||||
|
||||
@ -1,31 +1,37 @@
|
||||
set define off feedback off
|
||||
set define off
|
||||
set serveroutput on
|
||||
set verify off
|
||||
set feedback off
|
||||
set linesize 240
|
||||
set trimout on
|
||||
set trimspool on
|
||||
whenever sqlerror exit sql.sqlcode rollback
|
||||
|
||||
prompt
|
||||
prompt Uninstalling PL/SQL Export Utilities
|
||||
prompt ====================================
|
||||
prompt ============================================================
|
||||
prompt Drop package plex if exists (body)
|
||||
BEGIN
|
||||
FOR i IN (SELECT object_type,
|
||||
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;
|
||||
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,
|
||||
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;
|
||||
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 ============================================================
|
||||
prompt Uninstallation Done
|
||||
prompt
|
||||
prompt
|
||||
|
||||
139
src/PLEX.pkb
139
src/PLEX.pkb
@ -228,10 +228,13 @@ PROCEDURE util_clob_query_to_csv (
|
||||
p_header_prefix IN VARCHAR2 DEFAULT NULL);
|
||||
|
||||
PROCEDURE util_clob_table_to_insert (
|
||||
p_table_name IN VARCHAR2,
|
||||
p_data_scn IN NUMBER,
|
||||
p_max_rows IN NUMBER DEFAULT 1000,
|
||||
p_insert_all_size IN NUMBER DEFAULT 10);
|
||||
p_table_name IN VARCHAR2,
|
||||
p_data_scn IN NUMBER,
|
||||
p_max_rows IN NUMBER DEFAULT 1000,
|
||||
p_insert_style IN VARCHAR2 DEFAULT 'INSERT', -- can be INSERT or OM_TAPIGEN
|
||||
p_insert_all_size IN NUMBER DEFAULT 10,
|
||||
p_exclude_columns_list IN VARCHAR2 DEFAULT NULL -- a list of columns that should be excluded for the insert operation (for example audit columns which are populated automatically) FIXME: support the auto detection of an column prefix
|
||||
);
|
||||
|
||||
PROCEDURE util_clob_create_runtime_log (p_export_files IN OUT NOCOPY tab_export_files);
|
||||
|
||||
@ -977,11 +980,15 @@ END util_clob_query_to_csv;
|
||||
--------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
PROCEDURE util_clob_table_to_insert (
|
||||
p_table_name IN VARCHAR2,
|
||||
p_data_scn IN NUMBER,
|
||||
p_max_rows IN NUMBER DEFAULT 1000,
|
||||
p_insert_all_size IN NUMBER DEFAULT 10)
|
||||
p_table_name IN VARCHAR2,
|
||||
p_data_scn IN NUMBER,
|
||||
p_max_rows IN NUMBER DEFAULT 1000,
|
||||
p_insert_style IN VARCHAR2 DEFAULT 'INSERT',
|
||||
p_insert_all_size IN NUMBER DEFAULT 10,
|
||||
p_exclude_columns_list IN VARCHAR2 DEFAULT NULL)
|
||||
IS
|
||||
v_insert_style VARCHAR2(30);
|
||||
v_exclude_columns_list VARCHAR2(32767);
|
||||
v_nls rec_nls;
|
||||
v_query VARCHAR2(32767);
|
||||
v_cursor PLS_INTEGER;
|
||||
@ -1001,6 +1008,12 @@ IS
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
PROCEDURE init IS
|
||||
BEGIN
|
||||
v_insert_style := trim(upper(substr(p_insert_style,1,30)));
|
||||
v_exclude_columns_list := trim(upper(p_exclude_columns_list)) || ':';
|
||||
END;
|
||||
|
||||
PROCEDURE get_session_nls_params IS
|
||||
BEGIN
|
||||
-- Save current values.
|
||||
@ -1190,6 +1203,7 @@ IS
|
||||
where table_name = p_table_name
|
||||
and user_generated = 'YES'
|
||||
and virtual_column = 'NO'
|
||||
and instr(v_exclude_columns_list, ':'||column_name||':') = 0
|
||||
group by table_name
|
||||
) LOOP
|
||||
v_query := i.query;
|
||||
@ -1211,13 +1225,20 @@ IS
|
||||
ELSE
|
||||
dbms_sql.define_column(v_cursor, i, v_buffer_varchar2, c_vc2_max_size);
|
||||
END IF;
|
||||
v_table_insert_prefix := v_table_insert_prefix || v_desc_tab(i).col_name || ',';
|
||||
IF v_insert_style = 'INSERT' THEN
|
||||
v_table_insert_prefix := v_table_insert_prefix || v_desc_tab(i).col_name || ',';
|
||||
END IF;
|
||||
END LOOP;
|
||||
v_table_insert_prefix :=
|
||||
case when p_insert_all_size > 0
|
||||
then 'into '
|
||||
else 'insert into '
|
||||
end || p_table_name || '(' || rtrim(v_table_insert_prefix, ',' ) || ') values (';
|
||||
CASE v_insert_style
|
||||
WHEN 'INSERT' THEN
|
||||
case when p_insert_all_size > 0
|
||||
then 'into '
|
||||
else 'insert into '
|
||||
end || p_table_name || '(' || rtrim(v_table_insert_prefix, ',' ) || ') values ('
|
||||
WHEN 'OM_TAPIGEN' THEN
|
||||
lower(p_table_name) || '_api.create_or_update_row('
|
||||
END;
|
||||
v_ignore_me := dbms_sql.execute(v_cursor);
|
||||
END IF;
|
||||
END parse_query_and_describe_cols;
|
||||
@ -1231,8 +1252,10 @@ IS
|
||||
PROCEDURE create_header IS
|
||||
BEGIN
|
||||
util_clob_append('-- Script generated by PLEX version ' || c_plex_version || ' - more infos here: ' || c_plex_url || c_crlf);
|
||||
util_clob_append('-- Performance Hacks by Connor McDonald: https://connor-mcdonald.com/2019/05/17/hacking-together-faster-inserts/' || c_crlf);
|
||||
util_clob_append('-- For strange line end replacements a big thank to SQL*Plus: https://support.oracle.com/epmos/faces/DocumentDisplay?id=2377701.1 (SQL Failed With ORA-1756 In Sqlplus But Works In SQL Developer)' || c_crlf);
|
||||
if v_insert_style = 'INSERT' then
|
||||
util_clob_append('-- Performance Hacks by Connor McDonald: https://connor-mcdonald.com/2019/05/17/hacking-together-faster-inserts/' || c_crlf);
|
||||
util_clob_append('-- For strange line end replacements a big thank to SQL*Plus: https://support.oracle.com/epmos/faces/DocumentDisplay?id=2377701.1 (SQL Failed With ORA-1756 In Sqlplus But Works In SQL Developer)' || c_crlf);
|
||||
end if;
|
||||
util_clob_append('prompt - insert xxx rows into ' || p_table_name || ' (exported ' || to_char(systimestamp,'YYYY-MM-DD hh24:mi:ssxff TZR') || ')' || c_crlf);
|
||||
util_clob_append('set define off feedback off sqlblanklines on' || c_crlf);
|
||||
util_clob_append('alter session set cursor_sharing = force;' || c_crlf);
|
||||
@ -1253,12 +1276,15 @@ IS
|
||||
if v_data_count = 1 then
|
||||
create_header;
|
||||
end if;
|
||||
if p_insert_all_size > 0 and mod(v_data_count, p_insert_all_size) = 1 then
|
||||
if v_insert_style = 'INSERT' and p_insert_all_size > 0 and mod(v_data_count, p_insert_all_size) = 1 then
|
||||
util_clob_append('insert all' || c_crlf);
|
||||
end if;
|
||||
line_append(v_table_insert_prefix);
|
||||
--> process row
|
||||
FOR i IN 1..v_col_count LOOP
|
||||
IF v_insert_style = 'OM_TAPIGEN' THEN
|
||||
line_append('p_' || lower(v_desc_tab(i).col_name) || '=>');
|
||||
END IF;
|
||||
IF v_desc_tab(i).col_type = c_clob THEN
|
||||
dbms_sql.column_value(v_cursor, i, v_buffer_clob);
|
||||
process_clob_buffer;
|
||||
@ -1282,15 +1308,15 @@ IS
|
||||
process_varchar2_buffer('STRING');
|
||||
END IF;
|
||||
END IF;
|
||||
if i != v_col_count then
|
||||
if i != v_col_count then
|
||||
line_append(',');
|
||||
else
|
||||
line_append(')' || case when p_insert_all_size < 1 then ';' end);
|
||||
line_append(')' || case when v_insert_style = 'OM_TAPIGEN' or p_insert_all_size < 1 then ';' end);
|
||||
line_flush_cache;
|
||||
end if;
|
||||
END LOOP;
|
||||
--< end process row
|
||||
if p_insert_all_size > 0 and mod(v_data_count, p_insert_all_size) = 0 then
|
||||
if v_insert_style = 'INSERT' and p_insert_all_size > 0 and mod(v_data_count, p_insert_all_size) = 0 then
|
||||
util_clob_append('select * from dual;' || c_crlf);
|
||||
end if;
|
||||
|
||||
@ -1305,7 +1331,7 @@ IS
|
||||
if v_data_count = 0 then
|
||||
util_clob_append('Prompt Nothing to insert - there was no data in the source table ' || p_table_name || c_crlf);
|
||||
else
|
||||
if p_insert_all_size > 0 and mod(v_data_count, p_insert_all_size) != 0 then
|
||||
if V_insert_style = 'INSERT' and p_insert_all_size > 0 and mod(v_data_count, p_insert_all_size) != 0 then
|
||||
util_clob_append('select * from dual;' || c_crlf);
|
||||
end if;
|
||||
util_clob_append('end;' || c_crlf);
|
||||
@ -1330,6 +1356,7 @@ IS
|
||||
BEGIN
|
||||
IF p_table_name IS NOT NULL THEN
|
||||
--dbms_lob.createtemporary(v_buffer_clob, true);
|
||||
init;
|
||||
get_session_nls_params;
|
||||
parse_query_and_describe_cols;
|
||||
create_data;
|
||||
@ -2337,13 +2364,17 @@ SELECT table_name,
|
||||
v_file_path := v_path.to_data || '/' || v_rec.table_name || '.sql';
|
||||
util_log_start(v_file_path);
|
||||
util_clob_table_to_insert(
|
||||
p_table_name => v_rec.table_name,
|
||||
p_data_scn => v_data_scn,
|
||||
p_max_rows => p_data_max_rows,
|
||||
p_insert_all_size => to_number(nvl(regexp_substr(p_data_format,'insert:(\d+)',1,1,'i',1), '10')));
|
||||
p_table_name => v_rec.table_name,
|
||||
p_data_scn => v_data_scn,
|
||||
p_max_rows => p_data_max_rows,
|
||||
p_insert_style => 'INSERT',
|
||||
p_insert_all_size => to_number(nvl(regexp_substr(p_data_format,':(\d+)',1,1,'i',1), '10')),
|
||||
p_exclude_columns_list => regexp_substr(p_data_format,'(:\w+){1,}')
|
||||
);
|
||||
util_clob_add_to_export_files(
|
||||
p_export_files => v_export_files,
|
||||
p_name => v_file_path);
|
||||
p_name => v_file_path
|
||||
);
|
||||
v_files.data_(v_files.data_.count + 1) := v_file_path;
|
||||
util_log_stop;
|
||||
EXCEPTION
|
||||
@ -2351,6 +2382,31 @@ SELECT table_name,
|
||||
util_log_error(v_file_path);
|
||||
END;
|
||||
END IF;
|
||||
|
||||
-- insert with table API (OM_TAPIGEN style)
|
||||
IF upper(p_data_format) LIKE '%OM_TAPIGEN%' THEN
|
||||
BEGIN
|
||||
v_file_path := v_path.to_data || '/' || v_rec.table_name || '.api.sql';
|
||||
util_log_start(v_file_path);
|
||||
util_clob_table_to_insert(
|
||||
p_table_name => v_rec.table_name,
|
||||
p_data_scn => v_data_scn,
|
||||
p_max_rows => p_data_max_rows,
|
||||
p_insert_style => 'OM_TAPIGEN',
|
||||
p_exclude_columns_list => regexp_substr(p_data_format,'(:\w+){1,}')
|
||||
);
|
||||
util_clob_add_to_export_files(
|
||||
p_export_files => v_export_files,
|
||||
p_name => v_file_path
|
||||
);
|
||||
v_files.data_(v_files.data_.count + 1) := v_file_path;
|
||||
util_log_stop;
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
util_log_error(v_file_path);
|
||||
END;
|
||||
END IF;
|
||||
|
||||
END LOOP;
|
||||
CLOSE v_cur;
|
||||
|
||||
@ -2951,7 +3007,7 @@ BEGIN
|
||||
$end
|
||||
IF p_include_data THEN
|
||||
process_data;
|
||||
if upper(p_data_format) LIKE '%INSERT%' then
|
||||
if upper(p_data_format) LIKE '%INSERT%' or upper(p_data_format) LIKE '%OM_TAPIGEN%' then
|
||||
create_load_data_file;
|
||||
end if;
|
||||
END IF;
|
||||
@ -3092,6 +3148,37 @@ END;
|
||||
|
||||
--------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
PROCEDURE download (
|
||||
p_blob IN BLOB,
|
||||
p_name IN VARCHAR2 )
|
||||
IS
|
||||
-- we need to avoid PLS-00363: expression 'P_BLOB' cannot be used as an assignment target
|
||||
v_blob blob := p_blob;
|
||||
BEGIN
|
||||
owa_util.mime_header('application/octet', false);
|
||||
htp.p('Content-length:' || dbms_lob.getlength(v_blob));
|
||||
htp.p('Content-Disposition: attachment; filename="' || p_name || '"');
|
||||
|
||||
-- the browser should not cache the file
|
||||
htp.p('Cache-Control: must-revalidate, max-age=0');
|
||||
htp.p('Expires: Thu, 01 Jan 1970 01:00:00 CET');
|
||||
|
||||
owa_util.http_header_close;
|
||||
wpg_docload.download_file(v_blob);
|
||||
END download;
|
||||
|
||||
--------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
PROCEDURE download (
|
||||
p_clob IN CLOB,
|
||||
p_name IN VARCHAR2 )
|
||||
IS
|
||||
BEGIN
|
||||
download(util_clob_to_blob(p_clob), p_name);
|
||||
END download;
|
||||
|
||||
--------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
FUNCTION view_error_log RETURN tab_error_log PIPELINED IS
|
||||
BEGIN
|
||||
FOR i IN 1..g_errlog.count LOOP
|
||||
|
||||
36
src/PLEX.pks
36
src/PLEX.pks
@ -224,7 +224,6 @@ set termout on
|
||||
**/
|
||||
|
||||
|
||||
|
||||
PROCEDURE add_query (
|
||||
p_query IN VARCHAR2, -- The query itself
|
||||
p_file_name IN VARCHAR2, -- File name like 'Path/to/your/file-without-extension'.
|
||||
@ -245,7 +244,6 @@ END;
|
||||
**/
|
||||
|
||||
|
||||
|
||||
FUNCTION queries_to_csv (
|
||||
p_delimiter IN VARCHAR2 DEFAULT ',', -- The column delimiter.
|
||||
p_quote_mark IN VARCHAR2 DEFAULT '"', -- Used when the data contains the delimiter character.
|
||||
@ -359,7 +357,6 @@ spool off
|
||||
**/
|
||||
|
||||
|
||||
|
||||
FUNCTION to_zip (
|
||||
p_file_collection IN tab_export_files) -- The file collection to zip.
|
||||
RETURN BLOB;
|
||||
@ -380,6 +377,7 @@ END;
|
||||
```
|
||||
**/
|
||||
|
||||
|
||||
FUNCTION to_base64(
|
||||
p_blob IN BLOB) -- The BLOB to convert.
|
||||
RETURN CLOB;
|
||||
@ -398,6 +396,27 @@ END;
|
||||
```
|
||||
**/
|
||||
|
||||
|
||||
PROCEDURE download (
|
||||
p_blob IN BLOB,
|
||||
p_name IN VARCHAR2 );
|
||||
/**
|
||||
|
||||
Download a file based on a BLOB.
|
||||
|
||||
**/
|
||||
|
||||
|
||||
PROCEDURE download (
|
||||
p_clob IN CLOB,
|
||||
p_name IN VARCHAR2 );
|
||||
/**
|
||||
|
||||
Download a file based on a CLOB.
|
||||
|
||||
**/
|
||||
|
||||
|
||||
FUNCTION view_error_log RETURN tab_error_log PIPELINED;
|
||||
/**
|
||||
View the error log from the last plex run. The internal array for the error log is cleared on each call of BackApp or Queries_to_CSV.
|
||||
@ -534,10 +553,13 @@ PROCEDURE util_clob_query_to_csv (
|
||||
p_header_prefix IN VARCHAR2 DEFAULT NULL);
|
||||
|
||||
PROCEDURE util_clob_table_to_insert (
|
||||
p_table_name IN VARCHAR2,
|
||||
p_data_scn IN NUMBER,
|
||||
p_max_rows IN NUMBER DEFAULT 1000,
|
||||
p_insert_all_size IN NUMBER DEFAULT 10);
|
||||
p_table_name IN VARCHAR2,
|
||||
p_data_scn IN NUMBER,
|
||||
p_max_rows IN NUMBER DEFAULT 1000,
|
||||
p_insert_style IN VARCHAR2 DEFAULT 'INSERT', -- can be INSERT or OM_TAPIGEN
|
||||
p_insert_all_size IN NUMBER DEFAULT 10,
|
||||
p_exclude_columns_list IN VARCHAR2 DEFAULT NULL -- a colon separated list of columns that should be excluded for the insert operation (for example audit columns which are populated automatically) FIXME: support the auto detection of an column prefix
|
||||
);
|
||||
|
||||
PROCEDURE util_clob_create_runtime_log (p_export_files IN OUT NOCOPY tab_export_files);
|
||||
|
||||
|
||||
@ -3,14 +3,14 @@ var fs = require('fs');
|
||||
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')})
|
||||
.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',
|
||||
'src/plex_uninstall.sql',
|
||||
'plex_uninstall.sql'
|
||||
);
|
||||
@ -1,4 +1,10 @@
|
||||
set define off feedback off
|
||||
set define off
|
||||
set serveroutput on
|
||||
set verify off
|
||||
set feedback off
|
||||
set linesize 240
|
||||
set trimout on
|
||||
set trimspool on
|
||||
whenever sqlerror exit sql.sqlcode rollback
|
||||
|
||||
prompt
|
||||
@ -45,11 +51,11 @@ END;
|
||||
/
|
||||
|
||||
prompt Compile package plex (spec)
|
||||
@plex.pks
|
||||
@PLEX.pks
|
||||
show errors
|
||||
|
||||
prompt Compile package plex (body)
|
||||
@plex.pkb
|
||||
@PLEX.pkb
|
||||
show errors
|
||||
|
||||
prompt ============================================================
|
||||
|
||||
@ -1,31 +1,37 @@
|
||||
set define off feedback off
|
||||
set define off
|
||||
set serveroutput on
|
||||
set verify off
|
||||
set feedback off
|
||||
set linesize 240
|
||||
set trimout on
|
||||
set trimspool on
|
||||
whenever sqlerror exit sql.sqlcode rollback
|
||||
|
||||
prompt
|
||||
prompt Uninstalling PL/SQL Export Utilities
|
||||
prompt ====================================
|
||||
prompt ============================================================
|
||||
prompt Drop package plex if exists (body)
|
||||
BEGIN
|
||||
FOR i IN (SELECT object_type,
|
||||
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;
|
||||
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,
|
||||
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;
|
||||
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 ============================================================
|
||||
prompt Uninstallation Done
|
||||
prompt
|
||||
prompt
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user