plsqlwks 0.2.0__tar.gz → 0.2.1__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.
Files changed (130) hide show
  1. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/PKG-INFO +67 -7
  2. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/README.md +66 -6
  3. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/doc/API.md +26 -0
  4. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/doc/ARCHITECTURE.md +10 -0
  5. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/doc/COMPATIBILITY.md +40 -9
  6. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/doc/PLUGINS.md +9 -0
  7. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/doc/PLUGIN_CATALOG.md +114 -0
  8. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/doc/QUICKSTART.html +125 -94
  9. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/doc/QUICKSTART.md +25 -0
  10. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/__init__.py +1 -1
  11. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/config/loader.py +5 -0
  12. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/config/models.py +5 -0
  13. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/config/settings.py +18 -0
  14. plsqlwks-0.2.1/plsqlwks/db/ddl_remap.py +132 -0
  15. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/db/execution.py +12 -4
  16. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/db/session.py +32 -0
  17. plsqlwks-0.2.1/plsqlwks/db/table_export.py +464 -0
  18. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/db/timestamps.py +39 -1
  19. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/plugins/api.py +4 -0
  20. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/app.py +37 -4
  21. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/db_operations.py +3 -1
  22. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/db_session.py +2 -1
  23. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/documents.py +6 -1
  24. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/plugin_host.py +9 -0
  25. plsqlwks-0.2.1/plsqlwks/ui/table_export.py +242 -0
  26. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks.egg-info/SOURCES.txt +7 -0
  27. plsqlwks-0.2.1/plugins/packages/table-ddl-export-0.1.1.plwgn +0 -0
  28. plsqlwks-0.2.1/plugins/table-ddl-export/install.plw +7 -0
  29. plsqlwks-0.2.1/plugins/table-ddl-export/payload/plugin.py +21 -0
  30. plsqlwks-0.2.1/plugins/xlsx-export/payload/__init__.py +0 -0
  31. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/tests/conftest.py +5 -0
  32. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/license.txt +0 -0
  33. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/__main__.py +0 -0
  34. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/cli.py +0 -0
  35. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/config/__init__.py +0 -0
  36. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/config/paths.py +0 -0
  37. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/config/session.py +0 -0
  38. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/db/__init__.py +0 -0
  39. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/db/dependencies.py +0 -0
  40. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/db/editing.py +0 -0
  41. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/db/explain.py +0 -0
  42. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/db/health.py +0 -0
  43. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/db/identifiers.py +0 -0
  44. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/db/metadata.py +0 -0
  45. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/db/models.py +0 -0
  46. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/db/sql_analysis.py +0 -0
  47. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/db/transactions.py +0 -0
  48. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/exporting.py +0 -0
  49. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/plugins/__init__.py +0 -0
  50. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/plugins/loader.py +0 -0
  51. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/plugins/management.py +0 -0
  52. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/sqlbinds.py +0 -0
  53. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/sqlsplit.py +0 -0
  54. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/__init__.py +0 -0
  55. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/application_controller.py +0 -0
  56. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/browser.py +0 -0
  57. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/buffer.py +0 -0
  58. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/catalog.py +0 -0
  59. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/clipboard.py +0 -0
  60. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/code_generation.py +0 -0
  61. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/command_dispatcher.py +0 -0
  62. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/commands.py +0 -0
  63. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/completion.py +0 -0
  64. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/constants.py +0 -0
  65. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/db_worker.py +0 -0
  66. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/dependency_walker.py +0 -0
  67. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/dialogs.py +0 -0
  68. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/display.py +0 -0
  69. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/editor_controller.py +0 -0
  70. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/errors.py +0 -0
  71. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/help.py +0 -0
  72. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/input_controller.py +0 -0
  73. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/key_reader.py +0 -0
  74. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/keys.py +0 -0
  75. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/menu.py +0 -0
  76. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/output_selection.py +0 -0
  77. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/ports.py +0 -0
  78. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/query_controller.py +0 -0
  79. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/renderer.py +0 -0
  80. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/result_controller.py +0 -0
  81. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/result_export.py +0 -0
  82. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/result_presenter.py +0 -0
  83. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/results.py +0 -0
  84. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/sql.py +0 -0
  85. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/sqlplus.py +0 -0
  86. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/state.py +0 -0
  87. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/syntax.py +0 -0
  88. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/ui/viewport.py +0 -0
  89. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plsqlwks/workspace.py +0 -0
  90. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/csv-export/install.plw +0 -0
  91. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/csv-export/payload/__init__.py +0 -0
  92. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/csv-export/payload/plugin.py +0 -0
  93. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/csv-export/payload/support.py +0 -0
  94. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/csv-export/payload/writer.py +0 -0
  95. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/csv2oratab/install.plw +0 -0
  96. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/csv2oratab/payload/__init__.py +0 -0
  97. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/csv2oratab/payload/csv2oratab.py +0 -0
  98. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/csv2oratab/payload/plugin.py +0 -0
  99. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/dependencies-walker/install.plw +0 -0
  100. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/dependencies-walker/payload/__init__.py +0 -0
  101. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/dependencies-walker/payload/plugin.py +0 -0
  102. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/html-export/install.plw +0 -0
  103. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/html-export/payload/__init__.py +0 -0
  104. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/html-export/payload/html_exporting.py +0 -0
  105. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/html-export/payload/plugin.py +0 -0
  106. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/html-export/payload/support.py +0 -0
  107. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/html-export/payload/writer.py +0 -0
  108. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/packages/csv-export-1.0.0.plwgn +0 -0
  109. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/packages/csv2oratab-0.1.0.plwgn +0 -0
  110. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/packages/dependencies-walker-0.1.0.plwgn +0 -0
  111. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/packages/html-export-1.0.0.plwgn +0 -0
  112. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/packages/sqlplus-0.1.0.plwgn +0 -0
  113. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/packages/xlsx-export-1.0.0.plwgn +0 -0
  114. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/sqlplus/install.plw +0 -0
  115. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/sqlplus/payload/__init__.py +0 -0
  116. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/sqlplus/payload/plugin.py +0 -0
  117. {plsqlwks-0.2.0/plugins/xlsx-export → plsqlwks-0.2.1/plugins/table-ddl-export}/payload/__init__.py +0 -0
  118. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/xlsx-export/install.plw +0 -0
  119. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/xlsx-export/payload/plugin.py +0 -0
  120. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/xlsx-export/payload/support.py +0 -0
  121. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/plugins/xlsx-export/payload/xlsx_exporting.py +0 -0
  122. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/pyproject.toml +0 -0
  123. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/pytest.ini +0 -0
  124. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/rchar.py +0 -0
  125. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/requirements.txt +0 -0
  126. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/setup.cfg +0 -0
  127. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/tests/fixtures/config_exports.txt +0 -0
  128. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/tests/fixtures/ui_exports.txt +0 -0
  129. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/tools/putty_keys.ps1 +0 -0
  130. {plsqlwks-0.2.0 → plsqlwks-0.2.1}/tools/windows_keys.cmd +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plsqlwks
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: An ncurses SQL and PL/SQL workspace for Oracle databases.
5
5
  Author: unu2000
6
6
  License-Expression: LicenseRef-plsqlwks-Donationware
@@ -98,6 +98,55 @@ protect it with `chmod 600`.
98
98
  `PLSQLWKS_ARRAYSIZE` sets the Oracle cursor array size. Both values must be
99
99
  positive integers.
100
100
 
101
+ ### Oracle Thin and Thick modes
102
+
103
+ Thin mode is the default and needs no Oracle Client installation. To use an
104
+ installed Oracle Client, start with `plsqlwks --thick`. Use `plsqlwks --thin` to
105
+ override a workspace's thick preference for one invocation. The flags are
106
+ mutually exclusive and are never saved to configuration.
107
+
108
+ For a persistent preference, edit the selected workspace's `config.ini` (or the
109
+ platform configuration file when using the default workspace):
110
+
111
+ ```ini
112
+ [database]
113
+ thick_mode = no
114
+ oracle_client_lib_dir =
115
+ oracle_client_config_dir =
116
+ ```
117
+
118
+ Set `thick_mode = yes` to enable Thick mode. Invalid boolean values are errors.
119
+ Both optional directories expand `~`; relative paths are resolved from the
120
+ configuration file's directory. Blank values use Oracle's normal discovery.
121
+ The directory settings are used only in Thick mode. All tabs and reconnects
122
+ share one driver mode; restart after changing mode or client settings.
123
+
124
+ Install an Oracle Instant Client **Basic** or **Basic Light** package compatible
125
+ with your Python architecture, python-oracledb version, and database. Libraries
126
+ are installed separately and are not bundled with PLSQLWKS. On Linux, normally
127
+ leave `oracle_client_lib_dir` blank and configure `ldconfig` or `LD_LIBRARY_PATH`
128
+ **before** launching Python. Setting that directory alone does not configure
129
+ Linux's dependent-library search path. On macOS, an explicit library directory
130
+ can be useful. When running through SSH or WSL, install the libraries where the
131
+ Python process runs. For a full Oracle Client installation, configure its
132
+ Oracle environment before launch.
133
+
134
+ `oracle_client_config_dir` selects the directory containing Oracle network
135
+ configuration such as `sqlnet.ora` and `tnsnames.ora`; when blank, Oracle uses
136
+ its normal lookup, including `TNS_ADMIN`. Native network encryption is configured
137
+ through Oracle Client's `sqlnet.ora` and the server's matching requirements.
138
+ The existing `ORACLE_USER`, `ORACLE_DSN`, and password-file authentication remain
139
+ in use. See the [Oracle Client initialization guide](https://python-oracledb.readthedocs.io/en/v3.4.2/user_guide/initialization.html)
140
+ for platform setup and the [compatibility contract](doc/COMPATIBILITY.md) for
141
+ validated combinations.
142
+
143
+ Client-loading failures such as `DPI-1047` stop startup before the terminal UI,
144
+ with no automatic fallback. Check library architecture, required system
145
+ libraries, and the pre-launch library search path. Mode conflicts or changed
146
+ initialization arguments require a process restart. Successful connection status
147
+ includes `Thin mode` or `Thick mode`. Help, version, and plugin management commands
148
+ do not initialize Oracle Client libraries.
149
+
101
150
  ## Install
102
151
 
103
152
  Python 3.10 or newer is required, along with a compatible terminal and a Python
@@ -850,12 +899,11 @@ period; DATE and TIMESTAMP input uses ISO
850
899
  Character and CLOB input is preserved as entered. Types that cannot be compared
851
900
  without losing information, including time-zone timestamps and timestamps with
852
901
  precision above six, are read-only in the grid.
853
- In python-oracledb Thin mode, non-null `TIMESTAMP WITH TIME ZONE` and
854
- `TIMESTAMP WITH LOCAL TIME ZONE` values are shown and exported as explicit
855
- lossless-fetch-unavailable markers instead of misleading naive datetimes. Use
856
- an explicit `TO_CHAR` expression with the required precision and zone fields
857
- when the exact value is needed; named-zone timestamps are not supported by the
858
- current Thin driver.
902
+ In both driver modes, ordinary SELECT/WITH queries format zoned timestamps on
903
+ Oracle to preserve their zone and fractional precision. Query forms that cannot
904
+ use this projection show explicit lossless-fetch-unavailable markers for
905
+ non-null zoned values on the native fetch path. Use an explicit `TO_CHAR`
906
+ expression with the required precision and zone fields for those query forms.
859
907
  Displayed CLOB and BLOB values are limited to the first 65,536 characters or
860
908
  bytes and include a truncation marker with the full size. Truncated LOB cells
861
909
  cannot be edited safely. Schema-browser DDL is always read in full.
@@ -1136,6 +1184,18 @@ lifecycle change requires a restart. See the
1136
1184
  [managed-package guide](https://gitlab.com/unununu/plsqlwks/-/blob/main/doc/PLUGINS.md#managed-plugin-packages)
1137
1185
  for the exact manifest, source layout, validation, replacement, and trust rules.
1138
1186
 
1187
+ ### Table DDL Export
1188
+
1189
+ Install `plugins/packages/table-ddl-export-0.1.1.plwgn` with
1190
+ `plsqlwks plugin install` and restart. **Alt-O -> Database -> Export table DDL**
1191
+ lets you choose a schema, filter table names as you type, select tables, and
1192
+ optionally remap them to another schema. It automatically includes related
1193
+ sequences and directly referencing packages, functions, procedures, and views, and follows
1194
+ required source-schema tables and views recursively. Definitions, constraints, indexes,
1195
+ foreign keys and triggers are ordered by creation dependencies in a new
1196
+ unsaved SQL tab for review. Generation activates that tab and focuses its editor.
1197
+ See the [selection keys and remapping details](doc/PLUGIN_CATALOG.md#table-ddl-export).
1198
+
1139
1199
  ### Dependencies walker
1140
1200
 
1141
1201
  Install the optional dependency browser and restart PLSQLWKS:
@@ -64,6 +64,55 @@ protect it with `chmod 600`.
64
64
  `PLSQLWKS_ARRAYSIZE` sets the Oracle cursor array size. Both values must be
65
65
  positive integers.
66
66
 
67
+ ### Oracle Thin and Thick modes
68
+
69
+ Thin mode is the default and needs no Oracle Client installation. To use an
70
+ installed Oracle Client, start with `plsqlwks --thick`. Use `plsqlwks --thin` to
71
+ override a workspace's thick preference for one invocation. The flags are
72
+ mutually exclusive and are never saved to configuration.
73
+
74
+ For a persistent preference, edit the selected workspace's `config.ini` (or the
75
+ platform configuration file when using the default workspace):
76
+
77
+ ```ini
78
+ [database]
79
+ thick_mode = no
80
+ oracle_client_lib_dir =
81
+ oracle_client_config_dir =
82
+ ```
83
+
84
+ Set `thick_mode = yes` to enable Thick mode. Invalid boolean values are errors.
85
+ Both optional directories expand `~`; relative paths are resolved from the
86
+ configuration file's directory. Blank values use Oracle's normal discovery.
87
+ The directory settings are used only in Thick mode. All tabs and reconnects
88
+ share one driver mode; restart after changing mode or client settings.
89
+
90
+ Install an Oracle Instant Client **Basic** or **Basic Light** package compatible
91
+ with your Python architecture, python-oracledb version, and database. Libraries
92
+ are installed separately and are not bundled with PLSQLWKS. On Linux, normally
93
+ leave `oracle_client_lib_dir` blank and configure `ldconfig` or `LD_LIBRARY_PATH`
94
+ **before** launching Python. Setting that directory alone does not configure
95
+ Linux's dependent-library search path. On macOS, an explicit library directory
96
+ can be useful. When running through SSH or WSL, install the libraries where the
97
+ Python process runs. For a full Oracle Client installation, configure its
98
+ Oracle environment before launch.
99
+
100
+ `oracle_client_config_dir` selects the directory containing Oracle network
101
+ configuration such as `sqlnet.ora` and `tnsnames.ora`; when blank, Oracle uses
102
+ its normal lookup, including `TNS_ADMIN`. Native network encryption is configured
103
+ through Oracle Client's `sqlnet.ora` and the server's matching requirements.
104
+ The existing `ORACLE_USER`, `ORACLE_DSN`, and password-file authentication remain
105
+ in use. See the [Oracle Client initialization guide](https://python-oracledb.readthedocs.io/en/v3.4.2/user_guide/initialization.html)
106
+ for platform setup and the [compatibility contract](doc/COMPATIBILITY.md) for
107
+ validated combinations.
108
+
109
+ Client-loading failures such as `DPI-1047` stop startup before the terminal UI,
110
+ with no automatic fallback. Check library architecture, required system
111
+ libraries, and the pre-launch library search path. Mode conflicts or changed
112
+ initialization arguments require a process restart. Successful connection status
113
+ includes `Thin mode` or `Thick mode`. Help, version, and plugin management commands
114
+ do not initialize Oracle Client libraries.
115
+
67
116
  ## Install
68
117
 
69
118
  Python 3.10 or newer is required, along with a compatible terminal and a Python
@@ -816,12 +865,11 @@ period; DATE and TIMESTAMP input uses ISO
816
865
  Character and CLOB input is preserved as entered. Types that cannot be compared
817
866
  without losing information, including time-zone timestamps and timestamps with
818
867
  precision above six, are read-only in the grid.
819
- In python-oracledb Thin mode, non-null `TIMESTAMP WITH TIME ZONE` and
820
- `TIMESTAMP WITH LOCAL TIME ZONE` values are shown and exported as explicit
821
- lossless-fetch-unavailable markers instead of misleading naive datetimes. Use
822
- an explicit `TO_CHAR` expression with the required precision and zone fields
823
- when the exact value is needed; named-zone timestamps are not supported by the
824
- current Thin driver.
868
+ In both driver modes, ordinary SELECT/WITH queries format zoned timestamps on
869
+ Oracle to preserve their zone and fractional precision. Query forms that cannot
870
+ use this projection show explicit lossless-fetch-unavailable markers for
871
+ non-null zoned values on the native fetch path. Use an explicit `TO_CHAR`
872
+ expression with the required precision and zone fields for those query forms.
825
873
  Displayed CLOB and BLOB values are limited to the first 65,536 characters or
826
874
  bytes and include a truncation marker with the full size. Truncated LOB cells
827
875
  cannot be edited safely. Schema-browser DDL is always read in full.
@@ -1102,6 +1150,18 @@ lifecycle change requires a restart. See the
1102
1150
  [managed-package guide](https://gitlab.com/unununu/plsqlwks/-/blob/main/doc/PLUGINS.md#managed-plugin-packages)
1103
1151
  for the exact manifest, source layout, validation, replacement, and trust rules.
1104
1152
 
1153
+ ### Table DDL Export
1154
+
1155
+ Install `plugins/packages/table-ddl-export-0.1.1.plwgn` with
1156
+ `plsqlwks plugin install` and restart. **Alt-O -> Database -> Export table DDL**
1157
+ lets you choose a schema, filter table names as you type, select tables, and
1158
+ optionally remap them to another schema. It automatically includes related
1159
+ sequences and directly referencing packages, functions, procedures, and views, and follows
1160
+ required source-schema tables and views recursively. Definitions, constraints, indexes,
1161
+ foreign keys and triggers are ordered by creation dependencies in a new
1162
+ unsaved SQL tab for review. Generation activates that tab and focuses its editor.
1163
+ See the [selection keys and remapping details](doc/PLUGIN_CATALOG.md#table-ddl-export).
1164
+
1105
1165
  ### Dependencies walker
1106
1166
 
1107
1167
  Install the optional dependency browser and restart PLSQLWKS:
@@ -190,6 +190,7 @@ class PluginContext(Protocol):
190
190
  def start_result_export(self, request: ResultExportRequest) -> None: ...
191
191
  def start_code_generation(self, request: CodeGenerationRequest) -> None: ...
192
192
  def start_dependency_walk(self) -> None: ...
193
+ def start_table_ddl_export(self) -> None: ...
193
194
  def start_sqlplus(self, executable: str = "sqlplus") -> None: ...
194
195
  ```
195
196
 
@@ -532,6 +533,31 @@ def generate_select(context: PluginContext) -> None:
532
533
  ordinary exceptions are also reported through the plugin error UI. The exact
533
534
  wording of either presentation is not part of the API.
534
535
 
536
+ ## Table DDL export
537
+
538
+ `PluginContext.start_table_ddl_export()` is an additive API-v1 capability.
539
+ It starts a host-owned workflow to choose a source schema, filter and select
540
+ tables, and choose a target schema. Sequences and source-schema packages,
541
+ functions, procedures, and views that directly reference the tables are included
542
+ automatically, without a separate sequence picker. It returns immediately while the host
543
+ reads metadata through the initiating tab's database worker. No connection,
544
+ credentials, cursor, or arbitrary SQL capability crosses the plugin boundary.
545
+
546
+ Required source-schema tables and views are followed recursively; tables include
547
+ their constraints, indexes, triggers, and detected sequences. Selection of callers stays
548
+ limited to direct references to the initially checked tables. Definitions are
549
+ ordered by creation dependencies across object types; unresolved prerequisites
550
+ and genuine dependency cycles are reported in the generated script.
551
+
552
+ On success the host opens and activates a new unsaved tab containing the generated
553
+ SQL, with keyboard focus in the editor. Cancellation,
554
+ metadata failure, session replacement, or a stale editor context prevents that
555
+ tab from opening. Metadata calls neither execute generated SQL nor commit,
556
+ roll back, or drain DBMS_OUTPUT. Transform settings belong to individual
557
+ DBMS_METADATA handles, not to the session. See the
558
+ [catalog workflow](PLUGIN_CATALOG.md#table-ddl-export) for selection keys,
559
+ remapping behavior, prerequisites, and metadata privilege requirements.
560
+
535
561
  ## Dependency walking
536
562
 
537
563
  `PluginContext.start_dependency_walk()` is an additive API v1 capability. The
@@ -112,6 +112,16 @@ metadata reads, optional safe numeric primary-key start derivation,
112
112
  cancellation, stale-editor checks, and fresh unsaved-tab creation, while the
113
113
  plugin receives only frozen column and primary-key descriptions.
114
114
 
115
+ The Table DDL Export command delegates through `start_table_ddl_export()`.
116
+ Its host controller owns the table checklist with incremental substring filtering
117
+ and cancellable worker jobs. Its database service discovers related sequences
118
+ and directly referencing source-schema program units using bound dictionary
119
+ reads, orders included routines by dependency, and extracts definitions using
120
+ per-handle DBMS_METADATA transforms. Generation creates a fresh unsaved tab only for the originating
121
+ editor/session. Identifier-aware remapping preserves literals and comments and
122
+ reports ambiguous references. The plugin itself never receives database or UI
123
+ internals and generated SQL is never automatically executed.
124
+
115
125
  Plugin API version 1 does not expose the database worker, `OracleWorkspace`,
116
126
  mutable results or `UIState`, curses objects, global shortcut registration,
117
127
  lifecycle events, arbitrary background jobs, declarative settings schemas, hot
@@ -52,8 +52,8 @@ database failover configurations are not release-gating combinations.
52
52
 
53
53
  Oracle `DATE` has no time-zone component. Plain `DATE` and `TIMESTAMP(6)` values
54
54
  are materialized as NLS-independent Python datetimes and ISO display strings.
55
- The current pinned python-oracledb Thin driver does not preserve the offset or
56
- zone of `TIMESTAMP WITH TIME ZONE` and `TIMESTAMP WITH LOCAL TIME ZONE` values,
55
+ The native timestamp fetch path does not provide the lossless representation
56
+ PLSQLWKS requires for `TIMESTAMP WITH TIME ZONE` and `TIMESTAMP WITH LOCAL TIME ZONE` values,
57
57
  and it truncates precision beyond Python microseconds. Returning the resulting
58
58
  naive datetime would falsely imply a lossless value.
59
59
 
@@ -73,6 +73,13 @@ Original headings, bind values, ordering, row limits, and timestamp metadata
73
73
  are preserved. Zoned cells remain read-only; neighboring editable columns are
74
74
  unaffected. Plain `DATE` and `TIMESTAMP` behavior is unchanged.
75
75
 
76
+ For duplicate headings, simple trailing `OFFSET` and `FETCH FIRST/NEXT ... ONLY`
77
+ limits are applied after positional column aliases and the original native-value
78
+ ordering. Counts can be numeric literals or simple named binds; an omitted
79
+ `FETCH` count is also supported. `WITH TIES`, `PERCENT`, and count expressions
80
+ retain their original placement and use the fallback below if Oracle rejects
81
+ the projection.
82
+
76
83
  The projection is parsed before executing the user query, which executes once.
77
84
  Special forms such as `SELECT FOR UPDATE`, inline `WITH FUNCTION/PROCEDURE`, and
78
85
  results containing LONG, REF CURSOR, or object columns use the existing native
@@ -81,8 +88,8 @@ or rejects the projection's syntax or types, the original query runs instead.
81
88
  Non-null zoned cells on this fallback path retain a warning
82
89
  and these fail-safe display/export values:
83
90
 
84
- - `<TIMESTAMP WITH TIME ZONE: lossless Thin-mode fetch unavailable; use TO_CHAR>`
85
- - `<TIMESTAMP WITH LOCAL TIME ZONE: lossless Thin-mode fetch unavailable; use TO_CHAR>`
91
+ - `<TIMESTAMP WITH TIME ZONE: lossless native fetch unavailable; use TO_CHAR>`
92
+ - `<TIMESTAMP WITH LOCAL TIME ZONE: lossless native fetch unavailable; use TO_CHAR>`
86
93
 
87
94
  Named-zone values on that native fallback path can still raise Thin-mode
88
95
  `DPY-3022`. Select a lossless companion string explicitly for these query forms:
@@ -96,17 +103,41 @@ For a local-time-zone column, first cast it at the required precision to
96
103
 
97
104
  ### Experimental connection matrices
98
105
 
99
- No executable experimental connection job or runtime switch is part of the
100
- current release gate. The following names reserve separate future contracts so
101
- their results cannot be mistaken for coverage of the mandatory Thin matrix:
106
+ PLSQLWKS supports an optional startup Thick-mode switch (`--thick` or
107
+ `[database] thick_mode = yes`); Thin mode remains the default. The experimental
108
+ Thick matrix is a separate opt-in local test profile, outside the mandatory
109
+ release gates. Wallet/TCPS and TNS-alias matrices remain reserved. Experimental
110
+ results do not broaden the mandatory Thin compatibility claim:
102
111
 
103
- | Reserved matrix | Required isolated infrastructure |
112
+ | Experimental matrix | Required isolated infrastructure |
104
113
  | --- | --- |
105
114
  | `oracle-experimental-thick` | A separate process and protected runner image with reviewed Oracle Instant Client libraries |
106
115
  | `oracle-experimental-wallet-tcps` | A dedicated TCPS endpoint and disposable protected wallet/configuration files |
107
116
  | `oracle-experimental-tns-alias` | A disposable `tnsnames.ora`/`TNS_ADMIN` configuration and a dedicated alias |
108
117
 
109
- Each future experiment must retain the identity, version, endpoint-fingerprint,
118
+ To run the Thick experiment, provision the complete isolated matrix described
119
+ below for the selected target and install compatible Oracle Client libraries.
120
+ Optional client directories come from the selected workspace configuration;
121
+ Linux library discovery must be configured before launch. Run each target in a
122
+ separate process, with its matching matrix environment:
123
+
124
+ ```bash
125
+ PLSQLWKS_TEST_ORACLE_TARGET=19c python3 tools/dev.py test oracle-experimental-thick
126
+ PLSQLWKS_TEST_ORACLE_TARGET=26ai python3 tools/dev.py test oracle-experimental-thick
127
+ ```
128
+
129
+ This profile explicitly enables `PLSQLWKS_TEST_ORACLE_THICK=1` together with the
130
+ base Oracle and matrix opt-ins. Direct pytest use of the Thick selector without
131
+ both opt-ins is rejected. Other development profiles, including `all`, clear
132
+ this selector and retain Thin-mode validation. Every matrix and live-suite
133
+ connection, including fresh-workspace tests, receives the selected mode. The
134
+ preflight verifies the actual mode before accessing endpoints, and suite
135
+ metadata includes the Oracle Client version for Thick runs. Missing client
136
+ libraries or incomplete infrastructure fail the experiment rather than skip it.
137
+ No protected CI job is added in this release; any future job must use isolated
138
+ reviewed client infrastructure and remain separate from the Thin release gates.
139
+
140
+ The Thick experiment and each future experiment must retain the identity, version, endpoint-fingerprint,
110
141
  privilege, guard-token, and database-lock checks used by the base matrix. It
111
142
  starts as a separate non-gating job with separate secrets and no artifacts or
112
143
  caches. It can be added to the compatibility claim only after becoming
@@ -168,6 +168,15 @@ SQL*Plus exits before restoring PLSQLWKS. SQL*Plus has its own session and
168
168
  transaction settings, including when launched from a read-only host. Install
169
169
  and configuration instructions are in the [catalog](PLUGIN_CATALOG.md#sqlplus-launcher).
170
170
 
171
+ ## Table DDL Export package
172
+
173
+ `table-ddl-export-0.1.1.plwgn` adds **Database -> Export table DDL** through
174
+ `PluginContext.start_table_ddl_export()`. The host supplies schema/table selection
175
+ with filtering as you type, automatic dependent-object and directly referencing
176
+ program-unit/view extraction, schema remapping, progress, and a new unsaved SQL tab.
177
+ No extra dependencies are required. See the
178
+ [catalog guide](PLUGIN_CATALOG.md#table-ddl-export) for installation and details.
179
+
171
180
  ## Dependencies walker package
172
181
 
173
182
  `dependencies-walker-0.1.0.plwgn` adds **Database -> Dependencies walker** through
@@ -14,6 +14,7 @@ the [Plugin API v1 reference](API.md) for the normative contract.
14
14
  | csv2oratab importer | `plugins/packages/csv2oratab-0.1.0.plwgn` | `plsqlwks[csv2oratab]` |
15
15
  | Dependencies walker | `plugins/packages/dependencies-walker-0.1.0.plwgn` | Host with dependency-walker support |
16
16
  | SQL*Plus launcher | `plugins/packages/sqlplus-0.1.0.plwgn` | SQL*Plus client on the POSIX host |
17
+ | Table DDL Export | `plugins/packages/table-ddl-export-0.1.1.plwgn` | Updated host with table DDL export support |
17
18
 
18
19
  Install the commands you want from a checkout or unpacked source distribution:
19
20
 
@@ -52,6 +53,119 @@ archives are deterministic copies of the adjacent source trees; tests require
52
53
  byte-for-byte equality. The source distribution includes this catalog, while
53
54
  the application wheel does not.
54
55
 
56
+ ## Table DDL Export
57
+
58
+ Install the package and restart PLSQLWKS:
59
+
60
+ ```bash
61
+ plsqlwks plugin install plugins/packages/table-ddl-export-0.1.1.plwgn
62
+ ```
63
+
64
+ Choose **Alt-O -> Database -> Export table DDL**. Enter a source schema
65
+ (the current schema is suggested), filter and select tables, and enter a target
66
+ schema. Keeping the source name disables remapping. Use
67
+ double quotes for exact mixed-case or unusual schema names.
68
+
69
+ Type in the table list to filter names immediately by a case-insensitive literal
70
+ substring. **Backspace** edits the filter, **Ctrl+L** clears it, and **/** opens
71
+ an optional filter prompt for text containing spaces. An empty filter shows all
72
+ tables. Use arrows/Page Up/Page Down/Home/End to navigate, **Space** to toggle
73
+ an entry, **Ctrl+A** to select matching tables, and **Ctrl+U** to deselect them.
74
+ Checked tables stay selected when hidden by a filter; the screen shows both
75
+ total and visible selection counts. **Enter** exports the checked tables,
76
+ including hidden selections. **Esc** or **Ctrl+C** cancels, including during
77
+ metadata reads. At least one table must be checked.
78
+
79
+ There is no sequence-selection dialog. Source-schema sequences referenced by
80
+ defaults and Oracle-recorded table/trigger/program-unit dependencies are included
81
+ automatically. Trigger bodies are also scanned for explicit NEXTVAL/CURRVAL
82
+ references to accessible sequences, including invalid or disabled triggers whose
83
+ dictionary dependencies may be incomplete. Comments, strings, and remote
84
+ references are ignored; names are not inferred from table names. Identity backing
85
+ sequences are excluded: identity definitions remain in CREATE TABLE. Sequences
86
+ shared by several tables are emitted once.
87
+
88
+ For ordinary sequences, START WITH uses the exporting session's CURRVAL plus
89
+ INCREMENT BY when CURRVAL is defined, taking priority over the metadata cache
90
+ boundary. A cycling sequence wraps at its configured bounds; an exhausted
91
+ noncycling sequence stops the export with an error. If CURRVAL is undefined in
92
+ that session (ORA-08002), the original DBMS_METADATA START WITH is preserved.
93
+ Scalable/sharded sequences retain their metadata restart position with a review
94
+ comment because raw CURRVAL includes offsets. Other sequence options remain intact.
95
+
96
+ Each definition states which restart source was used. CURRVAL describes only
97
+ the export session: other sessions may have consumed different values. Metadata
98
+ snapshots may skip unused cached numbers, and later source activity is not
99
+ reflected in the script. Export never calls NEXTVAL, changes sequence settings,
100
+ recompiles source triggers, or scans table data to calculate a start value.
101
+
102
+ Source-schema packages, standalone functions, procedures, and views that directly
103
+ reference any initially checked table are also included. A package match includes its
104
+ specification and its body when present, even if only the body references the
105
+ table. Shared objects are emitted once; indirect callers, views built only on
106
+ other views, and routines accessing tables only through views are not selected. Detection uses Oracle's
107
+ recorded dependencies, so dynamic SQL references cannot be discovered reliably.
108
+
109
+ Required source-schema tables and views are included automatically, following dependencies
110
+ recursively through table definitions, foreign keys, triggers, indexes, and the
111
+ included routines and views. For example, exporting `HARDWARE` also exports `HARDWARE_HIST`
112
+ when a hardware trigger references that history table, and exporting `ECONOMIC_CALENDAR`
113
+ includes the prerequisite view `LDR_ECOCAL_FF`. Each added table includes
114
+ its constraints, indexes, triggers, and detected sequences; shared tables are
115
+ emitted once. The script header lists automatically added tables and views. This expansion
116
+ does not select additional callers of those tables or recursively include other
117
+ callers of the added views. Tables excluded from the table picker and objects in other schemas
118
+ remain prerequisites.
119
+
120
+ After generation, the new unsaved tab is named `YYYYMMDD_<table_name>.sql`
121
+ using the local export date, for example `20261001_HARDWARE.sql`. Multiple
122
+ tables use the alphabetically first checked name plus the checked table count
123
+ padded to three digits, for example `20261001_HARDWARE_010.sql` for ten tables.
124
+ Characters unsuitable for filenames are replaced with underscores. The tab becomes active with keyboard
125
+ focus in its editor, and Save suggests the generated filename.
126
+ Definitions are ordered by creation dependencies across all exported object types.
127
+ Independent objects prefer sequences, tables with non-FK constraints, package
128
+ specifications, functions, procedures, package bodies, views, indexes, foreign keys, then
129
+ triggers, with stable name ordering within each group. A prerequisite overrides
130
+ that grouping: an included function used by a virtual column precedes its table,
131
+ and a trigger named by `FOLLOWS` or `PRECEDES` precedes the trigger naming it.
132
+ Static function calls in virtual-column and index expressions supplement Oracle's
133
+ recorded dependencies. Foreign keys follow both participating tables and keys;
134
+ mutual foreign keys do not create a table-creation cycle. Genuine dependency
135
+ cycles identify only their participating objects in a warning; creation order
136
+ alone cannot resolve them, and no automatic recovery/recompilation is generated.
137
+ Primary/unique key indexes are not duplicated. Constraint and trigger states,
138
+ identity/virtual columns, defaults, and partitioning are preserved. Tablespace
139
+ and segment-storage clauses are omitted. Ordinary user tables are listed;
140
+ recycle-bin entries, materialized-view storage and internal storage tables are excluded.
141
+
142
+ Remapping changes source-schema ownership and identifiable static references,
143
+ including references to automatically included tables. Required source tables
144
+ that cannot be included must already exist in the **target** schema. References
145
+ to other schemas remain unchanged. Strings and comments are preserved; dynamic
146
+ SQL, ambiguous qualifiers, and source qualifiers in strings receive review
147
+ notes. Dependencies outside the export appear as prerequisites in the script
148
+ header; Oracle metadata cannot discover every dynamic or indirect dependency.
149
+
150
+ The source account must be able to retrieve each requested object's metadata.
151
+ Normally this means owning the objects; cross-schema extraction requires
152
+ appropriate DBMS_METADATA catalog privileges, such as SELECT_CATALOG_ROLE.
153
+ Having SELECT on another schema's table alone is insufficient. Metadata errors
154
+ abort generation instead of presenting an incomplete export as successful.
155
+
156
+ Review and save the script normally. Export does not execute SQL, create the
157
+ destination schema, copy rows, grant privileges, commit, roll back, or drain
158
+ DBMS_OUTPUT. The destination schema must already exist when the script is run.
159
+ Grants, synonyms, other routines, types and other dependent
160
+ schemas are not exported recursively. Missing prerequisite objects and sequences
161
+ used only through dynamic SQL may require manual additions. Existing editor content/results remain
162
+ intact. Both Thin and Thick connections are supported.
163
+
164
+ When upgrading an existing package, add `--replace` to the install command.
165
+ Update the host application and restart as well: the selection and extraction
166
+ workflow is implemented by the host, so replacing only the plugin archive does
167
+ not update an older host's behavior.
168
+
55
169
  ## SQL*Plus launcher
56
170
 
57
171
  Install the optional package, then restart PLSQLWKS: