plsqlwks 0.2.1__tar.gz → 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/PKG-INFO +6 -2
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/README.md +5 -1
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/doc/API.md +5 -1
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/doc/ARCHITECTURE.md +30 -2
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/doc/PLUGIN_CATALOG.md +53 -7
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/doc/QUICKSTART.md +3 -2
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/__init__.py +1 -1
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/db/table_export.py +79 -38
- plsqlwks-0.2.2/plsqlwks/db/table_export_catalog.py +488 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/sqlsplit.py +10 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/app.py +6 -1
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/buffer.py +47 -1
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/clipboard.py +22 -5
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/dialogs.py +17 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/editor_controller.py +1 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/ports.py +2 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/query_controller.py +3 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/renderer.py +102 -16
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/syntax.py +140 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/table_export.py +10 -4
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks.egg-info/SOURCES.txt +1 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/doc/COMPATIBILITY.md +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/doc/PLUGINS.md +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/doc/QUICKSTART.html +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/license.txt +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/__main__.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/cli.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/config/__init__.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/config/loader.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/config/models.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/config/paths.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/config/session.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/config/settings.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/db/__init__.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/db/ddl_remap.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/db/dependencies.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/db/editing.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/db/execution.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/db/explain.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/db/health.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/db/identifiers.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/db/metadata.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/db/models.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/db/session.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/db/sql_analysis.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/db/timestamps.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/db/transactions.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/exporting.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/plugins/__init__.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/plugins/api.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/plugins/loader.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/plugins/management.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/sqlbinds.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/__init__.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/application_controller.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/browser.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/catalog.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/code_generation.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/command_dispatcher.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/commands.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/completion.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/constants.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/db_operations.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/db_session.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/db_worker.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/dependency_walker.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/display.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/documents.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/errors.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/help.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/input_controller.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/key_reader.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/keys.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/menu.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/output_selection.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/plugin_host.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/result_controller.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/result_export.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/result_presenter.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/results.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/sql.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/sqlplus.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/state.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/ui/viewport.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plsqlwks/workspace.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/csv-export/install.plw +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/csv-export/payload/__init__.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/csv-export/payload/plugin.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/csv-export/payload/support.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/csv-export/payload/writer.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/csv2oratab/install.plw +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/csv2oratab/payload/__init__.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/csv2oratab/payload/csv2oratab.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/csv2oratab/payload/plugin.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/dependencies-walker/install.plw +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/dependencies-walker/payload/__init__.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/dependencies-walker/payload/plugin.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/html-export/install.plw +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/html-export/payload/__init__.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/html-export/payload/html_exporting.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/html-export/payload/plugin.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/html-export/payload/support.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/html-export/payload/writer.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/packages/csv-export-1.0.0.plwgn +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/packages/csv2oratab-0.1.0.plwgn +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/packages/dependencies-walker-0.1.0.plwgn +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/packages/html-export-1.0.0.plwgn +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/packages/sqlplus-0.1.0.plwgn +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/packages/table-ddl-export-0.1.1.plwgn +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/packages/xlsx-export-1.0.0.plwgn +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/sqlplus/install.plw +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/sqlplus/payload/__init__.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/sqlplus/payload/plugin.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/table-ddl-export/install.plw +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/table-ddl-export/payload/__init__.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/table-ddl-export/payload/plugin.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/xlsx-export/install.plw +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/xlsx-export/payload/__init__.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/xlsx-export/payload/plugin.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/xlsx-export/payload/support.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/plugins/xlsx-export/payload/xlsx_exporting.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/pyproject.toml +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/pytest.ini +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/rchar.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/requirements.txt +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/setup.cfg +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/tests/conftest.py +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/tests/fixtures/config_exports.txt +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/tests/fixtures/ui_exports.txt +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/tools/putty_keys.ps1 +0 -0
- {plsqlwks-0.2.1 → plsqlwks-0.2.2}/tools/windows_keys.cmd +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: plsqlwks
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: An ncurses SQL and PL/SQL workspace for Oracle databases.
|
|
5
5
|
Author: unu2000
|
|
6
6
|
License-Expression: LicenseRef-plsqlwks-Donationware
|
|
@@ -749,12 +749,16 @@ also works from Command Prompt and continues to support PuTTY.
|
|
|
749
749
|
| `Ctrl+=` | Reconnect |
|
|
750
750
|
|
|
751
751
|
Use `/` on a line by itself after PL/SQL objects or anonymous blocks when running a script.
|
|
752
|
+
With no selection, `F11` asks: **To run the whole buffer, press Enter. Esc cancels.**
|
|
753
|
+
Press Enter to continue or Esc/Ctrl+C to cancel before bind prompts and execution.
|
|
754
|
+
Executing selected text does not require this additional confirmation.
|
|
752
755
|
Script execution reports statement progress as `n/total` and stops at the first
|
|
753
756
|
failed statement while preserving earlier results. Scripts are sent directly to
|
|
754
757
|
Oracle, not through SQL*Plus or SQLcl: client commands such as `PROMPT`, `SPOOL`,
|
|
755
758
|
and `SET SERVEROUTPUT`, and `&`/`&&` substitution variables, are rejected before
|
|
756
759
|
bind prompts or execution. Oracle SQL statements such as `SET TRANSACTION`
|
|
757
|
-
remain supported.
|
|
760
|
+
remain supported. A standalone `SET DEFINE OFF` line is accepted locally and
|
|
761
|
+
omitted from database execution. It does not enable substitution variables.
|
|
758
762
|
Execution and explain errors report mapped editor line and column diagnostics.
|
|
759
763
|
The cursor moves only when the buffer still matches the source that was sent to
|
|
760
764
|
Oracle; if it changed while the operation ran, the result warns about the stale
|
|
@@ -715,12 +715,16 @@ also works from Command Prompt and continues to support PuTTY.
|
|
|
715
715
|
| `Ctrl+=` | Reconnect |
|
|
716
716
|
|
|
717
717
|
Use `/` on a line by itself after PL/SQL objects or anonymous blocks when running a script.
|
|
718
|
+
With no selection, `F11` asks: **To run the whole buffer, press Enter. Esc cancels.**
|
|
719
|
+
Press Enter to continue or Esc/Ctrl+C to cancel before bind prompts and execution.
|
|
720
|
+
Executing selected text does not require this additional confirmation.
|
|
718
721
|
Script execution reports statement progress as `n/total` and stops at the first
|
|
719
722
|
failed statement while preserving earlier results. Scripts are sent directly to
|
|
720
723
|
Oracle, not through SQL*Plus or SQLcl: client commands such as `PROMPT`, `SPOOL`,
|
|
721
724
|
and `SET SERVEROUTPUT`, and `&`/`&&` substitution variables, are rejected before
|
|
722
725
|
bind prompts or execution. Oracle SQL statements such as `SET TRANSACTION`
|
|
723
|
-
remain supported.
|
|
726
|
+
remain supported. A standalone `SET DEFINE OFF` line is accepted locally and
|
|
727
|
+
omitted from database execution. It does not enable substitution variables.
|
|
724
728
|
Execution and explain errors report mapped editor line and column diagnostics.
|
|
725
729
|
The cursor moves only when the buffer still matches the source that was sent to
|
|
726
730
|
Oracle; if it changed while the operation ran, the result warns about the stale
|
|
@@ -547,7 +547,11 @@ Required source-schema tables and views are followed recursively; tables include
|
|
|
547
547
|
their constraints, indexes, triggers, and detected sequences. Selection of callers stays
|
|
548
548
|
limited to direct references to the initially checked tables. Definitions are
|
|
549
549
|
ordered by creation dependencies across object types; unresolved prerequisites
|
|
550
|
-
and genuine dependency cycles are reported in the generated script.
|
|
550
|
+
and genuine dependency cycles are reported in the generated script. Discovery
|
|
551
|
+
prefers ALL_* catalogs and supplements them with accessible DBA_* views.
|
|
552
|
+
Cross-schema definitions use catalog rendering for supported objects and
|
|
553
|
+
DBMS_METADATA fallback for advanced or incomplete metadata. Own-schema
|
|
554
|
+
definitions retain DBMS_METADATA extraction.
|
|
551
555
|
|
|
552
556
|
On success the host opens and activates a new unsaved tab containing the generated
|
|
553
557
|
SQL, with keyboard focus in the editor. Cancellation,
|
|
@@ -47,6 +47,32 @@ UI command as force-disconnected, quarantines that worker, and closes the exact
|
|
|
47
47
|
captured client connection on a best-effort control thread. No server-side kill
|
|
48
48
|
or process termination is attempted, and other tab workers are unaffected.
|
|
49
49
|
|
|
50
|
+
## Editor rendering
|
|
51
|
+
|
|
52
|
+
The SQL document remains in memory, with a lazy `ViewportSyntax` cache owned by
|
|
53
|
+
each `Buffer`. The cache keeps line-boundary lexer states and code-bracket
|
|
54
|
+
positions for scanned lines, but retains tokens only for the visible rows and
|
|
55
|
+
one screen above and below. Buffer edits, completion, and undo/redo report their
|
|
56
|
+
changed line ranges. Parsing resumes from the first invalid line and reuses the
|
|
57
|
+
unchanged suffix once its incoming lexer state agrees again. Display and cursor
|
|
58
|
+
movement do not join or tokenize the entire document.
|
|
59
|
+
|
|
60
|
+
Cold jumps and edits that change multiline strings or comments may need context
|
|
61
|
+
from earlier lines. Parsing and distant bracket searches run in cooperative
|
|
62
|
+
8 ms batches on the curses thread. Unresolved rows appear immediately in the
|
|
63
|
+
default text style; accurate highlighting follows as context becomes available.
|
|
64
|
+
The event loop polls input and database completions between batches, without
|
|
65
|
+
the normal 200 ms idle delay. The budget is checked between lines and bracket
|
|
66
|
+
positions; an exceptionally long individual line can exceed it.
|
|
67
|
+
|
|
68
|
+
`Renderer` retains a curses window sized to the editor viewport. Small vertical
|
|
69
|
+
scrolls move its existing rows, and row signatures limit painting to exposed or
|
|
70
|
+
changed text, selection, and bracket overlays. Geometry or active-buffer changes
|
|
71
|
+
invalidate the appropriate rows. The root screen and editor window compose via
|
|
72
|
+
`noutrefresh()` and one `doupdate()`, restoring the active cursor after composition.
|
|
73
|
+
Recomposing the retained editor also restores it after overlapping dialogs and
|
|
74
|
+
external terminal use. No document-sized curses pad or rendering thread is used.
|
|
75
|
+
|
|
50
76
|
## Transaction state
|
|
51
77
|
|
|
52
78
|
Each worker-owned `OracleWorkspace` is the detailed source of truth. It tracks
|
|
@@ -116,8 +142,10 @@ The Table DDL Export command delegates through `start_table_ddl_export()`.
|
|
|
116
142
|
Its host controller owns the table checklist with incremental substring filtering
|
|
117
143
|
and cancellable worker jobs. Its database service discovers related sequences
|
|
118
144
|
and directly referencing source-schema program units using bound dictionary
|
|
119
|
-
reads, orders included routines by dependency, and
|
|
120
|
-
|
|
145
|
+
reads, orders included routines by dependency, and supplements ALL_* discovery
|
|
146
|
+
with accessible DBA_* views. Cross-schema definitions use conservative catalog
|
|
147
|
+
renderers; own-schema and unsupported definitions use per-handle DBMS_METADATA
|
|
148
|
+
transforms. Generation creates a fresh unsaved tab only for the originating
|
|
121
149
|
editor/session. Identifier-aware remapping preserves literals and comments and
|
|
122
150
|
reports ambiguous references. The plugin itself never receives database or UI
|
|
123
151
|
internals and generated SQL is never automatically executed.
|
|
@@ -70,12 +70,21 @@ Type in the table list to filter names immediately by a case-insensitive literal
|
|
|
70
70
|
substring. **Backspace** edits the filter, **Ctrl+L** clears it, and **/** opens
|
|
71
71
|
an optional filter prompt for text containing spaces. An empty filter shows all
|
|
72
72
|
tables. Use arrows/Page Up/Page Down/Home/End to navigate, **Space** to toggle
|
|
73
|
-
an entry, **
|
|
73
|
+
an entry, **F2** to select matching tables, and **Ctrl+U** to deselect them.
|
|
74
74
|
Checked tables stay selected when hidden by a filter; the screen shows both
|
|
75
75
|
total and visible selection counts. **Enter** exports the checked tables,
|
|
76
76
|
including hidden selections. **Esc** or **Ctrl+C** cancels, including during
|
|
77
77
|
metadata reads. At least one table must be checked.
|
|
78
78
|
|
|
79
|
+
During metadata reads and DDL generation, the screen shows **Elapsed: HH:MM:SS**.
|
|
80
|
+
The timer resets for each operation and excludes time spent selecting tables
|
|
81
|
+
or answering prompts. There is no percentage estimate.
|
|
82
|
+
|
|
83
|
+
Generated scripts begin with `SET DEFINE OFF` so SQL*Plus does not prompt for
|
|
84
|
+
ampersands in definitions, such as an `&afcid` string literal. PLSQLWKS accepts
|
|
85
|
+
this standalone directive locally without sending it to Oracle. Generation
|
|
86
|
+
opens the script in a new unsaved editor tab; it does not execute it.
|
|
87
|
+
|
|
79
88
|
There is no sequence-selection dialog. Source-schema sequences referenced by
|
|
80
89
|
defaults and Oracle-recorded table/trigger/program-unit dependencies are included
|
|
81
90
|
automatically. Trigger bodies are also scanned for explicit NEXTVAL/CURRVAL
|
|
@@ -89,7 +98,11 @@ For ordinary sequences, START WITH uses the exporting session's CURRVAL plus
|
|
|
89
98
|
INCREMENT BY when CURRVAL is defined, taking priority over the metadata cache
|
|
90
99
|
boundary. A cycling sequence wraps at its configured bounds; an exhausted
|
|
91
100
|
noncycling sequence stops the export with an error. If CURRVAL is undefined in
|
|
92
|
-
that session (ORA-08002), the
|
|
101
|
+
that session (ORA-08002), the metadata START WITH is preserved. Cross-schema
|
|
102
|
+
catalog rendering obtains that snapshot from ALL_SEQUENCES.LAST_NUMBER or,
|
|
103
|
+
when available, DBA_SEQUENCES.LAST_NUMBER. If the account cannot read CURRVAL,
|
|
104
|
+
the snapshot is retained after confirming the sequence remains catalog-visible.
|
|
105
|
+
Dictionary access alone does not grant access to sequence values.
|
|
93
106
|
Scalable/sharded sequences retain their metadata restart position with a review
|
|
94
107
|
comment because raw CURRVAL includes offsets. Other sequence options remain intact.
|
|
95
108
|
|
|
@@ -147,11 +160,44 @@ SQL, ambiguous qualifiers, and source qualifiers in strings receive review
|
|
|
147
160
|
notes. Dependencies outside the export appear as prerequisites in the script
|
|
148
161
|
header; Oracle metadata cannot discover every dynamic or indirect dependency.
|
|
149
162
|
|
|
150
|
-
The
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
163
|
+
The host prefers ALL_* catalog views and supplements discovery with readable
|
|
164
|
+
DBA_* views, even when ALL_* returns only part of the schema. For example, a
|
|
165
|
+
sequence absent from ALL_SEQUENCES can be exported using DBA_SEQUENCES. Access
|
|
166
|
+
is checked per view using actual queries; the exporter neither enables roles
|
|
167
|
+
nor requests grants. Catalog visibility limits which dependencies can be found.
|
|
168
|
+
|
|
169
|
+
For objects owned by the session user, definitions still come from per-handle
|
|
170
|
+
DBMS_METADATA calls. Cross-schema exports first render ordinary permanent heap
|
|
171
|
+
tables, scalar columns/defaults, constraints, B-tree/function-based indexes,
|
|
172
|
+
global sequences, ordinary views, and readable PL/SQL source from catalog
|
|
173
|
+
metadata. Stored source and view text are read in full. Changing CURRENT_SCHEMA
|
|
174
|
+
does not change ownership or metadata privileges.
|
|
175
|
+
|
|
176
|
+
Catalog rendering supports identity, virtual, invisible, and collated table
|
|
177
|
+
columns. Identity generation modes and sequence options are preserved; restart
|
|
178
|
+
uses this session's readable CURRVAL plus the increment, or the backing
|
|
179
|
+
sequence's catalog LAST_NUMBER snapshot if CURRVAL is undefined or inaccessible.
|
|
180
|
+
Export never calls NEXTVAL and does not recreate the internal identity sequence
|
|
181
|
+
separately. These snapshots may leave cache gaps and do not track concurrent
|
|
182
|
+
sessions. If neither restart source is usable, export requires metadata instead
|
|
183
|
+
of resetting numbering to the identity's initial value.
|
|
184
|
+
|
|
185
|
+
Virtual expressions are read in full. Visible columns retain their current
|
|
186
|
+
SELECT * order, including columns made visible again; invisible columns follow
|
|
187
|
+
in internal-column order. System-generated hidden columns are recreated by their
|
|
188
|
+
constraints/indexes. Named table and column collations are preserved, including
|
|
189
|
+
the original columns behind internal collation keys. Named collations require
|
|
190
|
+
the destination database to support data-bound collation (MAX_STRING_SIZE=EXTENDED).
|
|
191
|
+
|
|
192
|
+
Advanced features use DBMS_METADATA instead, including partitioned/IOT/external/
|
|
193
|
+
object tables, encrypted columns, edition-specific virtual-column clauses, specialized indexes
|
|
194
|
+
(including descending indexes), constrained or specialized views, and session/
|
|
195
|
+
scalable/sharded sequences. This fallback requires the object owner or appropriate
|
|
196
|
+
DBMS_METADATA catalog privileges, such as SELECT_CATALOG_ROLE. Object grants or
|
|
197
|
+
readable DBA_* views do not by themselves guarantee DBMS_METADATA access.
|
|
198
|
+
If both paths fail for an included object, generation stops with its name and
|
|
199
|
+
the reasons, including the column and unsupported feature or missing column
|
|
200
|
+
metadata where applicable; no incomplete export buffer is opened.
|
|
155
201
|
|
|
156
202
|
Review and save the script normally. Export does not execute SQL, create the
|
|
157
203
|
destination schema, copy rows, grant privileges, commit, roll back, or drain
|
|
@@ -157,8 +157,9 @@ select count(*) as visible_objects
|
|
|
157
157
|
from user_objects;
|
|
158
158
|
```
|
|
159
159
|
|
|
160
|
-
`F11` runs the whole buffer (or the selection).
|
|
161
|
-
|
|
160
|
+
`F11` runs the whole buffer (or the selection). When running the whole buffer,
|
|
161
|
+
press Enter at the confirmation prompt to continue, or Esc/Ctrl+C to cancel.
|
|
162
|
+
Press `F6` to switch between normal results and captured `DBMS_OUTPUT`.
|
|
162
163
|
|
|
163
164
|
### Page through a larger result
|
|
164
165
|
|
|
@@ -12,6 +12,7 @@ import oracledb
|
|
|
12
12
|
|
|
13
13
|
from .ddl_remap import ddl_tokens, function_references, remap_sql, sequence_references
|
|
14
14
|
from .identifiers import normalize_identifier, quote_identifier
|
|
15
|
+
from .table_export_catalog import CatalogUnavailable, ExportCatalog, error_code, sequence_restart_value
|
|
15
16
|
|
|
16
17
|
_METADATA_TYPES = {'PACKAGE': 'PACKAGE_SPEC', 'PACKAGE BODY': 'PACKAGE_BODY'}
|
|
17
18
|
_SEQUENCE_START = re.compile(r'START\s+WITH\s+([+-]?\d+)', re.IGNORECASE)
|
|
@@ -125,6 +126,8 @@ class TableExportService:
|
|
|
125
126
|
def __init__(self, connection: oracledb.Connection, cancelled: Callable[[], bool] = lambda: False):
|
|
126
127
|
self.connection = connection
|
|
127
128
|
self.cancelled = cancelled
|
|
129
|
+
self.catalog = ExportCatalog(lambda sql, **binds: self.rows(sql, **binds))
|
|
130
|
+
self._session_user: str | None = None
|
|
128
131
|
|
|
129
132
|
def check_cancelled(self) -> None:
|
|
130
133
|
if self.cancelled():
|
|
@@ -139,27 +142,35 @@ class TableExportService:
|
|
|
139
142
|
def current_schema(self) -> str:
|
|
140
143
|
return str(self.rows("select sys_context('USERENV', 'CURRENT_SCHEMA') from dual")[0][0])
|
|
141
144
|
|
|
145
|
+
def session_user(self) -> str:
|
|
146
|
+
if self._session_user is None:
|
|
147
|
+
self._session_user = str(self.rows("select sys_context('USERENV', 'SESSION_USER') from dual")[0][0])
|
|
148
|
+
return self._session_user
|
|
149
|
+
|
|
142
150
|
def tables(self, schema: str) -> tuple[str, ...]:
|
|
143
|
-
|
|
151
|
+
materialized = {row[0] for row in self.catalog.rows(
|
|
152
|
+
'select mview_name from all_mviews where owner = :owner', owner=schema,
|
|
153
|
+
)}
|
|
154
|
+
return tuple(sorted(row[0] for row in self.catalog.rows(
|
|
144
155
|
"""select table_name from all_tables t where owner = :owner
|
|
145
156
|
and nested = 'NO' and secondary = 'N'
|
|
146
157
|
and (iot_type is null or iot_type = 'IOT')
|
|
147
158
|
and table_name not like 'BIN$%'
|
|
148
|
-
and not exists (select 1 from all_mviews m where m.owner = t.owner and m.mview_name = t.table_name)
|
|
149
159
|
order by table_name""", owner=schema,
|
|
150
|
-
))
|
|
160
|
+
) if row[0] not in materialized))
|
|
151
161
|
|
|
152
162
|
def sequences(self, schema: str) -> tuple[str, ...]:
|
|
153
|
-
|
|
163
|
+
identities = {row[0] for row in self.catalog.rows(
|
|
164
|
+
'select sequence_name from all_tab_identity_cols where owner = :owner', owner=schema,
|
|
165
|
+
)}
|
|
166
|
+
return tuple(sorted(row[0] for row in self.catalog.rows(
|
|
154
167
|
"""select s.sequence_name from all_sequences s where s.sequence_owner = :owner
|
|
155
|
-
and not exists (select 1 from all_tab_identity_cols i
|
|
156
|
-
where i.owner = s.sequence_owner and i.sequence_name = s.sequence_name)
|
|
157
168
|
order by s.sequence_name""", owner=schema,
|
|
158
|
-
))
|
|
169
|
+
) if row[0] not in identities))
|
|
159
170
|
|
|
160
171
|
def table_dependencies(self, obj: ExportObject, known_objects: set[ExportObject]) -> set[ExportObject]:
|
|
161
172
|
dependencies = self.object_dependencies(obj)
|
|
162
|
-
for (default,) in self.rows(
|
|
173
|
+
for (default,) in self.catalog.rows(
|
|
163
174
|
"select data_default from all_tab_cols where owner = :owner and table_name = :name and default_length > 0",
|
|
164
175
|
owner=obj.owner, name=obj.name,
|
|
165
176
|
):
|
|
@@ -173,7 +184,7 @@ class TableExportService:
|
|
|
173
184
|
dependencies = self.object_dependencies(obj)
|
|
174
185
|
# Both FOLLOWS and PRECEDES require the named trigger to exist first;
|
|
175
186
|
# this is creation order, not the firing order of the resulting triggers.
|
|
176
|
-
dependencies.update(ExportObject(owner, name, 'TRIGGER') for owner, name in self.rows(
|
|
187
|
+
dependencies.update(ExportObject(owner, name, 'TRIGGER') for owner, name in self.catalog.rows(
|
|
177
188
|
'''select referenced_trigger_owner, referenced_trigger_name from all_trigger_ordering
|
|
178
189
|
where trigger_owner = :owner and trigger_name = :name''', owner=obj.owner, name=obj.name,
|
|
179
190
|
))
|
|
@@ -183,7 +194,7 @@ class TableExportService:
|
|
|
183
194
|
for sequence in sorted(candidates - dependencies):
|
|
184
195
|
# A token may name a synonym or a PL/SQL record rather than a
|
|
185
196
|
# sequence. Keep dictionary-resolved synonym dependencies intact.
|
|
186
|
-
if self.rows(
|
|
197
|
+
if self.catalog.rows(
|
|
187
198
|
'select sequence_name from all_sequences where sequence_owner = :owner and sequence_name = :name',
|
|
188
199
|
owner=sequence.owner, name=sequence.name,
|
|
189
200
|
):
|
|
@@ -204,7 +215,7 @@ class TableExportService:
|
|
|
204
215
|
visible = known_objects
|
|
205
216
|
if candidate.owner != schema:
|
|
206
217
|
visible = {ExportObject(candidate.owner, candidate.name, _METADATA_TYPES.get(kind, kind))
|
|
207
|
-
for (kind,) in self.rows(
|
|
218
|
+
for (kind,) in self.catalog.rows(
|
|
208
219
|
'select object_type from all_objects where owner = :owner and object_name = :name',
|
|
209
220
|
owner=candidate.owner, name=candidate.name,
|
|
210
221
|
)}
|
|
@@ -218,7 +229,7 @@ class TableExportService:
|
|
|
218
229
|
return dependencies
|
|
219
230
|
|
|
220
231
|
def table_users(self, schema: str, table: str) -> set[ExportObject]:
|
|
221
|
-
return {ExportObject(schema, name, _METADATA_TYPES.get(kind, kind)) for name, kind in self.rows(
|
|
232
|
+
return {ExportObject(schema, name, _METADATA_TYPES.get(kind, kind)) for name, kind in self.catalog.rows(
|
|
222
233
|
"""select distinct name, type from all_dependencies
|
|
223
234
|
where owner = :owner and referenced_owner = :owner and referenced_name = :name
|
|
224
235
|
and referenced_type = 'TABLE' and referenced_link_name is null
|
|
@@ -228,7 +239,7 @@ class TableExportService:
|
|
|
228
239
|
|
|
229
240
|
def object_dependencies(self, obj: ExportObject) -> set[ExportObject]:
|
|
230
241
|
dictionary_kind = {'PACKAGE_SPEC': 'PACKAGE', 'PACKAGE_BODY': 'PACKAGE BODY'}.get(obj.kind, obj.kind)
|
|
231
|
-
references = {ExportObject(owner, name, _METADATA_TYPES.get(kind, kind)) for owner, name, kind in self.rows(
|
|
242
|
+
references = {ExportObject(owner, name, _METADATA_TYPES.get(kind, kind)) for owner, name, kind in self.catalog.rows(
|
|
232
243
|
"""select distinct referenced_owner, referenced_name, referenced_type from all_dependencies
|
|
233
244
|
where owner = :owner and name = :name and type = :kind
|
|
234
245
|
and referenced_owner is not null and referenced_link_name is null""",
|
|
@@ -239,6 +250,19 @@ class TableExportService:
|
|
|
239
250
|
return references
|
|
240
251
|
|
|
241
252
|
def ddl(self, obj: ExportObject, source: str, target: str) -> str:
|
|
253
|
+
self.check_cancelled()
|
|
254
|
+
if obj.owner == self.session_user():
|
|
255
|
+
return self.metadata_ddl(obj, source, target)
|
|
256
|
+
try:
|
|
257
|
+
return self.catalog.ddl(obj.owner, obj.name, obj.kind)
|
|
258
|
+
except CatalogUnavailable as catalog_error:
|
|
259
|
+
self.check_cancelled()
|
|
260
|
+
try:
|
|
261
|
+
return self.metadata_ddl(obj, source, target)
|
|
262
|
+
except RuntimeError as metadata_error:
|
|
263
|
+
raise RuntimeError(f'{obj.label}: {catalog_error}; DBMS_METADATA: {metadata_error}') from metadata_error
|
|
264
|
+
|
|
265
|
+
def metadata_ddl(self, obj: ExportObject, source: str, target: str) -> str:
|
|
242
266
|
self.check_cancelled()
|
|
243
267
|
with self.connection.cursor() as cursor:
|
|
244
268
|
result = cursor.var(oracledb.DB_TYPE_CLOB)
|
|
@@ -298,13 +322,21 @@ class TableExportService:
|
|
|
298
322
|
try:
|
|
299
323
|
current = int(self.rows(f"select to_char({qualified}.currval, 'TM9') from dual")[0][0])
|
|
300
324
|
except oracledb.DatabaseError as exc:
|
|
301
|
-
|
|
325
|
+
code = error_code(exc)
|
|
326
|
+
if code not in {8002, 1031, 2289}:
|
|
302
327
|
raise RuntimeError(f'{obj.label}: cannot read CURRVAL: {exc}') from exc
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
328
|
+
if code != 8002 and not self.catalog.rows(
|
|
329
|
+
'select sequence_name from all_sequences where sequence_owner = :owner and sequence_name = :name',
|
|
330
|
+
owner=obj.owner, name=obj.name,
|
|
331
|
+
):
|
|
332
|
+
raise RuntimeError(f'{obj.label}: sequence disappeared or metadata is no longer accessible') from exc
|
|
333
|
+
reason = 'undefined in this session' if code == 8002 else 'not accessible to this account'
|
|
334
|
+
return f'-- START WITH {saved} from metadata; CURRVAL is {reason}.\n{ddl}'
|
|
335
|
+
rows = self.catalog.rows(
|
|
336
|
+
'''select to_char(increment_by, 'TM9'), to_char(min_value, 'TM9'), to_char(max_value, 'TM9'),
|
|
337
|
+
cycle_flag, scale_flag, sharded_flag
|
|
306
338
|
from all_sequences where sequence_owner = :owner and sequence_name = :name''',
|
|
307
|
-
owner=obj.owner, name=obj.name,
|
|
339
|
+
key=(), owner=obj.owner, name=obj.name,
|
|
308
340
|
)
|
|
309
341
|
if not rows:
|
|
310
342
|
raise RuntimeError(f'{obj.label}: sequence metadata is no longer accessible')
|
|
@@ -312,11 +344,10 @@ class TableExportService:
|
|
|
312
344
|
if scale == 'Y' or sharded == 'Y':
|
|
313
345
|
return f'-- START WITH {saved} from metadata; SCALE/SHARD CURRVAL offsets require manual review.\n{ddl}'
|
|
314
346
|
increment, minimum, maximum = int(increment), int(minimum), int(maximum)
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
restart = minimum if increment > 0 else maximum
|
|
347
|
+
try:
|
|
348
|
+
restart = sequence_restart_value(current, increment, minimum, maximum, cycle)
|
|
349
|
+
except CatalogUnavailable as exc:
|
|
350
|
+
raise RuntimeError(f'{obj.label}: {exc}') from exc
|
|
320
351
|
ddl = ddl[:start.start(1)] + str(restart) + ddl[start.end(1):]
|
|
321
352
|
return (f'-- START WITH {restart} from session CURRVAL {current} and INCREMENT BY {increment}'
|
|
322
353
|
f' (metadata START WITH {saved}).\n{ddl}')
|
|
@@ -331,7 +362,7 @@ class TableExportService:
|
|
|
331
362
|
available_tables = set(self.tables(source))
|
|
332
363
|
if not set(tables) <= available_tables:
|
|
333
364
|
raise ValueError('A selected table disappeared or is no longer accessible; restart the export')
|
|
334
|
-
schema_objects = self.rows('select object_name, object_type from all_objects where owner = :owner', owner=source)
|
|
365
|
+
schema_objects = self.catalog.rows('select object_name, object_type from all_objects where owner = :owner', owner=source)
|
|
335
366
|
known_names = {name for name, kind in schema_objects}
|
|
336
367
|
known_objects = {ExportObject(source, name, _METADATA_TYPES.get(kind, kind)) for name, kind in schema_objects}
|
|
337
368
|
package_bodies = {name for name, kind in schema_objects if kind == 'PACKAGE BODY'}
|
|
@@ -377,43 +408,51 @@ class TableExportService:
|
|
|
377
408
|
table_obj = ExportObject(source, table, 'TABLE')
|
|
378
409
|
progress(f'Reading dependencies: {table_obj.label}', completed_tables, len(included_tables))
|
|
379
410
|
add_references(table_obj, self.table_dependencies(table_obj, known_objects))
|
|
380
|
-
|
|
411
|
+
key_indexes = set(self.catalog.rows(
|
|
412
|
+
"""select index_owner, index_name from all_constraints where owner = :owner
|
|
413
|
+
and table_name = :name and constraint_type in ('P','U') and index_name is not null""",
|
|
414
|
+
owner=source, name=table,
|
|
415
|
+
))
|
|
416
|
+
for owner, name in self.catalog.rows(
|
|
381
417
|
"""select i.owner, i.index_name from all_indexes i
|
|
382
418
|
where i.table_owner = :owner and i.table_name = :name
|
|
383
|
-
and i.index_type not in ('LOB', 'IOT - TOP')
|
|
384
|
-
and not exists (select 1 from all_constraints c where c.owner = :owner
|
|
385
|
-
and c.table_name = :name and c.constraint_type in ('P','U')
|
|
386
|
-
and c.index_owner = i.owner and c.index_name = i.index_name)""", owner=source, name=table,
|
|
419
|
+
and i.index_type not in ('LOB', 'IOT - TOP')""", owner=source, name=table,
|
|
387
420
|
):
|
|
421
|
+
if (owner, name) in key_indexes:
|
|
422
|
+
continue
|
|
388
423
|
obj = ExportObject(owner, name, 'INDEX')
|
|
389
424
|
refs = self.object_dependencies(obj) | {table_obj}
|
|
390
|
-
for (expression,) in self.rows(
|
|
425
|
+
for (expression,) in self.catalog.rows(
|
|
391
426
|
'select column_expression from all_ind_expressions where index_owner = :owner and index_name = :name',
|
|
392
427
|
owner=owner, name=name,
|
|
393
428
|
):
|
|
394
429
|
if expression:
|
|
395
430
|
refs.update(self.expression_dependencies(expression, owner, known_objects))
|
|
396
431
|
add_references(obj, refs)
|
|
397
|
-
for owner, name, body in self.rows(
|
|
432
|
+
for owner, name, body in self.catalog.rows(
|
|
398
433
|
'select owner, trigger_name, trigger_body from all_triggers where table_owner = :owner and table_name = :name',
|
|
399
|
-
owner=source, name=table,
|
|
434
|
+
key=(0, 1), owner=source, name=table,
|
|
400
435
|
):
|
|
401
436
|
obj = ExportObject(owner, name, 'TRIGGER')
|
|
402
437
|
add_references(obj, self.trigger_dependencies(obj, body) | {table_obj})
|
|
403
|
-
for owner, name, ref_owner,
|
|
404
|
-
"""select c.owner, c.constraint_name, c.r_owner,
|
|
405
|
-
from all_constraints c
|
|
406
|
-
on p.owner = c.r_owner and p.constraint_name = c.r_constraint_name
|
|
438
|
+
for owner, name, ref_owner, ref_constraint in self.catalog.rows(
|
|
439
|
+
"""select c.owner, c.constraint_name, c.r_owner, c.r_constraint_name
|
|
440
|
+
from all_constraints c
|
|
407
441
|
where c.owner = :owner and c.table_name = :name and c.constraint_type = 'R'""",
|
|
408
|
-
owner=source, name=table,
|
|
442
|
+
key=(0, 1), owner=source, name=table,
|
|
409
443
|
):
|
|
444
|
+
parent = self.catalog.rows(
|
|
445
|
+
'select table_name from all_constraints where owner = :owner and constraint_name = :name',
|
|
446
|
+
key=(), owner=ref_owner, name=ref_constraint,
|
|
447
|
+
)
|
|
448
|
+
ref_table = parent[0][0] if parent else None
|
|
410
449
|
add_references(ExportObject(owner, name, 'REF_CONSTRAINT'), {
|
|
411
450
|
table_obj, ExportObject(ref_owner, ref_table or '<inaccessible referenced table>', 'TABLE'),
|
|
412
451
|
})
|
|
413
452
|
completed_tables += 1
|
|
414
453
|
dependencies = {ref for refs in references.values() for ref in refs}
|
|
415
454
|
# Identity backing sequences are part of CREATE TABLE, never separate exports.
|
|
416
|
-
identities = {ExportObject(source, row[0], 'SEQUENCE') for table in sorted(included_tables) for row in self.rows(
|
|
455
|
+
identities = {ExportObject(source, row[0], 'SEQUENCE') for table in sorted(included_tables) for row in self.catalog.rows(
|
|
417
456
|
'select sequence_name from all_tab_identity_cols where owner = :owner and table_name = :name',
|
|
418
457
|
owner=source, name=table,
|
|
419
458
|
)}
|
|
@@ -441,6 +480,7 @@ class TableExportService:
|
|
|
441
480
|
self.check_cancelled()
|
|
442
481
|
warnings = sorted(set(warnings))
|
|
443
482
|
header = [
|
|
483
|
+
'SET DEFINE OFF',
|
|
444
484
|
'-- Table DDL Export: definitions only; review before execution.',
|
|
445
485
|
f'-- Source: {quote_identifier(source)}; target: {quote_identifier(target)}',
|
|
446
486
|
f'-- {len(included_tables)} table(s), {len(sequence_objects)} sequence(s). Destination schema must already exist.',
|
|
@@ -452,6 +492,7 @@ class TableExportService:
|
|
|
452
492
|
' directly referencing package(s)/function(s)/procedure(s).',
|
|
453
493
|
f'-- {sum(obj.kind == "VIEW" for obj in table_users)} directly referencing view(s).',
|
|
454
494
|
'-- Definitions follow creation dependencies; cycles and external prerequisites are listed below.',
|
|
495
|
+
'-- Discovery prefers ALL_* catalogs, supplemented by accessible DBA_* views; invisible dependencies may be absent.',
|
|
455
496
|
'-- Tablespaces/storage omitted. Sequence starts prefer session CURRVAL + increment, else metadata.',
|
|
456
497
|
'-- CURRVAL is session-local; other sessions may have consumed different values.',
|
|
457
498
|
'-- Restart positions are export-time snapshots; cache gaps may occur. No source NEXTVAL was called.',
|