plsqlwks 0.2.0__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.
Files changed (132) hide show
  1. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/PKG-INFO +72 -8
  2. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/README.md +71 -7
  3. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/doc/API.md +30 -0
  4. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/doc/ARCHITECTURE.md +38 -0
  5. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/doc/COMPATIBILITY.md +40 -9
  6. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/doc/PLUGINS.md +9 -0
  7. plsqlwks-0.2.2/doc/PLUGIN_CATALOG.md +353 -0
  8. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/doc/QUICKSTART.html +125 -94
  9. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/doc/QUICKSTART.md +28 -2
  10. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/__init__.py +1 -1
  11. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/config/loader.py +5 -0
  12. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/config/models.py +5 -0
  13. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/config/settings.py +18 -0
  14. plsqlwks-0.2.2/plsqlwks/db/ddl_remap.py +132 -0
  15. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/db/execution.py +12 -4
  16. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/db/session.py +32 -0
  17. plsqlwks-0.2.2/plsqlwks/db/table_export.py +505 -0
  18. plsqlwks-0.2.2/plsqlwks/db/table_export_catalog.py +488 -0
  19. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/db/timestamps.py +39 -1
  20. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/plugins/api.py +4 -0
  21. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/sqlsplit.py +10 -0
  22. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/app.py +43 -5
  23. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/buffer.py +47 -1
  24. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/clipboard.py +22 -5
  25. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/db_operations.py +3 -1
  26. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/db_session.py +2 -1
  27. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/dialogs.py +17 -0
  28. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/documents.py +6 -1
  29. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/editor_controller.py +1 -0
  30. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/plugin_host.py +9 -0
  31. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/ports.py +2 -0
  32. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/query_controller.py +3 -0
  33. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/renderer.py +102 -16
  34. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/syntax.py +140 -0
  35. plsqlwks-0.2.2/plsqlwks/ui/table_export.py +248 -0
  36. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks.egg-info/SOURCES.txt +8 -0
  37. plsqlwks-0.2.2/plugins/packages/table-ddl-export-0.1.1.plwgn +0 -0
  38. plsqlwks-0.2.2/plugins/table-ddl-export/install.plw +7 -0
  39. plsqlwks-0.2.2/plugins/table-ddl-export/payload/plugin.py +21 -0
  40. plsqlwks-0.2.2/plugins/xlsx-export/payload/__init__.py +0 -0
  41. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/tests/conftest.py +5 -0
  42. plsqlwks-0.2.0/doc/PLUGIN_CATALOG.md +0 -193
  43. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/license.txt +0 -0
  44. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/__main__.py +0 -0
  45. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/cli.py +0 -0
  46. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/config/__init__.py +0 -0
  47. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/config/paths.py +0 -0
  48. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/config/session.py +0 -0
  49. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/db/__init__.py +0 -0
  50. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/db/dependencies.py +0 -0
  51. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/db/editing.py +0 -0
  52. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/db/explain.py +0 -0
  53. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/db/health.py +0 -0
  54. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/db/identifiers.py +0 -0
  55. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/db/metadata.py +0 -0
  56. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/db/models.py +0 -0
  57. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/db/sql_analysis.py +0 -0
  58. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/db/transactions.py +0 -0
  59. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/exporting.py +0 -0
  60. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/plugins/__init__.py +0 -0
  61. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/plugins/loader.py +0 -0
  62. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/plugins/management.py +0 -0
  63. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/sqlbinds.py +0 -0
  64. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/__init__.py +0 -0
  65. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/application_controller.py +0 -0
  66. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/browser.py +0 -0
  67. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/catalog.py +0 -0
  68. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/code_generation.py +0 -0
  69. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/command_dispatcher.py +0 -0
  70. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/commands.py +0 -0
  71. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/completion.py +0 -0
  72. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/constants.py +0 -0
  73. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/db_worker.py +0 -0
  74. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/dependency_walker.py +0 -0
  75. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/display.py +0 -0
  76. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/errors.py +0 -0
  77. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/help.py +0 -0
  78. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/input_controller.py +0 -0
  79. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/key_reader.py +0 -0
  80. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/keys.py +0 -0
  81. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/menu.py +0 -0
  82. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/output_selection.py +0 -0
  83. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/result_controller.py +0 -0
  84. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/result_export.py +0 -0
  85. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/result_presenter.py +0 -0
  86. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/results.py +0 -0
  87. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/sql.py +0 -0
  88. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/sqlplus.py +0 -0
  89. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/state.py +0 -0
  90. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/ui/viewport.py +0 -0
  91. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plsqlwks/workspace.py +0 -0
  92. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/csv-export/install.plw +0 -0
  93. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/csv-export/payload/__init__.py +0 -0
  94. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/csv-export/payload/plugin.py +0 -0
  95. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/csv-export/payload/support.py +0 -0
  96. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/csv-export/payload/writer.py +0 -0
  97. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/csv2oratab/install.plw +0 -0
  98. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/csv2oratab/payload/__init__.py +0 -0
  99. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/csv2oratab/payload/csv2oratab.py +0 -0
  100. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/csv2oratab/payload/plugin.py +0 -0
  101. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/dependencies-walker/install.plw +0 -0
  102. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/dependencies-walker/payload/__init__.py +0 -0
  103. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/dependencies-walker/payload/plugin.py +0 -0
  104. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/html-export/install.plw +0 -0
  105. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/html-export/payload/__init__.py +0 -0
  106. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/html-export/payload/html_exporting.py +0 -0
  107. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/html-export/payload/plugin.py +0 -0
  108. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/html-export/payload/support.py +0 -0
  109. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/html-export/payload/writer.py +0 -0
  110. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/packages/csv-export-1.0.0.plwgn +0 -0
  111. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/packages/csv2oratab-0.1.0.plwgn +0 -0
  112. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/packages/dependencies-walker-0.1.0.plwgn +0 -0
  113. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/packages/html-export-1.0.0.plwgn +0 -0
  114. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/packages/sqlplus-0.1.0.plwgn +0 -0
  115. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/packages/xlsx-export-1.0.0.plwgn +0 -0
  116. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/sqlplus/install.plw +0 -0
  117. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/sqlplus/payload/__init__.py +0 -0
  118. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/sqlplus/payload/plugin.py +0 -0
  119. {plsqlwks-0.2.0/plugins/xlsx-export → plsqlwks-0.2.2/plugins/table-ddl-export}/payload/__init__.py +0 -0
  120. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/xlsx-export/install.plw +0 -0
  121. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/xlsx-export/payload/plugin.py +0 -0
  122. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/xlsx-export/payload/support.py +0 -0
  123. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/plugins/xlsx-export/payload/xlsx_exporting.py +0 -0
  124. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/pyproject.toml +0 -0
  125. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/pytest.ini +0 -0
  126. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/rchar.py +0 -0
  127. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/requirements.txt +0 -0
  128. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/setup.cfg +0 -0
  129. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/tests/fixtures/config_exports.txt +0 -0
  130. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/tests/fixtures/ui_exports.txt +0 -0
  131. {plsqlwks-0.2.0 → plsqlwks-0.2.2}/tools/putty_keys.ps1 +0 -0
  132. {plsqlwks-0.2.0 → 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.0
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
@@ -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
@@ -700,12 +749,16 @@ also works from Command Prompt and continues to support PuTTY.
700
749
  | `Ctrl+=` | Reconnect |
701
750
 
702
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.
703
755
  Script execution reports statement progress as `n/total` and stops at the first
704
756
  failed statement while preserving earlier results. Scripts are sent directly to
705
757
  Oracle, not through SQL*Plus or SQLcl: client commands such as `PROMPT`, `SPOOL`,
706
758
  and `SET SERVEROUTPUT`, and `&`/`&&` substitution variables, are rejected before
707
759
  bind prompts or execution. Oracle SQL statements such as `SET TRANSACTION`
708
- 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.
709
762
  Execution and explain errors report mapped editor line and column diagnostics.
710
763
  The cursor moves only when the buffer still matches the source that was sent to
711
764
  Oracle; if it changed while the operation ran, the result warns about the stale
@@ -850,12 +903,11 @@ period; DATE and TIMESTAMP input uses ISO
850
903
  Character and CLOB input is preserved as entered. Types that cannot be compared
851
904
  without losing information, including time-zone timestamps and timestamps with
852
905
  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.
906
+ In both driver modes, ordinary SELECT/WITH queries format zoned timestamps on
907
+ Oracle to preserve their zone and fractional precision. Query forms that cannot
908
+ use this projection show explicit lossless-fetch-unavailable markers for
909
+ non-null zoned values on the native fetch path. Use an explicit `TO_CHAR`
910
+ expression with the required precision and zone fields for those query forms.
859
911
  Displayed CLOB and BLOB values are limited to the first 65,536 characters or
860
912
  bytes and include a truncation marker with the full size. Truncated LOB cells
861
913
  cannot be edited safely. Schema-browser DDL is always read in full.
@@ -1136,6 +1188,18 @@ lifecycle change requires a restart. See the
1136
1188
  [managed-package guide](https://gitlab.com/unununu/plsqlwks/-/blob/main/doc/PLUGINS.md#managed-plugin-packages)
1137
1189
  for the exact manifest, source layout, validation, replacement, and trust rules.
1138
1190
 
1191
+ ### Table DDL Export
1192
+
1193
+ Install `plugins/packages/table-ddl-export-0.1.1.plwgn` with
1194
+ `plsqlwks plugin install` and restart. **Alt-O -> Database -> Export table DDL**
1195
+ lets you choose a schema, filter table names as you type, select tables, and
1196
+ optionally remap them to another schema. It automatically includes related
1197
+ sequences and directly referencing packages, functions, procedures, and views, and follows
1198
+ required source-schema tables and views recursively. Definitions, constraints, indexes,
1199
+ foreign keys and triggers are ordered by creation dependencies in a new
1200
+ unsaved SQL tab for review. Generation activates that tab and focuses its editor.
1201
+ See the [selection keys and remapping details](doc/PLUGIN_CATALOG.md#table-ddl-export).
1202
+
1139
1203
  ### Dependencies walker
1140
1204
 
1141
1205
  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
@@ -666,12 +715,16 @@ also works from Command Prompt and continues to support PuTTY.
666
715
  | `Ctrl+=` | Reconnect |
667
716
 
668
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.
669
721
  Script execution reports statement progress as `n/total` and stops at the first
670
722
  failed statement while preserving earlier results. Scripts are sent directly to
671
723
  Oracle, not through SQL*Plus or SQLcl: client commands such as `PROMPT`, `SPOOL`,
672
724
  and `SET SERVEROUTPUT`, and `&`/`&&` substitution variables, are rejected before
673
725
  bind prompts or execution. Oracle SQL statements such as `SET TRANSACTION`
674
- 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.
675
728
  Execution and explain errors report mapped editor line and column diagnostics.
676
729
  The cursor moves only when the buffer still matches the source that was sent to
677
730
  Oracle; if it changed while the operation ran, the result warns about the stale
@@ -816,12 +869,11 @@ period; DATE and TIMESTAMP input uses ISO
816
869
  Character and CLOB input is preserved as entered. Types that cannot be compared
817
870
  without losing information, including time-zone timestamps and timestamps with
818
871
  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.
872
+ In both driver modes, ordinary SELECT/WITH queries format zoned timestamps on
873
+ Oracle to preserve their zone and fractional precision. Query forms that cannot
874
+ use this projection show explicit lossless-fetch-unavailable markers for
875
+ non-null zoned values on the native fetch path. Use an explicit `TO_CHAR`
876
+ expression with the required precision and zone fields for those query forms.
825
877
  Displayed CLOB and BLOB values are limited to the first 65,536 characters or
826
878
  bytes and include a truncation marker with the full size. Truncated LOB cells
827
879
  cannot be edited safely. Schema-browser DDL is always read in full.
@@ -1102,6 +1154,18 @@ lifecycle change requires a restart. See the
1102
1154
  [managed-package guide](https://gitlab.com/unununu/plsqlwks/-/blob/main/doc/PLUGINS.md#managed-plugin-packages)
1103
1155
  for the exact manifest, source layout, validation, replacement, and trust rules.
1104
1156
 
1157
+ ### Table DDL Export
1158
+
1159
+ Install `plugins/packages/table-ddl-export-0.1.1.plwgn` with
1160
+ `plsqlwks plugin install` and restart. **Alt-O -> Database -> Export table DDL**
1161
+ lets you choose a schema, filter table names as you type, select tables, and
1162
+ optionally remap them to another schema. It automatically includes related
1163
+ sequences and directly referencing packages, functions, procedures, and views, and follows
1164
+ required source-schema tables and views recursively. Definitions, constraints, indexes,
1165
+ foreign keys and triggers are ordered by creation dependencies in a new
1166
+ unsaved SQL tab for review. Generation activates that tab and focuses its editor.
1167
+ See the [selection keys and remapping details](doc/PLUGIN_CATALOG.md#table-ddl-export).
1168
+
1105
1169
  ### Dependencies walker
1106
1170
 
1107
1171
  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,35 @@ 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. 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.
555
+
556
+ On success the host opens and activates a new unsaved tab containing the generated
557
+ SQL, with keyboard focus in the editor. Cancellation,
558
+ metadata failure, session replacement, or a stale editor context prevents that
559
+ tab from opening. Metadata calls neither execute generated SQL nor commit,
560
+ roll back, or drain DBMS_OUTPUT. Transform settings belong to individual
561
+ DBMS_METADATA handles, not to the session. See the
562
+ [catalog workflow](PLUGIN_CATALOG.md#table-ddl-export) for selection keys,
563
+ remapping behavior, prerequisites, and metadata privilege requirements.
564
+
535
565
  ## Dependency walking
536
566
 
537
567
  `PluginContext.start_dependency_walk()` is an additive API v1 capability. The
@@ -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
@@ -112,6 +138,18 @@ metadata reads, optional safe numeric primary-key start derivation,
112
138
  cancellation, stale-editor checks, and fresh unsaved-tab creation, while the
113
139
  plugin receives only frozen column and primary-key descriptions.
114
140
 
141
+ The Table DDL Export command delegates through `start_table_ddl_export()`.
142
+ Its host controller owns the table checklist with incremental substring filtering
143
+ and cancellable worker jobs. Its database service discovers related sequences
144
+ and directly referencing source-schema program units using bound dictionary
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
149
+ editor/session. Identifier-aware remapping preserves literals and comments and
150
+ reports ambiguous references. The plugin itself never receives database or UI
151
+ internals and generated SQL is never automatically executed.
152
+
115
153
  Plugin API version 1 does not expose the database worker, `OracleWorkspace`,
116
154
  mutable results or `UIState`, curses objects, global shortcut registration,
117
155
  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