plsqlwks 0.1.6__tar.gz → 0.1.7__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 (115) hide show
  1. plsqlwks-0.1.7/MANIFEST.in +91 -0
  2. {plsqlwks-0.1.6/plsqlwks.egg-info → plsqlwks-0.1.7}/PKG-INFO +75 -9
  3. plsqlwks-0.1.7/QUICKSTART.md +288 -0
  4. plsqlwks-0.1.6/PKG-INFO → plsqlwks-0.1.7/README.md +72 -33
  5. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/__init__.py +1 -1
  6. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/config/models.py +1 -1
  7. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/config/settings.py +10 -13
  8. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/db/editing.py +51 -24
  9. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/db/execution.py +404 -58
  10. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/db/models.py +26 -1
  11. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/db/session.py +17 -0
  12. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/exporting.py +75 -13
  13. plsqlwks-0.1.7/plsqlwks/sqlbinds.py +373 -0
  14. plsqlwks-0.1.7/plsqlwks/sqlsplit.py +836 -0
  15. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/ui/__init__.py +1 -1
  16. plsqlwks-0.1.7/plsqlwks/ui/app.py +356 -0
  17. plsqlwks-0.1.7/plsqlwks/ui/application_controller.py +88 -0
  18. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/ui/browser.py +4 -0
  19. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/ui/buffer.py +166 -28
  20. plsqlwks-0.1.6/plsqlwks/ui/app_tabs_browser.py → plsqlwks-0.1.7/plsqlwks/ui/catalog.py +173 -137
  21. plsqlwks-0.1.7/plsqlwks/ui/command_dispatcher.py +37 -0
  22. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/ui/commands.py +28 -1
  23. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/ui/constants.py +1 -0
  24. plsqlwks-0.1.7/plsqlwks/ui/db_operations.py +396 -0
  25. plsqlwks-0.1.7/plsqlwks/ui/db_session.py +406 -0
  26. plsqlwks-0.1.7/plsqlwks/ui/db_worker.py +397 -0
  27. plsqlwks-0.1.7/plsqlwks/ui/dialogs.py +445 -0
  28. plsqlwks-0.1.7/plsqlwks/ui/documents.py +497 -0
  29. plsqlwks-0.1.6/plsqlwks/ui/app_editor.py → plsqlwks-0.1.7/plsqlwks/ui/editor_controller.py +359 -273
  30. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/ui/errors.py +178 -7
  31. plsqlwks-0.1.7/plsqlwks/ui/input_controller.py +269 -0
  32. plsqlwks-0.1.7/plsqlwks/ui/key_reader.py +51 -0
  33. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/ui/keys.py +6 -3
  34. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/ui/menu.py +11 -4
  35. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/ui/plugin_host.py +3 -3
  36. plsqlwks-0.1.7/plsqlwks/ui/ports.py +71 -0
  37. plsqlwks-0.1.7/plsqlwks/ui/query_controller.py +596 -0
  38. plsqlwks-0.1.6/plsqlwks/ui/app_render.py → plsqlwks-0.1.7/plsqlwks/ui/renderer.py +122 -43
  39. plsqlwks-0.1.6/plsqlwks/ui/app_results.py → plsqlwks-0.1.7/plsqlwks/ui/result_controller.py +202 -98
  40. plsqlwks-0.1.7/plsqlwks/ui/result_presenter.py +766 -0
  41. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/ui/results.py +39 -4
  42. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/ui/state.py +21 -0
  43. plsqlwks-0.1.7/plsqlwks/ui/viewport.py +256 -0
  44. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks.egg-info/SOURCES.txt +17 -31
  45. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/pyproject.toml +13 -6
  46. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/pytest.ini +1 -0
  47. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/tests/conftest.py +73 -6
  48. plsqlwks-0.1.6/MANIFEST.in +0 -8
  49. plsqlwks-0.1.6/README.md +0 -552
  50. plsqlwks-0.1.6/plsqlwks/sqlbinds.py +0 -163
  51. plsqlwks-0.1.6/plsqlwks/sqlsplit.py +0 -275
  52. plsqlwks-0.1.6/plsqlwks/ui/app.py +0 -194
  53. plsqlwks-0.1.6/plsqlwks/ui/app_db.py +0 -932
  54. plsqlwks-0.1.6/plsqlwks/ui/app_files.py +0 -468
  55. plsqlwks-0.1.6/plsqlwks/ui/app_input.py +0 -638
  56. plsqlwks-0.1.6/plsqlwks/ui/db_worker.py +0 -228
  57. plsqlwks-0.1.6/plsqlwks.egg-info/dependency_links.txt +0 -1
  58. plsqlwks-0.1.6/plsqlwks.egg-info/entry_points.txt +0 -2
  59. plsqlwks-0.1.6/plsqlwks.egg-info/requires.txt +0 -11
  60. plsqlwks-0.1.6/plsqlwks.egg-info/top_level.txt +0 -1
  61. plsqlwks-0.1.6/tests/test_config_workspace.py +0 -1014
  62. plsqlwks-0.1.6/tests/test_csv_export_plugin.py +0 -396
  63. plsqlwks-0.1.6/tests/test_db_editing.py +0 -947
  64. plsqlwks-0.1.6/tests/test_db_helpers.py +0 -1890
  65. plsqlwks-0.1.6/tests/test_db_worker.py +0 -464
  66. plsqlwks-0.1.6/tests/test_exporting.py +0 -276
  67. plsqlwks-0.1.6/tests/test_html_export_plugin.py +0 -739
  68. plsqlwks-0.1.6/tests/test_oracle_integration.py +0 -631
  69. plsqlwks-0.1.6/tests/test_packaging.py +0 -407
  70. plsqlwks-0.1.6/tests/test_plugins.py +0 -311
  71. plsqlwks-0.1.6/tests/test_pty_keys.py +0 -101
  72. plsqlwks-0.1.6/tests/test_rchar.py +0 -14
  73. plsqlwks-0.1.6/tests/test_sqlbinds.py +0 -133
  74. plsqlwks-0.1.6/tests/test_sqlsplit.py +0 -343
  75. plsqlwks-0.1.6/tests/test_ui_flows.py +0 -2887
  76. plsqlwks-0.1.6/tests/test_ui_keys.py +0 -4976
  77. plsqlwks-0.1.6/tests/test_ui_plugins.py +0 -907
  78. plsqlwks-0.1.6/tests/test_xlsx_export_plugin.py +0 -1139
  79. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/PLUGINS.md +0 -0
  80. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/license.txt +0 -0
  81. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/__main__.py +0 -0
  82. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/config/__init__.py +0 -0
  83. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/config/loader.py +0 -0
  84. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/config/paths.py +0 -0
  85. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/config/session.py +0 -0
  86. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/db/__init__.py +0 -0
  87. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/db/explain.py +0 -0
  88. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/db/health.py +0 -0
  89. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/db/metadata.py +0 -0
  90. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/db/sql_analysis.py +0 -0
  91. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/db/transactions.py +0 -0
  92. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/html_exporting.py +0 -0
  93. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/plugins/__init__.py +0 -0
  94. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/plugins/_result_export.py +0 -0
  95. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/plugins/api.py +0 -0
  96. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/plugins/csv_export.py +0 -0
  97. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/plugins/html_export.py +0 -0
  98. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/plugins/loader.py +0 -0
  99. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/plugins/xlsx_export.py +0 -0
  100. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/ui/clipboard.py +0 -0
  101. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/ui/completion.py +0 -0
  102. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/ui/display.py +0 -0
  103. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/ui/help.py +0 -0
  104. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/ui/sql.py +0 -0
  105. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/ui/syntax.py +0 -0
  106. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/workspace.py +0 -0
  107. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plsqlwks/xlsx_exporting.py +0 -0
  108. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plugin-requirements/csv-export/requirements.txt +0 -0
  109. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plugin-requirements/html-export/requirements.txt +0 -0
  110. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/plugin-requirements/xlsx-export/requirements.txt +0 -0
  111. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/rchar.py +0 -0
  112. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/requirements.txt +0 -0
  113. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/setup.cfg +0 -0
  114. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/tests/fixtures/config_exports.txt +0 -0
  115. {plsqlwks-0.1.6 → plsqlwks-0.1.7}/tests/fixtures/ui_exports.txt +0 -0
@@ -0,0 +1,91 @@
1
+ # Source distributions are intentionally allowlisted. Keep this list in sync
2
+ # with the exact artifact manifests asserted by tests/test_packaging.py.
3
+ global-exclude *
4
+
5
+ include MANIFEST.in
6
+ include PLUGINS.md
7
+ include QUICKSTART.md
8
+ include README.md
9
+ include license.txt
10
+ include pyproject.toml
11
+ include pytest.ini
12
+ include rchar.py
13
+ include requirements.txt
14
+
15
+ include plsqlwks/__init__.py
16
+ include plsqlwks/__main__.py
17
+ include plsqlwks/exporting.py
18
+ include plsqlwks/html_exporting.py
19
+ include plsqlwks/sqlbinds.py
20
+ include plsqlwks/sqlsplit.py
21
+ include plsqlwks/workspace.py
22
+ include plsqlwks/xlsx_exporting.py
23
+
24
+ include plsqlwks/config/__init__.py
25
+ include plsqlwks/config/loader.py
26
+ include plsqlwks/config/models.py
27
+ include plsqlwks/config/paths.py
28
+ include plsqlwks/config/session.py
29
+ include plsqlwks/config/settings.py
30
+
31
+ include plsqlwks/db/__init__.py
32
+ include plsqlwks/db/editing.py
33
+ include plsqlwks/db/execution.py
34
+ include plsqlwks/db/explain.py
35
+ include plsqlwks/db/health.py
36
+ include plsqlwks/db/metadata.py
37
+ include plsqlwks/db/models.py
38
+ include plsqlwks/db/session.py
39
+ include plsqlwks/db/sql_analysis.py
40
+ include plsqlwks/db/transactions.py
41
+
42
+ include plsqlwks/plugins/__init__.py
43
+ include plsqlwks/plugins/_result_export.py
44
+ include plsqlwks/plugins/api.py
45
+ include plsqlwks/plugins/csv_export.py
46
+ include plsqlwks/plugins/html_export.py
47
+ include plsqlwks/plugins/loader.py
48
+ include plsqlwks/plugins/xlsx_export.py
49
+
50
+ include plsqlwks/ui/__init__.py
51
+ include plsqlwks/ui/app.py
52
+ include plsqlwks/ui/application_controller.py
53
+ include plsqlwks/ui/browser.py
54
+ include plsqlwks/ui/buffer.py
55
+ include plsqlwks/ui/catalog.py
56
+ include plsqlwks/ui/clipboard.py
57
+ include plsqlwks/ui/command_dispatcher.py
58
+ include plsqlwks/ui/commands.py
59
+ include plsqlwks/ui/completion.py
60
+ include plsqlwks/ui/constants.py
61
+ include plsqlwks/ui/db_operations.py
62
+ include plsqlwks/ui/db_session.py
63
+ include plsqlwks/ui/db_worker.py
64
+ include plsqlwks/ui/dialogs.py
65
+ include plsqlwks/ui/display.py
66
+ include plsqlwks/ui/documents.py
67
+ include plsqlwks/ui/editor_controller.py
68
+ include plsqlwks/ui/errors.py
69
+ include plsqlwks/ui/help.py
70
+ include plsqlwks/ui/input_controller.py
71
+ include plsqlwks/ui/key_reader.py
72
+ include plsqlwks/ui/keys.py
73
+ include plsqlwks/ui/menu.py
74
+ include plsqlwks/ui/plugin_host.py
75
+ include plsqlwks/ui/ports.py
76
+ include plsqlwks/ui/query_controller.py
77
+ include plsqlwks/ui/renderer.py
78
+ include plsqlwks/ui/result_controller.py
79
+ include plsqlwks/ui/result_presenter.py
80
+ include plsqlwks/ui/results.py
81
+ include plsqlwks/ui/sql.py
82
+ include plsqlwks/ui/state.py
83
+ include plsqlwks/ui/syntax.py
84
+ include plsqlwks/ui/viewport.py
85
+
86
+ include plugin-requirements/csv-export/requirements.txt
87
+ include plugin-requirements/html-export/requirements.txt
88
+ include plugin-requirements/xlsx-export/requirements.txt
89
+ include tests/conftest.py
90
+ include tests/fixtures/config_exports.txt
91
+ include tests/fixtures/ui_exports.txt
@@ -1,11 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plsqlwks
3
- Version: 0.1.6
3
+ Version: 0.1.7
4
4
  Summary: An ncurses SQL and PL/SQL workspace for Oracle databases.
5
+ Author: unu2000
5
6
  License-Expression: LicenseRef-plsqlwks-Donationware
6
7
  Project-URL: Repository, https://gitlab.com/unununu/plsqlwks
7
8
  Project-URL: Issues, https://gitlab.com/unununu/plsqlwks/-/issues
8
9
  Project-URL: Changelog, https://gitlab.com/unununu/plsqlwks/-/blob/main/CHANGELOG.md
10
+ Project-URL: Ko-fi, https://ko-fi.com/unu2000
9
11
  Classifier: Programming Language :: Python :: 3
10
12
  Classifier: Programming Language :: Python :: 3 :: Only
11
13
  Classifier: Topic :: Database
@@ -27,8 +29,19 @@ Dynamic: license-file
27
29
 
28
30
  An ncurses SQL and PL/SQL workspace for Oracle databases.
29
31
 
32
+ Author and support: [unu2000 on Ko-fi](https://ko-fi.com/unu2000).
33
+
34
+ The supported and continuously tested database releases are Oracle Database
35
+ 19c and Oracle AI Database 26ai. See the
36
+ [Oracle compatibility matrix](https://gitlab.com/unununu/plsqlwks/-/blob/main/COMPATIBILITY.md) for the tested connection and
37
+ privilege profiles, safety gate, and integration-test setup.
38
+
30
39
  ![PLSQLWKS PREVIEW](https://gitlab.com/unununu/plsqlwks/-/raw/main/img/preview.png)
31
40
 
41
+ New here? Follow the [installation-to-first-query quick start](QUICKSTART.md)
42
+ for copy-ready connection setup, screenshots, practical SQL workflows,
43
+ troubleshooting, and a complete installed-plugin example.
44
+
32
45
  ## Connection
33
46
 
34
47
  The default connection is:
@@ -85,7 +98,7 @@ python3 -m pip install .
85
98
  Run the default test and lint checks from a development checkout with:
86
99
 
87
100
  ```bash
88
- python3 -m pytest -q
101
+ python3 -m pytest -q --maxfail=1
89
102
  python3 -m ruff check .
90
103
  ```
91
104
 
@@ -93,8 +106,8 @@ Plugin API and built-in plugin tests are optional and are not part of the
93
106
  default core test run. Run them with either opt-in form:
94
107
 
95
108
  ```bash
96
- PLSQLWKS_TEST_PLUGINS=1 python3 -m pytest -q
97
- python3 -m pytest -q -m plugin
109
+ PLSQLWKS_TEST_PLUGINS=1 python3 -m pytest -q --maxfail=1
110
+ python3 -m pytest -q --maxfail=1 -m plugin
98
111
  ```
99
112
 
100
113
  The CSV and HTML export plugins have no additional dependencies. XLSX export
@@ -111,11 +124,26 @@ retains `plugin-requirements/xlsx-export/requirements.txt` as a compatible
111
124
  fallback for existing checkout automation.
112
125
 
113
126
  Oracle integration tests require the connection environment variables shown
114
- above and an accessible password file. Enable every test group with:
127
+ above and a nonempty regular password file. Setting `PLSQLWKS_TEST_ORACLE=1`
128
+ is an explicit opt-in, so invalid or missing credentials fail collection rather
129
+ than silently skipping the live suite. Set `PLSQLWKS_TEST_ORACLE_TARGET` to
130
+ `19c` or `26ai` when the test run must verify that it reached the intended
131
+ server release:
132
+
133
+ ```bash
134
+ PLSQLWKS_TEST_ORACLE=1 PLSQLWKS_TEST_ORACLE_TARGET=19c \
135
+ python3 -m pytest -q -m oracle --maxfail=1
136
+ ```
137
+
138
+ Omit the target for an ad-hoc run against another reachable Oracle database.
139
+ The complete release-gating setup, including the developer, DML-only, and
140
+ read-only profiles, is documented in the
141
+ [Oracle compatibility matrix](https://gitlab.com/unununu/plsqlwks/-/blob/main/COMPATIBILITY.md).
142
+ Enable every optional test group with:
115
143
 
116
144
  ```bash
117
145
  PLSQLWKS_TEST_ORACLE=1 PLSQLWKS_TEST_PLUGINS=1 PLSQLWKS_TEST_PTY=1 PLSQLWKS_TEST_SLOW=1 \
118
- python3 -m pytest -q -rs
146
+ python3 -m pytest -q -rs --maxfail=1
119
147
  ```
120
148
 
121
149
  ## Run
@@ -136,6 +164,11 @@ The CLI option takes precedence over `PLSQLWKS_WORKSPACE`. For compatibility, a
136
164
  source checkout that already contains a configured `workspace/` continues to
137
165
  use it and displays a migration notice; files are never moved automatically.
138
166
 
167
+ Fresh workspaces start in manual transaction mode and write
168
+ `[database] autocommit = no` to their generated `config.ini`. Existing explicit
169
+ `yes` or `no` settings are preserved; a missing or malformed setting uses the
170
+ safe manual fallback.
171
+
139
172
  Choose the initial transaction mode for one invocation with `--manual` or
140
173
  `--autocommit`. These options override `[database] autocommit` from the active
141
174
  `config.ini`:
@@ -176,9 +209,21 @@ explicitly, so Oracle rolls its uncommitted work back.
176
209
  If the old connection is already dead and reports an error while closing,
177
210
  plsqlwks still attempts the replacement connection and reports the close error
178
211
  as a warning after a successful reconnect.
212
+ An unexpected connection loss is shown in the header and status bar. Rows that
213
+ were already loaded remain available for viewing, but paging, editing, and
214
+ inserting are disabled until reconnect because their live cursor/session state
215
+ is no longer valid. If manual work may have been pending, the status explicitly
216
+ warns that the transaction outcome is unknown.
179
217
 
180
218
  After a successful quit, plsqlwks records the open file-backed tabs, active tab, and cursor positions in the managed `[session.tabs]` section of `config.ini`. Fresh platform-default workspaces use the user-config directory; explicitly selected and legacy workspaces keep `config.ini` inside the workspace for compatibility. On the next start the app tries each saved path independently, silently skips files that are missing or unreadable, and leaves the initial empty tab in place when none can be opened. A saved cursor position that no longer exists in its file starts at the beginning instead. Untitled, template, and generated schema tabs are not persisted because they do not have a file to reopen.
181
219
 
220
+ Worksheet and configuration saves replace their destination atomically while
221
+ preserving an existing file's POSIX permission bits. A
222
+ file-backed worksheet also detects when its file was changed or deleted outside
223
+ plsqlwks and asks whether to overwrite it, save under another name, or cancel.
224
+ Undo and redo update the unsaved-change marker by comparing the current content
225
+ with the last successful save.
226
+
182
227
  ## Keys
183
228
 
184
229
  ### Global
@@ -227,7 +272,7 @@ After a successful quit, plsqlwks records the open file-backed tabs, active tab,
227
272
  | `F4` | New template |
228
273
  | `F5` / `Ctrl-Enter` / `Alt-X` | Execute selected SQL or current statement |
229
274
  | `F11` | Execute selected SQL or whole buffer as a script |
230
- | `Alt-G` | Generate SELECT, INSERT, or UPDATE with table columns |
275
+ | `Alt-G` | Generate SELECT, INSERT, or UPDATE with table or view columns |
231
276
  | `Alt-+` | Refresh autocomplete metadata cache |
232
277
  | `Alt-R` | Rename current buffer |
233
278
  | `Ctrl-T` | New file tab |
@@ -246,7 +291,18 @@ After a successful quit, plsqlwks records the open file-backed tabs, active tab,
246
291
  | `Ctrl+=` | Reconnect |
247
292
 
248
293
  Use `/` on a line by itself after PL/SQL objects or anonymous blocks when running a script.
249
- Execution and explain errors report the mapped editor line and column, then move the cursor to that location when Oracle provides one.
294
+ Script execution reports statement progress as `n/total` and stops at the first
295
+ failed statement while preserving earlier results. Scripts are sent directly to
296
+ Oracle, not through SQL*Plus or SQLcl: client commands such as `PROMPT`, `SPOOL`,
297
+ and `SET SERVEROUTPUT`, and `&`/`&&` substitution variables, are rejected before
298
+ bind prompts or execution. Oracle SQL statements such as `SET TRANSACTION`
299
+ remain supported.
300
+ Execution and explain errors report mapped editor line and column diagnostics.
301
+ The cursor moves only when the buffer still matches the source that was sent to
302
+ Oracle; if it changed while the operation ran, the result warns about the stale
303
+ source instead. Use `Alt-O -> Editor -> Next execution diagnostic` or
304
+ `Previous execution diagnostic` to visit additional locations from the most
305
+ recent unchanged source.
250
306
  When executed or explained SQL contains bind variables such as `:id`, plsqlwks opens a text box for each value and sends the answers as Oracle bind parameters.
251
307
  Unquoted bind names are case-insensitive, so `:id` and `:ID` share one prompt and value. Quoted bind names remain case-sensitive.
252
308
  Set `[database] remember_bind_values = yes` in the active `config.ini` to prefill future bind prompts with values entered earlier in the same app session.
@@ -293,6 +349,7 @@ Read-only mode is a client-side guardrail that rejects statements which the SQL
293
349
  | `Home` / `End` | Move to the first/last result-grid column |
294
350
  | `Ctrl-Home` / `Ctrl-End` | Move to the first/last result-grid row |
295
351
  | `F8` | Toggle result grid / row-detail output |
352
+ | `Ctrl-C` | Copy the selected result cell to the clipboard |
296
353
  | `F10` | View the full selected result cell |
297
354
  | `Enter` | Edit the selected ROWID-backed result cell when available |
298
355
  | `INS` | Prepare a draft insert row for ROWID-backed results |
@@ -307,7 +364,11 @@ unquoted current-schema table that include `ROWID`, press `Enter` on a directly
307
364
  selected unquoted table column to update it by rowid. Press `INS` in the grid to
308
365
  prepare a draft row at the top of the grid, edit its cells with `Enter`, use
309
366
  `Ctrl-Alt-C` to insert it, or use `Esc` to cancel it.
310
- Database null values are displayed and entered as `<NULL>` in editable results. Plain `NULL` is stored as literal text.
367
+ While entering a cell, use Left/Right or Home/End to move within the existing
368
+ text and Backspace/Delete to edit around the cursor. DATE and TIMESTAMP cells
369
+ offer a choice between an ISO value and database-side `SYSDATE`.
370
+ Database null values are displayed and entered as `<NULL>` in editable results.
371
+ Plain `NULL` is stored as literal text.
311
372
  Grid edits compare the selected cell's originally loaded typed value as well as
312
373
  the `ROWID`. If another session changes that cell or deletes the row first, the
313
374
  edit is rejected and the query must be refreshed. Changes to other cells in the
@@ -320,6 +381,11 @@ precision above six, are read-only in the grid.
320
381
  Displayed CLOB and BLOB values are limited to the first 65,536 characters or
321
382
  bytes and include a truncation marker with the full size. Truncated LOB cells
322
383
  cannot be edited safely. Schema-browser DDL is always read in full.
384
+ DBMS_OUTPUT is collected after each statement and after every fetched result
385
+ page without replacing a real query grid. Output-read or cursor-cleanup failures
386
+ are displayed as warnings while preserving successfully fetched rows. PL/SQL
387
+ compiler warnings are also retained with successful statement results; compiler
388
+ errors remain execution failures with navigable source locations.
323
389
  `F7` cycles a grid fullscreen view that starts with the table header on the first terminal line and uses the last line for data, an editor-only fullscreen view, and a split layout with 2/3 editor and 1/3 data grid.
324
390
 
325
391
  To export the active table, use one of these command paths:
@@ -0,0 +1,288 @@
1
+ # PLSQLWKS quick start
2
+
3
+ This guide goes from a source checkout to a first Oracle query in about five
4
+ minutes. It then covers a few useful query workflows, the most common startup
5
+ problems, and a small installed plugin. For the complete key reference and
6
+ runtime behavior, see [README.md](README.md); for the full extension contract,
7
+ see [PLUGINS.md](PLUGINS.md).
8
+
9
+ ## 1. Check the prerequisites
10
+
11
+ You need:
12
+
13
+ - Python 3.10 or newer with the standard-library `curses` module
14
+ - a terminal with at least 80 columns and 24 rows
15
+ - an Oracle username, password, and Easy Connect service name
16
+ - network access to the Oracle listener
17
+
18
+ The DSN in this guide has the form `host:port/service_name`, for example
19
+ `db.example.test:1521/freepdb1`. Ask the database administrator for the exact
20
+ value when in doubt; a service name is not necessarily the same as an Oracle
21
+ SID.
22
+
23
+ ## 2. Install PLSQLWKS
24
+
25
+ From a checkout of the repository, create an isolated environment and install
26
+ the application:
27
+
28
+ ```bash
29
+ python3 -m venv .venv
30
+ source .venv/bin/activate
31
+ python3 -m pip install --upgrade pip
32
+ python3 -m pip install .
33
+ ```
34
+
35
+ Confirm that the console command is available:
36
+
37
+ ```bash
38
+ plsqlwks --help
39
+ ```
40
+
41
+ For development, replace the final install command with
42
+ `python3 -m pip install -e '.[dev]'`.
43
+
44
+ ## 3. Configure the Oracle connection
45
+
46
+ The following Bash example prompts without echoing the password, creates a
47
+ private password file, and exports the connection for the current shell. Change
48
+ the user and DSN to match the target database.
49
+
50
+ ```bash
51
+ config_dir="${XDG_CONFIG_HOME:-$HOME/.config}/plsqlwks"
52
+ mkdir -p "$config_dir"
53
+ chmod 700 "$config_dir"
54
+ umask 077
55
+ IFS= read -r -s -p "Oracle password: " oracle_password
56
+ printf '\n'
57
+ printf '%s' "$oracle_password" > "$config_dir/orapass"
58
+ unset oracle_password
59
+
60
+ export ORACLE_USER='hr'
61
+ export ORACLE_PASSWORD_FILE="$config_dir/orapass"
62
+ export ORACLE_DSN='127.0.0.1:1521/free'
63
+ ```
64
+
65
+ PLSQLWKS preserves spaces in the password and removes only final CR/LF line
66
+ endings. Keep the password file private; on POSIX systems its mode should be
67
+ `0600`.
68
+
69
+ These variables override the built-in defaults. To keep them across terminal
70
+ sessions, add only the three `export` lines to the shell profile; do not put the
71
+ password itself in the profile.
72
+
73
+ ## 4. Run the first query
74
+
75
+ Start in manual transaction mode:
76
+
77
+ ```bash
78
+ plsqlwks --manual
79
+ ```
80
+
81
+ The header should say `db connected`. Enter this query in the upper editor:
82
+
83
+ ```sql
84
+ select
85
+ sys_context('USERENV', 'SESSION_USER') as session_user,
86
+ sys_context('USERENV', 'DB_NAME') as database_name,
87
+ to_char(systimestamp, 'YYYY-MM-DD HH24:MI:SS TZH:TZM') as database_time
88
+ from dual;
89
+ ```
90
+
91
+ Press `F5`, `Ctrl-Enter`, or `Alt-X`. The lower pane shows one row from the
92
+ connected database. Press `Tab` to focus the grid, arrow keys to move between
93
+ cells, and `Tab` again to return to the editor. Press `Ctrl-Q` to quit.
94
+
95
+ ![PLSQLWKS editor and result workspace](https://gitlab.com/unununu/plsqlwks/-/raw/main/img/preview.png)
96
+
97
+ The result is a connection check that does not depend on application tables or
98
+ sample schemas. The displayed user and database name should match the intended
99
+ target before running any write statement.
100
+
101
+ ## Practical query examples
102
+
103
+ ### Prompt for a bind value
104
+
105
+ Execute this statement with `F5`:
106
+
107
+ ```sql
108
+ select :name as supplied_name,
109
+ 'Hello, ' || :name as greeting
110
+ from dual;
111
+ ```
112
+
113
+ PLSQLWKS prompts once for `:name` and passes the answer as an Oracle bind value.
114
+ Set `[database] remember_bind_values = yes` in the active `config.ini` if the
115
+ same bind should be prefilled later in the application session.
116
+
117
+ ### Run a script and inspect DBMS_OUTPUT
118
+
119
+ Use `F11` for a multi-statement script:
120
+
121
+ ```sql
122
+ begin
123
+ dbms_output.put_line(
124
+ 'Connected as ' || sys_context('USERENV', 'SESSION_USER')
125
+ );
126
+ end;
127
+ /
128
+
129
+ select count(*) as visible_objects
130
+ from user_objects;
131
+ ```
132
+
133
+ `F11` runs the whole buffer (or the selection). Press `F6` to switch between
134
+ normal results and captured `DBMS_OUTPUT`.
135
+
136
+ ### Page through a larger result
137
+
138
+ If the connected schema has the Oracle HR sample tables, try:
139
+
140
+ ```sql
141
+ select employee_id, first_name, last_name, department_id
142
+ from employees
143
+ order by employee_id;
144
+ ```
145
+
146
+ `PLSQLWKS_MAX_ROWS` controls the number of rows loaded per page. With the result
147
+ grid focused, use `Ctrl-PageDown` and `Ctrl-PageUp` to page. The status and
148
+ result label say when more rows are available.
149
+
150
+ ### Export loaded rows
151
+
152
+ With a table result visible, press `Alt-O`, type `export`, and choose CSV, HTML,
153
+ or XLSX. The export contains exactly the rows currently loaded in the grid and
154
+ defaults to the workspace `results/` directory. XLSX support requires
155
+ `python3 -m pip install 'plsqlwks[xlsx]'`.
156
+
157
+ ### Commit or roll back deliberately
158
+
159
+ Fresh workspaces use manual transactions. After a DML statement, use
160
+ `Ctrl-Alt-C` to commit or `Ctrl-Alt-R` to roll back. `F12` changes transaction
161
+ mode. The `--read-only` option adds a client-side guardrail against statements
162
+ that appear to write, but database privileges remain the security boundary.
163
+
164
+ ## Troubleshooting
165
+
166
+ | Symptom | What to check |
167
+ | --- | --- |
168
+ | `No module named _curses` or `curses` | Use a Python build and terminal that provide curses. On native Windows, a supported WSL environment is usually the simplest route. |
169
+ | `Password file is missing` | Check `ORACLE_PASSWORD_FILE`, create the file, and restart. The path must name a nonempty regular file. |
170
+ | Password permission warning | Run `chmod 600 "$ORACLE_PASSWORD_FILE"`; also keep its parent directory private. |
171
+ | `ORA-01017` | Recheck `ORACLE_USER`, rewrite the password file without adding unintended characters, and confirm that the account is valid for this service. |
172
+ | `ORA-12514` or `ORA-12154` | Recheck the service name in `ORACLE_DSN`. Easy Connect uses `host:port/service_name`. |
173
+ | `ORA-12541`, timeout, or connection refused | Check host, port, listener availability, VPN, firewall, and DNS from the same terminal. |
174
+ | Header says `db disconnected` after a network problem | Loaded rows remain viewable. Restore connectivity and press `Ctrl+=` to reconnect; if manual work was pending, treat its outcome as unknown until verified. |
175
+ | `Ctrl-Enter` inserts a newline or is not recognized | Terminal key encodings vary. Use `F5` or `Alt-X`, which run the same current-statement action. |
176
+ | Box drawing or non-ASCII text is garbled | Start from a UTF-8 locale such as `C.UTF-8`; check the available names with `locale -a`. |
177
+ | The UI is clipped or a picker will not open | Enlarge the terminal to at least 80 columns by 24 rows. |
178
+ | A write statement is rejected in read-only mode | Restart with `--read-write` only if the account and task are intended to allow writes. |
179
+ | XLSX export reports that `openpyxl` is missing | Install the optional extra with `python3 -m pip install 'plsqlwks[xlsx]'`, then restart. |
180
+
181
+ Press `F1` at any time for the in-application key guide. Connection errors and
182
+ plugin failures are reported in the lower pane; the final status line provides
183
+ the shorter summary.
184
+
185
+ ## Develop a small command plugin
186
+
187
+ Plugin API v1 loads trusted Python packages in the PLSQLWKS process. This
188
+ example adds two commands: one reports the loaded-row count, and the other
189
+ prompts for a label. It needs no dependency beyond PLSQLWKS.
190
+
191
+ Create this layout outside the PLSQLWKS repository:
192
+
193
+ ```text
194
+ result-tools/
195
+ pyproject.toml
196
+ src/
197
+ result_tools/
198
+ __init__.py
199
+ plugin.py
200
+ ```
201
+
202
+ Use this `pyproject.toml`:
203
+
204
+ ```toml
205
+ [build-system]
206
+ requires = ["setuptools>=77"]
207
+ build-backend = "setuptools.build_meta"
208
+
209
+ [project]
210
+ name = "plsqlwks-result-tools"
211
+ version = "0.1.0"
212
+ requires-python = ">=3.10"
213
+ dependencies = ["plsqlwks>=0.1.7"]
214
+
215
+ [project.entry-points."plsqlwks.plugins"]
216
+ result-tools = "result_tools.plugin:create_plugin"
217
+
218
+ [tool.setuptools.packages.find]
219
+ where = ["src"]
220
+ ```
221
+
222
+ Leave `src/result_tools/__init__.py` empty and put this in
223
+ `src/result_tools/plugin.py`:
224
+
225
+ ```python
226
+ from plsqlwks.plugins import Plugin, PluginCommand, PluginContext
227
+
228
+
229
+ def show_loaded_count(context: PluginContext) -> None:
230
+ result = context.get_active_result()
231
+ if result is None:
232
+ context.set_status("No table result is active")
233
+ return
234
+ suffix = "; more rows exist" if result.has_more else ""
235
+ context.set_status(f"{len(result.rows)} loaded row(s){suffix}")
236
+
237
+
238
+ def label_loaded_result(context: PluginContext) -> None:
239
+ result = context.get_active_result()
240
+ if result is None:
241
+ context.set_status("No table result is active")
242
+ return
243
+ label = context.prompt_text("Result label", result.title)
244
+ if label is not None:
245
+ context.set_status(f"{label}: {len(result.rows)} loaded row(s)")
246
+
247
+
248
+ def create_plugin() -> Plugin:
249
+ return Plugin(
250
+ id="result-tools",
251
+ name="Result tools",
252
+ commands=(
253
+ PluginCommand(
254
+ id="show-loaded-count",
255
+ section="Results",
256
+ title="Show loaded row count",
257
+ handler=show_loaded_count,
258
+ keywords="plugin snapshot rows",
259
+ ),
260
+ PluginCommand(
261
+ id="label-loaded-result",
262
+ section="Results",
263
+ title="Label loaded result",
264
+ handler=label_loaded_result,
265
+ keywords="plugin prompt snapshot",
266
+ ),
267
+ ),
268
+ )
269
+ ```
270
+
271
+ Install it into the same virtual environment and perform a factory smoke test:
272
+
273
+ ```bash
274
+ python3 -m pip install -e /path/to/result-tools
275
+ python3 -c "from result_tools.plugin import create_plugin; print(create_plugin())"
276
+ ```
277
+
278
+ Restart PLSQLWKS, open `Alt-O`, and search for `loaded`. Plugin factories are
279
+ discovered only at startup. A bad plugin is skipped with a startup warning, and
280
+ an exception from a command is shown in the UI rather than ending the session.
281
+
282
+ Handlers receive an immutable snapshot of already loaded display rows and a
283
+ small UI-mediated context. API v1 intentionally does not expose database
284
+ execution, Oracle handles, mutable application state, curses drawing, global
285
+ shortcuts, background jobs, lifecycle hooks, or hot reload. Installed plugins
286
+ are not sandboxed, so install them only from sources you trust. Continue with
287
+ [PLUGINS.md](PLUGINS.md) for export-plugin examples, validation rules, optional
288
+ dependencies, and plugin test commands.