neon 3.0.0 → 3.1.0
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.
- package/README.md +54 -0
- package/dist/_shared/auth_selection.js +76 -79
- package/dist/_shared/credentials.js +166 -187
- package/dist/_shared/env-core/env.js +354 -517
- package/dist/_shared/env-core/reuse-secrets.js +159 -203
- package/dist/_shared/paths.js +129 -126
- package/dist/_shared/profiles.js +192 -242
- package/dist/_shared/secure_file.js +36 -38
- package/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/analytics.js +163 -207
- package/dist/api.js +815 -758
- package/dist/auth.js +121 -141
- package/dist/auth_context.js +39 -53
- package/dist/cli.js +4 -7
- package/dist/commands/api.js +220 -250
- package/dist/commands/api_keys.js +251 -314
- package/dist/commands/auth.js +283 -328
- package/dist/commands/bootstrap.js +372 -437
- package/dist/commands/branches.js +304 -455
- package/dist/commands/bucket.js +374 -514
- package/dist/commands/checkout.js +213 -298
- package/dist/commands/config.js +573 -690
- package/dist/commands/connection_string.js +137 -165
- package/dist/commands/data_api.js +238 -260
- package/dist/commands/databases.js +67 -76
- package/dist/commands/deploy.js +31 -25
- package/dist/commands/dev.js +639 -719
- package/dist/commands/diff.js +156 -200
- package/dist/commands/env.js +243 -303
- package/dist/commands/functions.js +275 -355
- package/dist/commands/index.js +70 -65
- package/dist/commands/init.js +84 -119
- package/dist/commands/inspect.js +55 -55
- package/dist/commands/ip_allow.js +88 -120
- package/dist/commands/link.js +874 -1019
- package/dist/commands/logs.js +291 -0
- package/dist/commands/neon_auth.js +725 -933
- package/dist/commands/operations.js +34 -25
- package/dist/commands/orgs.js +28 -18
- package/dist/commands/profile.js +614 -845
- package/dist/commands/projects.js +313 -373
- package/dist/commands/psql.js +60 -58
- package/dist/commands/roles.js +55 -58
- package/dist/commands/schema_diff.js +87 -131
- package/dist/commands/set_context.js +34 -26
- package/dist/commands/snapshots.js +288 -413
- package/dist/commands/status.js +41 -37
- package/dist/commands/user.js +21 -10
- package/dist/commands/vpc_endpoints.js +85 -113
- package/dist/config.js +7 -6
- package/dist/config_format.js +50 -66
- package/dist/config_template.js +128 -157
- package/dist/context.js +183 -235
- package/dist/current_branch_fast_path.js +40 -49
- package/dist/dev/env.js +313 -394
- package/dist/dev/functions.js +54 -68
- package/dist/dev/inputs.js +46 -58
- package/dist/dev/runtime.js +135 -164
- package/dist/dev/websocket.js +766 -959
- package/dist/env.js +27 -33
- package/dist/env_file.js +118 -132
- package/dist/env_services.js +36 -38
- package/dist/errors.js +57 -68
- package/dist/functions_api.js +45 -43
- package/dist/help.js +189 -140
- package/dist/index.js +182 -257
- package/dist/init/agents.js +137 -118
- package/dist/init/auth.js +58 -68
- package/dist/init/bootstrap.js +325 -396
- package/dist/init/build_config.js +4 -2
- package/dist/init/detect_agent.js +56 -101
- package/dist/init/editors.js +35 -52
- package/dist/init/enrich_output.js +51 -66
- package/dist/init/extension.js +134 -171
- package/dist/init/inspect.js +179 -266
- package/dist/init/interactive.js +510 -622
- package/dist/init/neonctl.js +117 -168
- package/dist/init/orchestrate.js +157 -173
- package/dist/init/phases/auth.js +188 -202
- package/dist/init/phases/cleanup.js +23 -23
- package/dist/init/phases/db.js +251 -277
- package/dist/init/phases/getting_started.js +213 -223
- package/dist/init/phases/mcp.js +174 -224
- package/dist/init/phases/migrations.js +247 -248
- package/dist/init/phases/neon_auth.js +114 -133
- package/dist/init/phases/setup.js +546 -703
- package/dist/init/phases/skills.js +75 -86
- package/dist/init/phases/status.js +72 -67
- package/dist/init/resolve_context.js +102 -99
- package/dist/init/route_command.js +91 -98
- package/dist/init/skills.js +174 -218
- package/dist/init/vsix.js +77 -99
- package/dist/log.js +17 -16
- package/dist/neon_services.js +104 -129
- package/dist/parameters.gen.js +481 -471
- package/dist/pkg.js +17 -19
- package/dist/profile_keys.js +44 -47
- package/dist/psql/cli.js +44 -47
- package/dist/psql/command/cmd_cond.js +231 -406
- package/dist/psql/command/cmd_connect.js +557 -764
- package/dist/psql/command/cmd_copy.js +727 -983
- package/dist/psql/command/cmd_describe.js +1499 -1688
- package/dist/psql/command/cmd_format.js +733 -905
- package/dist/psql/command/cmd_io.js +1293 -2082
- package/dist/psql/command/cmd_lo.js +297 -359
- package/dist/psql/command/cmd_meta.js +727 -878
- package/dist/psql/command/cmd_misc.js +138 -172
- package/dist/psql/command/cmd_pipeline.js +547 -1099
- package/dist/psql/command/cmd_restrict.js +119 -155
- package/dist/psql/command/cmd_show.js +529 -688
- package/dist/psql/command/dispatch.js +261 -325
- package/dist/psql/command/inputQueue.js +35 -33
- package/dist/psql/command/shared.js +49 -63
- package/dist/psql/complete/filenames.js +90 -133
- package/dist/psql/complete/index.js +59 -97
- package/dist/psql/complete/matcher.js +236 -300
- package/dist/psql/complete/psqlVars.js +218 -223
- package/dist/psql/complete/queries.js +159 -177
- package/dist/psql/complete/rules.js +1493 -2299
- package/dist/psql/core/common.js +762 -1180
- package/dist/psql/core/help.js +456 -546
- package/dist/psql/core/mainloop.js +692 -1302
- package/dist/psql/core/prompt.js +391 -408
- package/dist/psql/core/settings.js +429 -644
- package/dist/psql/core/sqlHelp.js +480 -554
- package/dist/psql/core/startup.js +626 -815
- package/dist/psql/core/syncVars.js +67 -110
- package/dist/psql/core/variables.js +156 -278
- package/dist/psql/describe/formatters.js +884 -1285
- package/dist/psql/describe/processNamePattern.js +173 -260
- package/dist/psql/describe/queries.js +1368 -2403
- package/dist/psql/describe/versionGate.js +32 -41
- package/dist/psql/index.js +1414 -1927
- package/dist/psql/io/history.js +232 -271
- package/dist/psql/io/input.js +103 -108
- package/dist/psql/io/lineEditor/buffer.js +238 -319
- package/dist/psql/io/lineEditor/complete.js +135 -213
- package/dist/psql/io/lineEditor/filename.js +139 -148
- package/dist/psql/io/lineEditor/index.js +653 -870
- package/dist/psql/io/lineEditor/keymap.js +544 -702
- package/dist/psql/io/lineEditor/vt100.js +294 -341
- package/dist/psql/io/pgpass.js +158 -187
- package/dist/psql/io/pgservice.js +146 -183
- package/dist/psql/io/psqlrc.js +328 -403
- package/dist/psql/print/aligned.js +1020 -1683
- package/dist/psql/print/asciidoc.js +180 -214
- package/dist/psql/print/crosstab.js +281 -442
- package/dist/psql/print/csv.js +48 -70
- package/dist/psql/print/html.js +195 -226
- package/dist/psql/print/json.js +75 -88
- package/dist/psql/print/latex.js +291 -364
- package/dist/psql/print/pager.js +171 -242
- package/dist/psql/print/troff.js +194 -226
- package/dist/psql/print/unaligned.js +69 -95
- package/dist/psql/print/units.js +167 -169
- package/dist/psql/scanner/slash.js +428 -483
- package/dist/psql/scanner/sql.js +445 -889
- package/dist/psql/scanner/stringutils.js +309 -379
- package/dist/psql/types/index.js +2 -7
- package/dist/psql/types/scanner.js +25 -22
- package/dist/psql/wire/connection.js +2042 -2803
- package/dist/psql/wire/copy.js +84 -100
- package/dist/psql/wire/notify.js +39 -59
- package/dist/psql/wire/pipeline.js +305 -518
- package/dist/psql/wire/protocol.js +349 -417
- package/dist/psql/wire/sasl.js +180 -265
- package/dist/psql/wire/tls.js +400 -561
- package/dist/storage_api.js +115 -129
- package/dist/test_utils/fixtures.js +94 -113
- package/dist/test_utils/oauth_server.js +10 -7
- package/dist/test_utils/project_dir.js +33 -0
- package/dist/utils/ai_gateway_notice.js +131 -162
- package/dist/utils/api_enums.js +21 -28
- package/dist/utils/auth.js +10 -4
- package/dist/utils/branch_notice.js +20 -19
- package/dist/utils/branch_picker.js +83 -89
- package/dist/utils/cli_name.js +15 -12
- package/dist/utils/compute_units.js +20 -27
- package/dist/utils/config_diff.js +127 -158
- package/dist/utils/enrichers.js +95 -148
- package/dist/utils/esbuild.js +130 -189
- package/dist/utils/flags.js +35 -47
- package/dist/utils/formats.js +8 -15
- package/dist/utils/git_diff.js +69 -80
- package/dist/utils/inspect_db.js +101 -143
- package/dist/utils/inspect_queries.js +179 -142
- package/dist/utils/middlewares.js +37 -44
- package/dist/utils/openapi.js +87 -99
- package/dist/utils/package_manager.js +312 -110
- package/dist/utils/point_in_time.js +49 -53
- package/dist/utils/psql.js +89 -106
- package/dist/utils/service_picker.js +55 -58
- package/dist/utils/string.js +5 -5
- package/dist/utils/ui.js +38 -55
- package/dist/utils/write_sync.js +26 -35
- package/dist/utils/zip.js +4 -3
- package/dist/writer.js +67 -87
- package/package.json +7 -5
|
@@ -1,2452 +1,1417 @@
|
|
|
1
|
+
import { PG_10, PG_11, PG_12, PG_13, PG_14, PG_15, PG_18, PG_19, PG_9_5, serverAtLeast, serverLess } from "./versionGate.js";
|
|
2
|
+
//#region src/psql/describe/queries.ts
|
|
1
3
|
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* adapted for the active `serverVersion`. The header text (column aliases)
|
|
7
|
-
* matches upstream literally so that WP-20's formatter can rely on stable
|
|
8
|
-
* output column names.
|
|
9
|
-
*
|
|
10
|
-
* Pattern matching (the `processSQLNamePattern` flex routine in upstream) is
|
|
11
|
-
* NOT yet implemented; we accept a `pattern` option and emit a placeholder
|
|
12
|
-
* `(<col> ~ $1 OR $1 IS NULL)` clause where needed. WP-20 wires the real
|
|
13
|
-
* pattern parser. See TODO comments throughout.
|
|
14
|
-
*
|
|
15
|
-
* Translation policy: SQL whitespace is normalized but column aliases and
|
|
16
|
-
* catalog table/column names are byte-identical to upstream. Conditional
|
|
17
|
-
* branches in the C source collapse into TS conditional concatenation gated
|
|
18
|
-
* on `serverVersion`.
|
|
19
|
-
*/
|
|
20
|
-
import { PG_9_5, PG_9_6, PG_10, PG_11, PG_12, PG_13, PG_14, PG_15, PG_16, PG_17, PG_18, PG_19, serverAtLeast, serverLess, } from "./versionGate.js";
|
|
21
|
-
/* ------------------------------------------------------------------ */
|
|
22
|
-
/* Shared helpers */
|
|
23
|
-
/* ------------------------------------------------------------------ */
|
|
4
|
+
* Reproduces upstream `printACLColumn(buf, colname)`: emits the standard
|
|
5
|
+
* ACL pretty-printing expression with column alias "Access privileges".
|
|
6
|
+
*/
|
|
7
|
+
const aclColumn = (colname) => `CASE WHEN pg_catalog.array_length(${colname}, 1) = 0 THEN '(none)' ELSE pg_catalog.array_to_string(${colname}, E'\\n') END AS "Access privileges"`;
|
|
24
8
|
/**
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
* `params` so callers do not need to change call sites later.
|
|
35
|
-
*
|
|
36
|
-
* @param hasWhere whether a WHERE clause already exists in the SQL
|
|
37
|
-
* @param schemaCol column expression for the schema name, or undefined
|
|
38
|
-
* @param nameCol column expression for the object name
|
|
39
|
-
*/
|
|
9
|
+
* Placeholder pattern clause. WP-20 will replace these stubs with the real
|
|
10
|
+
* `processSQLNamePattern` port. For now the clause is a tautology so the
|
|
11
|
+
* query runs unfiltered; the pattern parameter is still threaded through
|
|
12
|
+
* `params` so callers do not need to change call sites later.
|
|
13
|
+
*
|
|
14
|
+
* @param hasWhere whether a WHERE clause already exists in the SQL
|
|
15
|
+
* @param schemaCol column expression for the schema name, or undefined
|
|
16
|
+
* @param nameCol column expression for the object name
|
|
17
|
+
*/
|
|
40
18
|
const patternStub = (hasWhere, schemaCol, nameCol) => {
|
|
41
|
-
|
|
42
|
-
void schemaCol;
|
|
43
|
-
void nameCol;
|
|
44
|
-
const join = hasWhere ? " AND " : "WHERE ";
|
|
45
|
-
return `${join}true /* TODO(WP-20): pattern matching */\n`;
|
|
19
|
+
return `${hasWhere ? " AND " : "WHERE "}true /* TODO(WP-20): pattern matching */\n`;
|
|
46
20
|
};
|
|
47
21
|
/**
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
22
|
+
* Per-argument pattern slot for `\df name argtype1 argtype2 …` and
|
|
23
|
+
* `\do name argtype1 argtype2`. Each slot emits a uniquely tagged
|
|
24
|
+
* placeholder so the dispatcher can substitute the i-th processed
|
|
25
|
+
* type-name pattern (matched against `t<i>.typname`, `nt<i>.nspname`,
|
|
26
|
+
* and `format_type(t<i>.oid, NULL)` like upstream).
|
|
27
|
+
*/
|
|
54
28
|
const argPatternStub = (slot) => `true /* ARG_PATTERN_${slot} */`;
|
|
55
29
|
const orderBy = (cols) => `ORDER BY ${cols};`;
|
|
56
|
-
// Returns the base params for a describe query. Always empty: the pattern
|
|
57
|
-
// itself is threaded through `processSQLNamePattern` + `applyPattern` in
|
|
58
|
-
// cmd_describe.ts, which renders the conditions with their own `$N` slots
|
|
59
|
-
// and pushes the right values into params at runtime. Returning [pattern]
|
|
60
|
-
// here would leave $1 unreferenced in the final SQL (applyPattern shifts
|
|
61
|
-
// the conditions' $N by baseParams.length), causing the server to reject
|
|
62
|
-
// the Parse with "could not determine data type of parameter $1".
|
|
63
30
|
const params = () => [];
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
sql +=
|
|
323
|
-
" pg_catalog.obj_description(t.oid, 'pg_type') as \"Description\"\n";
|
|
324
|
-
sql +=
|
|
325
|
-
"FROM pg_catalog.pg_type t\n" +
|
|
326
|
-
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n";
|
|
327
|
-
sql += "WHERE (t.typrelid = 0 ";
|
|
328
|
-
sql +=
|
|
329
|
-
"OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid))\n";
|
|
330
|
-
if (!pattern?.includes("[]")) {
|
|
331
|
-
sql +=
|
|
332
|
-
" AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid)\n";
|
|
333
|
-
}
|
|
334
|
-
if (!showSystem && pattern === undefined) {
|
|
335
|
-
sql +=
|
|
336
|
-
" AND n.nspname <> 'pg_catalog'\n" +
|
|
337
|
-
" AND n.nspname <> 'information_schema'\n";
|
|
338
|
-
}
|
|
339
|
-
sql += patternStub(true, "n.nspname", "t.typname");
|
|
340
|
-
sql += orderBy("1, 2");
|
|
341
|
-
return { sql, params: params(), description: "List of data types" };
|
|
342
|
-
};
|
|
343
|
-
export const describeOperators = (opts) => {
|
|
344
|
-
const { verbose, showSystem, pattern, serverVersion } = opts;
|
|
345
|
-
let argPatterns = opts.argPatterns ?? [];
|
|
346
|
-
// Upstream caps at 2 — extra args past two are silently dropped.
|
|
347
|
-
if (argPatterns.length > 2)
|
|
348
|
-
argPatterns = argPatterns.slice(0, 2);
|
|
349
|
-
let sql = 'SELECT n.nspname as "Schema",\n' +
|
|
350
|
-
' o.oprname AS "Name",\n' +
|
|
351
|
-
" CASE WHEN o.oprkind='l' THEN NULL ELSE pg_catalog.format_type(o.oprleft, NULL) END AS \"Left arg type\",\n" +
|
|
352
|
-
" CASE WHEN o.oprkind='r' THEN NULL ELSE pg_catalog.format_type(o.oprright, NULL) END AS \"Right arg type\",\n" +
|
|
353
|
-
' pg_catalog.format_type(o.oprresult, NULL) AS "Result type",\n';
|
|
354
|
-
if (verbose) {
|
|
355
|
-
sql += ' o.oprcode AS "Function",\n';
|
|
356
|
-
// PG 18 added "Leakproof?" to verbose `\do+`. Earlier servers only
|
|
357
|
-
// emitted Function and Description.
|
|
358
|
-
if (serverAtLeast(serverVersion, PG_18)) {
|
|
359
|
-
sql +=
|
|
360
|
-
" CASE WHEN p.proleakproof THEN 'yes' ELSE 'no' END AS \"Leakproof?\",\n";
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
sql +=
|
|
364
|
-
" coalesce(pg_catalog.obj_description(o.oid, 'pg_operator'),\n" +
|
|
365
|
-
" pg_catalog.obj_description(o.oprcode, 'pg_proc')) AS \"Description\"\n" +
|
|
366
|
-
"FROM pg_catalog.pg_operator o\n" +
|
|
367
|
-
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n";
|
|
368
|
-
// Upstream emits arg-type joins before the verbose `pg_proc` join.
|
|
369
|
-
// With one arg pattern: only join the right-hand side (oprright);
|
|
370
|
-
// with two: both oprleft/oprright. Tag indices match the join name
|
|
371
|
-
// so `t0/nt0` correspond to the first arg pattern slot.
|
|
372
|
-
if (argPatterns.length === 1) {
|
|
373
|
-
sql +=
|
|
374
|
-
" LEFT JOIN pg_catalog.pg_type t0 ON t0.oid = o.oprright\n" +
|
|
375
|
-
" LEFT JOIN pg_catalog.pg_namespace nt0 ON nt0.oid = t0.typnamespace\n";
|
|
376
|
-
}
|
|
377
|
-
else if (argPatterns.length >= 2) {
|
|
378
|
-
sql +=
|
|
379
|
-
" LEFT JOIN pg_catalog.pg_type t0 ON t0.oid = o.oprleft\n" +
|
|
380
|
-
" LEFT JOIN pg_catalog.pg_namespace nt0 ON nt0.oid = t0.typnamespace\n" +
|
|
381
|
-
" LEFT JOIN pg_catalog.pg_type t1 ON t1.oid = o.oprright\n" +
|
|
382
|
-
" LEFT JOIN pg_catalog.pg_namespace nt1 ON nt1.oid = t1.typnamespace\n";
|
|
383
|
-
}
|
|
384
|
-
if (verbose && serverAtLeast(serverVersion, PG_18)) {
|
|
385
|
-
// Only joined when we need proleakproof from pg_proc (PG 18+).
|
|
386
|
-
sql += " LEFT JOIN pg_catalog.pg_proc p ON p.oid = o.oprcode\n";
|
|
387
|
-
}
|
|
388
|
-
let hasWhere = false;
|
|
389
|
-
if (!showSystem && pattern === undefined) {
|
|
390
|
-
sql +=
|
|
391
|
-
"WHERE n.nspname <> 'pg_catalog'\n AND n.nspname <> 'information_schema'\n";
|
|
392
|
-
hasWhere = true;
|
|
393
|
-
}
|
|
394
|
-
sql += patternStub(hasWhere, "n.nspname", "o.oprname");
|
|
395
|
-
// With a single arg pattern, upstream additionally constrains the
|
|
396
|
-
// operator to be unary-right (oprleft = 0) so unrelated binary
|
|
397
|
-
// operators don't leak through the `t0` join.
|
|
398
|
-
if (argPatterns.length === 1) {
|
|
399
|
-
sql += " AND o.oprleft = 0\n";
|
|
400
|
-
}
|
|
401
|
-
for (let i = 0; i < argPatterns.length; i++) {
|
|
402
|
-
if (argPatterns[i] === "-") {
|
|
403
|
-
sql += ` AND t${i}.typname IS NULL\n`;
|
|
404
|
-
}
|
|
405
|
-
else {
|
|
406
|
-
sql += ` AND ${argPatternStub(i)}\n`;
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
sql += orderBy("1, 2, 3, 4");
|
|
410
|
-
return { sql, params: params(), description: "List of operators" };
|
|
411
|
-
};
|
|
412
|
-
/* ------------------------------------------------------------------ */
|
|
413
|
-
/* \l / \list — listAllDbs */
|
|
414
|
-
/* ------------------------------------------------------------------ */
|
|
415
|
-
export const listAllDbs = (opts) => {
|
|
416
|
-
const { verbose, serverVersion } = opts;
|
|
417
|
-
let sql = "SELECT\n" +
|
|
418
|
-
' d.datname as "Name",\n' +
|
|
419
|
-
' pg_catalog.pg_get_userbyid(d.datdba) as "Owner",\n' +
|
|
420
|
-
' pg_catalog.pg_encoding_to_char(d.encoding) as "Encoding",\n';
|
|
421
|
-
if (serverAtLeast(serverVersion, PG_15)) {
|
|
422
|
-
sql +=
|
|
423
|
-
" CASE d.datlocprovider" +
|
|
424
|
-
" WHEN 'b' THEN 'builtin'" +
|
|
425
|
-
" WHEN 'c' THEN 'libc'" +
|
|
426
|
-
" WHEN 'i' THEN 'icu'" +
|
|
427
|
-
' END AS "Locale Provider",\n';
|
|
428
|
-
}
|
|
429
|
-
else {
|
|
430
|
-
sql += " 'libc' AS \"Locale Provider\",\n";
|
|
431
|
-
}
|
|
432
|
-
sql += ' d.datcollate as "Collate",\n d.datctype as "Ctype",\n';
|
|
433
|
-
if (serverAtLeast(serverVersion, PG_17)) {
|
|
434
|
-
sql += ' d.datlocale as "Locale",\n';
|
|
435
|
-
}
|
|
436
|
-
else if (serverAtLeast(serverVersion, PG_15)) {
|
|
437
|
-
sql += ' d.daticulocale as "Locale",\n';
|
|
438
|
-
}
|
|
439
|
-
else {
|
|
440
|
-
sql += ' NULL as "Locale",\n';
|
|
441
|
-
}
|
|
442
|
-
if (serverAtLeast(serverVersion, PG_16)) {
|
|
443
|
-
sql += ' d.daticurules as "ICU Rules",\n';
|
|
444
|
-
}
|
|
445
|
-
else {
|
|
446
|
-
sql += ' NULL as "ICU Rules",\n';
|
|
447
|
-
}
|
|
448
|
-
sql += " " + aclColumn("d.datacl");
|
|
449
|
-
if (verbose) {
|
|
450
|
-
sql +=
|
|
451
|
-
",\n CASE WHEN pg_catalog.has_database_privilege(d.datname, 'CONNECT')\n" +
|
|
452
|
-
" THEN pg_catalog.pg_size_pretty(pg_catalog.pg_database_size(d.datname))\n" +
|
|
453
|
-
" ELSE 'No Access'\n" +
|
|
454
|
-
' END as "Size"' +
|
|
455
|
-
',\n t.spcname as "Tablespace"' +
|
|
456
|
-
",\n pg_catalog.shobj_description(d.oid, 'pg_database') as \"Description\"";
|
|
457
|
-
}
|
|
458
|
-
sql += "\nFROM pg_catalog.pg_database d\n";
|
|
459
|
-
if (verbose) {
|
|
460
|
-
sql += " JOIN pg_catalog.pg_tablespace t on d.dattablespace = t.oid\n";
|
|
461
|
-
}
|
|
462
|
-
if (opts.pattern !== undefined) {
|
|
463
|
-
sql += patternStub(false, undefined, "d.datname");
|
|
464
|
-
}
|
|
465
|
-
sql += orderBy("1");
|
|
466
|
-
return { sql, params: params(), description: "List of databases" };
|
|
467
|
-
};
|
|
468
|
-
/* ------------------------------------------------------------------ */
|
|
469
|
-
/* \dp / \z — permissionsList */
|
|
470
|
-
/* ------------------------------------------------------------------ */
|
|
471
|
-
export const permissionsList = (opts) => {
|
|
472
|
-
const { showSystem, pattern, serverVersion } = opts;
|
|
473
|
-
let sql = 'SELECT n.nspname as "Schema",\n' +
|
|
474
|
-
' c.relname as "Name",\n' +
|
|
475
|
-
" CASE c.relkind" +
|
|
476
|
-
" WHEN 'r' THEN 'table'" +
|
|
477
|
-
" WHEN 'v' THEN 'view'" +
|
|
478
|
-
" WHEN 'm' THEN 'materialized view'" +
|
|
479
|
-
" WHEN 'S' THEN 'sequence'" +
|
|
480
|
-
" WHEN 'f' THEN 'foreign table'" +
|
|
481
|
-
" WHEN 'p' THEN 'partitioned table'" +
|
|
482
|
-
' END as "Type",\n ';
|
|
483
|
-
sql += aclColumn("c.relacl");
|
|
484
|
-
sql +=
|
|
485
|
-
",\n pg_catalog.array_to_string(ARRAY(\n" +
|
|
486
|
-
" SELECT attname || E':\\n ' || pg_catalog.array_to_string(attacl, E'\\n ')\n" +
|
|
487
|
-
" FROM pg_catalog.pg_attribute a\n" +
|
|
488
|
-
" WHERE attrelid = c.oid AND NOT attisdropped AND attacl IS NOT NULL\n" +
|
|
489
|
-
" ), E'\\n') AS \"Column privileges\"";
|
|
490
|
-
if (serverAtLeast(serverVersion, PG_10)) {
|
|
491
|
-
sql +=
|
|
492
|
-
",\n pg_catalog.array_to_string(ARRAY(\n" +
|
|
493
|
-
" SELECT polname\n" +
|
|
494
|
-
" || CASE WHEN NOT polpermissive THEN E' (RESTRICTIVE)' ELSE '' END\n" +
|
|
495
|
-
" || CASE WHEN polcmd != '*' THEN E' (' || polcmd::pg_catalog.text || E'):' ELSE E':' END\n" +
|
|
496
|
-
" || CASE WHEN polqual IS NOT NULL THEN E'\\n (u): ' || pg_catalog.pg_get_expr(polqual, polrelid) ELSE E'' END\n" +
|
|
497
|
-
" || CASE WHEN polwithcheck IS NOT NULL THEN E'\\n (c): ' || pg_catalog.pg_get_expr(polwithcheck, polrelid) ELSE E'' END\n" +
|
|
498
|
-
" || CASE WHEN polroles <> '{0}' THEN E'\\n to: ' || pg_catalog.array_to_string(\n" +
|
|
499
|
-
" ARRAY(SELECT rolname FROM pg_catalog.pg_roles WHERE oid = ANY (polroles) ORDER BY 1)\n" +
|
|
500
|
-
" , E', ') ELSE E'' END\n" +
|
|
501
|
-
" FROM pg_catalog.pg_policy pol\n" +
|
|
502
|
-
" WHERE polrelid = c.oid), E'\\n') AS \"Policies\"";
|
|
503
|
-
}
|
|
504
|
-
else if (serverAtLeast(serverVersion, PG_9_5)) {
|
|
505
|
-
sql +=
|
|
506
|
-
",\n pg_catalog.array_to_string(ARRAY(\n" +
|
|
507
|
-
" SELECT polname\n" +
|
|
508
|
-
" || CASE WHEN polcmd != '*' THEN E' (' || polcmd::pg_catalog.text || E'):' ELSE E':' END\n" +
|
|
509
|
-
" || CASE WHEN polqual IS NOT NULL THEN E'\\n (u): ' || pg_catalog.pg_get_expr(polqual, polrelid) ELSE E'' END\n" +
|
|
510
|
-
" || CASE WHEN polwithcheck IS NOT NULL THEN E'\\n (c): ' || pg_catalog.pg_get_expr(polwithcheck, polrelid) ELSE E'' END\n" +
|
|
511
|
-
" || CASE WHEN polroles <> '{0}' THEN E'\\n to: ' || pg_catalog.array_to_string(\n" +
|
|
512
|
-
" ARRAY(SELECT rolname FROM pg_catalog.pg_roles WHERE oid = ANY (polroles) ORDER BY 1)\n" +
|
|
513
|
-
" , E', ') ELSE E'' END\n" +
|
|
514
|
-
" FROM pg_catalog.pg_policy pol\n" +
|
|
515
|
-
" WHERE polrelid = c.oid), E'\\n') AS \"Policies\"";
|
|
516
|
-
}
|
|
517
|
-
sql +=
|
|
518
|
-
"\nFROM pg_catalog.pg_class c\n" +
|
|
519
|
-
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n" +
|
|
520
|
-
"WHERE c.relkind IN ('r','v','m','S','f','p')\n";
|
|
521
|
-
if (!showSystem && pattern === undefined) {
|
|
522
|
-
sql +=
|
|
523
|
-
" AND n.nspname <> 'pg_catalog'\n AND n.nspname <> 'information_schema'\n";
|
|
524
|
-
}
|
|
525
|
-
sql += patternStub(true, "n.nspname", "c.relname");
|
|
526
|
-
sql += orderBy("1, 2");
|
|
527
|
-
return { sql, params: params(), description: "Access privileges" };
|
|
528
|
-
};
|
|
529
|
-
/* ------------------------------------------------------------------ */
|
|
530
|
-
/* \ddp — listDefaultACLs */
|
|
531
|
-
/* ------------------------------------------------------------------ */
|
|
532
|
-
export const listDefaultACLs = (opts) => {
|
|
533
|
-
const { serverVersion } = opts;
|
|
534
|
-
// PG 18 added DEFACLOBJ_LARGEOBJECT ('L'); pre-18 servers can never
|
|
535
|
-
// produce that defaclobjtype value, so emitting the WHEN is harmless
|
|
536
|
-
// there — but to mirror upstream `\ddp` output, we gate it.
|
|
537
|
-
let sql = 'SELECT pg_catalog.pg_get_userbyid(d.defaclrole) AS "Owner",\n' +
|
|
538
|
-
' n.nspname AS "Schema",\n' +
|
|
539
|
-
" CASE d.defaclobjtype" +
|
|
540
|
-
" WHEN 'r' THEN 'table'" +
|
|
541
|
-
" WHEN 'S' THEN 'sequence'" +
|
|
542
|
-
" WHEN 'f' THEN 'function'" +
|
|
543
|
-
" WHEN 'T' THEN 'type'" +
|
|
544
|
-
" WHEN 'n' THEN 'schema'";
|
|
545
|
-
if (serverAtLeast(serverVersion, PG_18)) {
|
|
546
|
-
sql += " WHEN 'L' THEN 'large object'";
|
|
547
|
-
}
|
|
548
|
-
sql += ' END AS "Type",\n ';
|
|
549
|
-
sql += aclColumn("d.defaclacl");
|
|
550
|
-
sql +=
|
|
551
|
-
"\nFROM pg_catalog.pg_default_acl d\n" +
|
|
552
|
-
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.defaclnamespace\n";
|
|
553
|
-
sql += patternStub(false, "n.nspname", "pg_catalog.pg_get_userbyid(d.defaclrole)");
|
|
554
|
-
sql += orderBy("1, 2, 3");
|
|
555
|
-
return {
|
|
556
|
-
sql,
|
|
557
|
-
params: params(),
|
|
558
|
-
description: "Default access privileges",
|
|
559
|
-
};
|
|
560
|
-
};
|
|
561
|
-
/* ------------------------------------------------------------------ */
|
|
562
|
-
/* \dd — objectDescription */
|
|
563
|
-
/* ------------------------------------------------------------------ */
|
|
564
|
-
export const objectDescription = (opts) => {
|
|
565
|
-
const sysPart = (objLabel) => !opts.showSystem && opts.pattern === undefined
|
|
566
|
-
? `WHERE n.nspname <> 'pg_catalog' AND n.nspname <> 'information_schema'` +
|
|
567
|
-
` /* ${objLabel} */ `
|
|
568
|
-
: `WHERE true /* ${objLabel} */ `;
|
|
569
|
-
let sql = 'SELECT DISTINCT tt.nspname AS "Schema", tt.name AS "Name", tt.object AS "Object", d.description AS "Description"\n' +
|
|
570
|
-
"FROM (\n";
|
|
571
|
-
sql +=
|
|
572
|
-
" SELECT pgc.oid as oid, pgc.tableoid AS tableoid, n.nspname as nspname,\n" +
|
|
573
|
-
" CAST(pgc.conname AS pg_catalog.text) as name," +
|
|
574
|
-
" CAST('table constraint' AS pg_catalog.text) as object\n" +
|
|
575
|
-
" FROM pg_catalog.pg_constraint pgc\n" +
|
|
576
|
-
" JOIN pg_catalog.pg_class c ON c.oid = pgc.conrelid\n" +
|
|
577
|
-
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n" +
|
|
578
|
-
sysPart("table constraint") +
|
|
579
|
-
"\n";
|
|
580
|
-
sql +=
|
|
581
|
-
"UNION ALL\n" +
|
|
582
|
-
" SELECT pgc.oid, pgc.tableoid, n.nspname,\n" +
|
|
583
|
-
" CAST(pgc.conname AS pg_catalog.text)," +
|
|
584
|
-
" CAST('domain constraint' AS pg_catalog.text)\n" +
|
|
585
|
-
" FROM pg_catalog.pg_constraint pgc\n" +
|
|
586
|
-
" JOIN pg_catalog.pg_type t ON t.oid = pgc.contypid\n" +
|
|
587
|
-
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n" +
|
|
588
|
-
sysPart("domain constraint") +
|
|
589
|
-
"\n";
|
|
590
|
-
sql +=
|
|
591
|
-
"UNION ALL\n" +
|
|
592
|
-
" SELECT o.oid, o.tableoid, n.nspname,\n" +
|
|
593
|
-
" CAST(o.opcname AS pg_catalog.text)," +
|
|
594
|
-
" CAST('operator class' AS pg_catalog.text)\n" +
|
|
595
|
-
" FROM pg_catalog.pg_opclass o\n" +
|
|
596
|
-
" JOIN pg_catalog.pg_am am ON o.opcmethod = am.oid\n" +
|
|
597
|
-
" JOIN pg_catalog.pg_namespace n ON n.oid = o.opcnamespace\n" +
|
|
598
|
-
sysPart("operator class") +
|
|
599
|
-
"\n";
|
|
600
|
-
sql +=
|
|
601
|
-
"UNION ALL\n" +
|
|
602
|
-
" SELECT opf.oid, opf.tableoid, n.nspname,\n" +
|
|
603
|
-
" CAST(opf.opfname AS pg_catalog.text)," +
|
|
604
|
-
" CAST('operator family' AS pg_catalog.text)\n" +
|
|
605
|
-
" FROM pg_catalog.pg_opfamily opf\n" +
|
|
606
|
-
" JOIN pg_catalog.pg_am am ON opf.opfmethod = am.oid\n" +
|
|
607
|
-
" JOIN pg_catalog.pg_namespace n ON opf.opfnamespace = n.oid\n" +
|
|
608
|
-
sysPart("operator family") +
|
|
609
|
-
"\n";
|
|
610
|
-
sql +=
|
|
611
|
-
"UNION ALL\n" +
|
|
612
|
-
" SELECT r.oid, r.tableoid, n.nspname,\n" +
|
|
613
|
-
" CAST(r.rulename AS pg_catalog.text)," +
|
|
614
|
-
" CAST('rule' AS pg_catalog.text)\n" +
|
|
615
|
-
" FROM pg_catalog.pg_rewrite r\n" +
|
|
616
|
-
" JOIN pg_catalog.pg_class c ON c.oid = r.ev_class\n" +
|
|
617
|
-
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n" +
|
|
618
|
-
" WHERE r.rulename != '_RETURN'\n";
|
|
619
|
-
sql +=
|
|
620
|
-
"UNION ALL\n" +
|
|
621
|
-
" SELECT t.oid, t.tableoid, n.nspname,\n" +
|
|
622
|
-
" CAST(t.tgname AS pg_catalog.text)," +
|
|
623
|
-
" CAST('trigger' AS pg_catalog.text)\n" +
|
|
624
|
-
" FROM pg_catalog.pg_trigger t\n" +
|
|
625
|
-
" JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid\n" +
|
|
626
|
-
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n" +
|
|
627
|
-
sysPart("trigger") +
|
|
628
|
-
"\n";
|
|
629
|
-
sql +=
|
|
630
|
-
") AS tt\n" +
|
|
631
|
-
" JOIN pg_catalog.pg_description d ON (tt.oid = d.objoid AND tt.tableoid = d.classoid AND d.objsubid = 0)\n";
|
|
632
|
-
sql += orderBy("1, 2, 3");
|
|
633
|
-
return { sql, params: params(), description: "Object descriptions" };
|
|
634
|
-
};
|
|
635
|
-
/* ------------------------------------------------------------------ */
|
|
636
|
-
/* \d (no args / \d <name>) — describeTableDetails */
|
|
637
|
-
/* This WP delivers ONLY the lookup query; the per-relation detail */
|
|
638
|
-
/* render is WP-20. */
|
|
639
|
-
/* ------------------------------------------------------------------ */
|
|
640
|
-
export const describeTableDetails = (opts) => {
|
|
641
|
-
const { verbose, showSystem, pattern, serverVersion } = opts;
|
|
642
|
-
const hideTableam = opts.hideTableam ?? false;
|
|
643
|
-
// For bare `\d [pattern]` upstream renders the same relations table as
|
|
644
|
-
// `\dtvmsiE` does, with the per-relkind type column populated. Include
|
|
645
|
-
// the verbose-mode columns when caller asks for them so `\d+ [pat]`
|
|
646
|
-
// matches `\dt+ [pat]` shape.
|
|
647
|
-
let sql = 'SELECT n.nspname as "Schema",\n' +
|
|
648
|
-
' c.relname as "Name",\n' +
|
|
649
|
-
" CASE c.relkind" +
|
|
650
|
-
" WHEN 'r' THEN 'table'" +
|
|
651
|
-
" WHEN 'v' THEN 'view'" +
|
|
652
|
-
" WHEN 'm' THEN 'materialized view'" +
|
|
653
|
-
" WHEN 'i' THEN 'index'" +
|
|
654
|
-
" WHEN 'S' THEN 'sequence'" +
|
|
655
|
-
" WHEN 't' THEN 'TOAST table'" +
|
|
656
|
-
" WHEN 'f' THEN 'foreign table'" +
|
|
657
|
-
" WHEN 'p' THEN 'partitioned table'" +
|
|
658
|
-
" WHEN 'I' THEN 'partitioned index'" +
|
|
659
|
-
' END as "Type",\n' +
|
|
660
|
-
' pg_catalog.pg_get_userbyid(c.relowner) as "Owner"';
|
|
661
|
-
if (verbose) {
|
|
662
|
-
sql +=
|
|
663
|
-
",\n CASE c.relpersistence" +
|
|
664
|
-
" WHEN 'p' THEN 'permanent'" +
|
|
665
|
-
" WHEN 't' THEN 'temporary'" +
|
|
666
|
-
" WHEN 'u' THEN 'unlogged'" +
|
|
667
|
-
' END as "Persistence"';
|
|
668
|
-
if (!hideTableam && serverAtLeast(serverVersion, PG_12)) {
|
|
669
|
-
sql += ',\n am.amname as "Access method"';
|
|
670
|
-
}
|
|
671
|
-
sql +=
|
|
672
|
-
',\n pg_catalog.pg_size_pretty(pg_catalog.pg_total_relation_size(c.oid)) as "Size"' +
|
|
673
|
-
",\n pg_catalog.obj_description(c.oid, 'pg_class') as \"Description\"";
|
|
674
|
-
}
|
|
675
|
-
sql +=
|
|
676
|
-
"\nFROM pg_catalog.pg_class c" +
|
|
677
|
-
"\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace";
|
|
678
|
-
if (verbose && !hideTableam && serverAtLeast(serverVersion, PG_12)) {
|
|
679
|
-
sql += "\n LEFT JOIN pg_catalog.pg_am am ON am.oid = c.relam";
|
|
680
|
-
}
|
|
681
|
-
sql += "\nWHERE c.relkind IN ('r','p','v','m','S','f','')\n";
|
|
682
|
-
if (!showSystem && pattern === undefined) {
|
|
683
|
-
sql +=
|
|
684
|
-
" AND n.nspname <> 'pg_catalog'\n" +
|
|
685
|
-
" AND n.nspname !~ '^pg_toast'\n" +
|
|
686
|
-
" AND n.nspname <> 'information_schema'\n";
|
|
687
|
-
}
|
|
688
|
-
sql += patternStub(true, "n.nspname", "c.relname");
|
|
689
|
-
sql += orderBy("1,2");
|
|
690
|
-
return {
|
|
691
|
-
sql,
|
|
692
|
-
params: params(),
|
|
693
|
-
description: "List of relations",
|
|
694
|
-
};
|
|
695
|
-
};
|
|
696
|
-
/* ------------------------------------------------------------------ */
|
|
697
|
-
/* \du / \dg — describeRoles */
|
|
698
|
-
/* ------------------------------------------------------------------ */
|
|
699
|
-
/**
|
|
700
|
-
* Upstream `describeRoles` (psql/describe.c) fetches the raw boolean
|
|
701
|
-
* columns then builds the cooked "Attributes" cell client-side from
|
|
702
|
-
* fixed per-flag strings. We do that aggregation in SQL via a
|
|
703
|
-
* NULL-skipping array_to_string so the printer sees only the final
|
|
704
|
-
* two visible columns ("Role name", "Attributes") plus an optional
|
|
705
|
-
* "Description" column when `+` is used. This matches the column
|
|
706
|
-
* layout, header banner ("List of roles"), and content ordering of
|
|
707
|
-
* vanilla psql 18, including the `Cannot login`-only rows produced by
|
|
708
|
-
* `\du regress_du_role*` in `src/test/regress/expected/psql.out`.
|
|
709
|
-
*/
|
|
710
|
-
export const describeRoles = (opts) => {
|
|
711
|
-
const { verbose, showSystem, pattern, serverVersion } = opts;
|
|
712
|
-
// Per-flag attribute strings, in upstream order. Each VALUES row
|
|
713
|
-
// contributes one string (or NULL when the flag is off) so
|
|
714
|
-
// array_to_string can join them with ", ".
|
|
715
|
-
const attrParts = [
|
|
716
|
-
"CASE WHEN r.rolsuper THEN 'Superuser' END",
|
|
717
|
-
"CASE WHEN NOT r.rolinherit THEN 'No inheritance' END",
|
|
718
|
-
"CASE WHEN r.rolcreaterole THEN 'Create role' END",
|
|
719
|
-
"CASE WHEN r.rolcreatedb THEN 'Create DB' END",
|
|
720
|
-
"CASE WHEN NOT r.rolcanlogin THEN 'Cannot login' END",
|
|
721
|
-
"CASE WHEN r.rolreplication THEN 'Replication' END",
|
|
722
|
-
];
|
|
723
|
-
if (serverAtLeast(serverVersion, PG_9_5)) {
|
|
724
|
-
attrParts.push("CASE WHEN r.rolbypassrls THEN 'Bypass RLS' END");
|
|
725
|
-
}
|
|
726
|
-
// `rolconnlimit = -1` means unlimited; only render when >= 0.
|
|
727
|
-
attrParts.push("CASE WHEN r.rolconnlimit >= 0 THEN" +
|
|
728
|
-
" pg_catalog.format('%s connection%s', r.rolconnlimit," +
|
|
729
|
-
" CASE WHEN r.rolconnlimit = 1 THEN '' ELSE 's' END) END");
|
|
730
|
-
// `rolvaliduntil` rendered with upstream's `Password valid until <ts>`.
|
|
731
|
-
attrParts.push("CASE WHEN r.rolvaliduntil IS NOT NULL THEN" +
|
|
732
|
-
" pg_catalog.format('Password valid until %s', r.rolvaliduntil) END");
|
|
733
|
-
const attrValues = attrParts.map((p) => `(${p})`).join(",\n ");
|
|
734
|
-
let sql = 'SELECT r.rolname AS "Role name",\n' +
|
|
735
|
-
" pg_catalog.array_to_string(ARRAY(\n" +
|
|
736
|
-
" SELECT a FROM (VALUES\n" +
|
|
737
|
-
` ${attrValues}\n` +
|
|
738
|
-
" ) AS x(a)\n" +
|
|
739
|
-
" WHERE a IS NOT NULL\n" +
|
|
740
|
-
" ), ', ') AS \"Attributes\"";
|
|
741
|
-
if (verbose) {
|
|
742
|
-
sql +=
|
|
743
|
-
",\n pg_catalog.shobj_description(r.oid, 'pg_authid') AS \"Description\"";
|
|
744
|
-
}
|
|
745
|
-
sql += "\nFROM pg_catalog.pg_roles r\n";
|
|
746
|
-
let hasWhere = false;
|
|
747
|
-
if (!showSystem && pattern === undefined) {
|
|
748
|
-
sql += "WHERE r.rolname !~ '^pg_'\n";
|
|
749
|
-
hasWhere = true;
|
|
750
|
-
}
|
|
751
|
-
sql += patternStub(hasWhere, undefined, "r.rolname");
|
|
752
|
-
sql += orderBy("1");
|
|
753
|
-
return { sql, params: params(), description: "List of roles" };
|
|
754
|
-
};
|
|
755
|
-
export const listDbRoleSettings = (opts) => {
|
|
756
|
-
let sql = 'SELECT rolname AS "Role", datname AS "Database",\n' +
|
|
757
|
-
"pg_catalog.array_to_string(setconfig, E'\\n') AS \"Settings\"\n" +
|
|
758
|
-
"FROM pg_catalog.pg_db_role_setting s\n" +
|
|
759
|
-
"LEFT JOIN pg_catalog.pg_database d ON d.oid = setdatabase\n" +
|
|
760
|
-
"LEFT JOIN pg_catalog.pg_roles r ON r.oid = setrole\n";
|
|
761
|
-
let hasWhere = false;
|
|
762
|
-
if (opts.pattern !== undefined) {
|
|
763
|
-
sql += patternStub(hasWhere, undefined, "r.rolname");
|
|
764
|
-
hasWhere = true;
|
|
765
|
-
}
|
|
766
|
-
if (opts.pattern2 !== undefined) {
|
|
767
|
-
sql += patternStub(hasWhere, undefined, "d.datname");
|
|
768
|
-
}
|
|
769
|
-
sql += orderBy("1, 2");
|
|
770
|
-
const ps = [];
|
|
771
|
-
if (opts.pattern !== undefined)
|
|
772
|
-
ps.push(opts.pattern);
|
|
773
|
-
if (opts.pattern2 !== undefined)
|
|
774
|
-
ps.push(opts.pattern2);
|
|
775
|
-
return { sql, params: ps, description: "List of settings" };
|
|
776
|
-
};
|
|
777
|
-
/* ------------------------------------------------------------------ */
|
|
778
|
-
/* \drg — describeRoleGrants */
|
|
779
|
-
/* ------------------------------------------------------------------ */
|
|
780
|
-
export const describeRoleGrants = (opts) => {
|
|
781
|
-
const { showSystem, pattern, serverVersion } = opts;
|
|
782
|
-
let sql = 'SELECT m.rolname AS "Role name", r.rolname AS "Member of",\n' +
|
|
783
|
-
" pg_catalog.concat_ws(', ',\n";
|
|
784
|
-
if (serverAtLeast(serverVersion, PG_16)) {
|
|
785
|
-
sql +=
|
|
786
|
-
" CASE WHEN pam.admin_option THEN 'ADMIN' END,\n" +
|
|
787
|
-
" CASE WHEN pam.inherit_option THEN 'INHERIT' END,\n" +
|
|
788
|
-
" CASE WHEN pam.set_option THEN 'SET' END\n";
|
|
789
|
-
}
|
|
790
|
-
else {
|
|
791
|
-
sql +=
|
|
792
|
-
" CASE WHEN pam.admin_option THEN 'ADMIN' END,\n" +
|
|
793
|
-
" CASE WHEN m.rolinherit THEN 'INHERIT' END,\n" +
|
|
794
|
-
" 'SET'\n";
|
|
795
|
-
}
|
|
796
|
-
sql += ' ) AS "Options",\n g.rolname AS "Grantor"\n';
|
|
797
|
-
sql +=
|
|
798
|
-
"FROM pg_catalog.pg_roles m\n" +
|
|
799
|
-
" JOIN pg_catalog.pg_auth_members pam ON (pam.member = m.oid)\n" +
|
|
800
|
-
" LEFT JOIN pg_catalog.pg_roles r ON (pam.roleid = r.oid)\n" +
|
|
801
|
-
" LEFT JOIN pg_catalog.pg_roles g ON (pam.grantor = g.oid)\n";
|
|
802
|
-
let hasWhere = false;
|
|
803
|
-
if (!showSystem && pattern === undefined) {
|
|
804
|
-
sql += "WHERE m.rolname !~ '^pg_'\n";
|
|
805
|
-
hasWhere = true;
|
|
806
|
-
}
|
|
807
|
-
sql += patternStub(hasWhere, undefined, "m.rolname");
|
|
808
|
-
sql += orderBy("1, 2, 4");
|
|
809
|
-
return { sql, params: params(), description: "List of role grants" };
|
|
810
|
-
};
|
|
811
|
-
export const listTables = (opts) => {
|
|
812
|
-
const { verbose, showSystem, pattern, serverVersion } = opts;
|
|
813
|
-
const hideTableam = opts.hideTableam ?? false;
|
|
814
|
-
const tt = opts.tabtypes ?? "";
|
|
815
|
-
let showTables = tt.includes("t");
|
|
816
|
-
const showIndexes = tt.includes("i");
|
|
817
|
-
let showViews = tt.includes("v");
|
|
818
|
-
let showMatViews = tt.includes("m");
|
|
819
|
-
let showSeq = tt.includes("s");
|
|
820
|
-
let showForeign = tt.includes("E");
|
|
821
|
-
const ntypes = +showTables +
|
|
822
|
-
+showIndexes +
|
|
823
|
-
+showViews +
|
|
824
|
-
+showMatViews +
|
|
825
|
-
+showSeq +
|
|
826
|
-
+showForeign;
|
|
827
|
-
if (ntypes === 0) {
|
|
828
|
-
showTables = showViews = showMatViews = showSeq = showForeign = true;
|
|
829
|
-
}
|
|
830
|
-
let sql = 'SELECT n.nspname as "Schema",\n' +
|
|
831
|
-
' c.relname as "Name",\n' +
|
|
832
|
-
" CASE c.relkind" +
|
|
833
|
-
" WHEN 'r' THEN 'table'" +
|
|
834
|
-
" WHEN 'v' THEN 'view'" +
|
|
835
|
-
" WHEN 'm' THEN 'materialized view'" +
|
|
836
|
-
" WHEN 'i' THEN 'index'" +
|
|
837
|
-
" WHEN 'S' THEN 'sequence'" +
|
|
838
|
-
" WHEN 't' THEN 'TOAST table'" +
|
|
839
|
-
" WHEN 'f' THEN 'foreign table'" +
|
|
840
|
-
" WHEN 'p' THEN 'partitioned table'" +
|
|
841
|
-
" WHEN 'I' THEN 'partitioned index'" +
|
|
842
|
-
' END as "Type",\n' +
|
|
843
|
-
' pg_catalog.pg_get_userbyid(c.relowner) as "Owner"';
|
|
844
|
-
if (showIndexes)
|
|
845
|
-
sql += ',\n c2.relname as "Table"';
|
|
846
|
-
if (verbose) {
|
|
847
|
-
sql +=
|
|
848
|
-
",\n CASE c.relpersistence" +
|
|
849
|
-
" WHEN 'p' THEN 'permanent'" +
|
|
850
|
-
" WHEN 't' THEN 'temporary'" +
|
|
851
|
-
" WHEN 'u' THEN 'unlogged'" +
|
|
852
|
-
' END as "Persistence"';
|
|
853
|
-
const wantsAm = !hideTableam &&
|
|
854
|
-
serverAtLeast(serverVersion, PG_12) &&
|
|
855
|
-
(showTables || showMatViews || showIndexes);
|
|
856
|
-
if (wantsAm)
|
|
857
|
-
sql += ',\n am.amname as "Access method"';
|
|
858
|
-
// Upstream uses `pg_total_relation_size` (table + indexes + toast)
|
|
859
|
-
// in verbose mode so the formatting matches `pg_size_pretty` exactly
|
|
860
|
-
// — including the "8192 bytes" vs "8 kB" threshold the upstream
|
|
861
|
-
// tests pin to.
|
|
862
|
-
sql +=
|
|
863
|
-
',\n pg_catalog.pg_size_pretty(pg_catalog.pg_total_relation_size(c.oid)) as "Size"' +
|
|
864
|
-
",\n pg_catalog.obj_description(c.oid, 'pg_class') as \"Description\"";
|
|
865
|
-
}
|
|
866
|
-
sql +=
|
|
867
|
-
"\nFROM pg_catalog.pg_class c" +
|
|
868
|
-
"\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace";
|
|
869
|
-
if (verbose &&
|
|
870
|
-
!hideTableam &&
|
|
871
|
-
serverAtLeast(serverVersion, PG_12) &&
|
|
872
|
-
(showTables || showMatViews || showIndexes)) {
|
|
873
|
-
sql += "\n LEFT JOIN pg_catalog.pg_am am ON am.oid = c.relam";
|
|
874
|
-
}
|
|
875
|
-
if (showIndexes) {
|
|
876
|
-
sql +=
|
|
877
|
-
"\n LEFT JOIN pg_catalog.pg_index i ON i.indexrelid = c.oid" +
|
|
878
|
-
"\n LEFT JOIN pg_catalog.pg_class c2 ON i.indrelid = c2.oid";
|
|
879
|
-
}
|
|
880
|
-
sql += "\nWHERE c.relkind IN (";
|
|
881
|
-
const kinds = [];
|
|
882
|
-
if (showTables) {
|
|
883
|
-
kinds.push("'r'", "'p'");
|
|
884
|
-
if (showSystem || pattern !== undefined)
|
|
885
|
-
kinds.push("'t'");
|
|
886
|
-
}
|
|
887
|
-
if (showViews)
|
|
888
|
-
kinds.push("'v'");
|
|
889
|
-
if (showMatViews)
|
|
890
|
-
kinds.push("'m'");
|
|
891
|
-
if (showIndexes)
|
|
892
|
-
kinds.push("'i'", "'I'");
|
|
893
|
-
if (showSeq)
|
|
894
|
-
kinds.push("'S'");
|
|
895
|
-
if (showSystem || pattern !== undefined)
|
|
896
|
-
kinds.push("'s'");
|
|
897
|
-
if (showForeign)
|
|
898
|
-
kinds.push("'f'");
|
|
899
|
-
kinds.push("''");
|
|
900
|
-
sql += kinds.join(",") + ")\n";
|
|
901
|
-
if (!showSystem && pattern === undefined) {
|
|
902
|
-
sql +=
|
|
903
|
-
" AND n.nspname <> 'pg_catalog'\n" +
|
|
904
|
-
" AND n.nspname !~ '^pg_toast'\n" +
|
|
905
|
-
" AND n.nspname <> 'information_schema'\n";
|
|
906
|
-
}
|
|
907
|
-
sql += patternStub(true, "n.nspname", "c.relname");
|
|
908
|
-
sql += orderBy("1,2");
|
|
909
|
-
// Upstream `describe.c::listTables` uses a type-specific title when the
|
|
910
|
-
// caller filters to a single relkind family, falling back to "relations"
|
|
911
|
-
// for mixed (or default) selections. Mirror that so `\dt` / `\dv` /
|
|
912
|
-
// `\dm` / `\di` / `\ds` / `\dE` titles match.
|
|
913
|
-
let description = "List of relations";
|
|
914
|
-
if (ntypes === 1) {
|
|
915
|
-
if (showTables)
|
|
916
|
-
description = "List of tables";
|
|
917
|
-
else if (showIndexes)
|
|
918
|
-
description = "List of indexes";
|
|
919
|
-
else if (showViews)
|
|
920
|
-
description = "List of views";
|
|
921
|
-
else if (showMatViews)
|
|
922
|
-
description = "List of materialized views";
|
|
923
|
-
else if (showSeq)
|
|
924
|
-
description = "List of sequences";
|
|
925
|
-
else if (showForeign)
|
|
926
|
-
description = "List of foreign tables";
|
|
927
|
-
}
|
|
928
|
-
return { sql, params: params(), description };
|
|
929
|
-
};
|
|
930
|
-
export const listPartitionedTables = (opts) => {
|
|
931
|
-
const { verbose, pattern, serverVersion } = opts;
|
|
932
|
-
if (serverLess(serverVersion, PG_10)) {
|
|
933
|
-
return {
|
|
934
|
-
sql: "/* server < 10 does not support declarative partitioning */ SELECT 1 WHERE false;",
|
|
935
|
-
params: [],
|
|
936
|
-
description: "List of partitioned relations",
|
|
937
|
-
};
|
|
938
|
-
}
|
|
939
|
-
const rt = opts.reltypes ?? "";
|
|
940
|
-
let showTables = rt.includes("t");
|
|
941
|
-
let showIndexes = rt.includes("i");
|
|
942
|
-
const showNested = rt.includes("n");
|
|
943
|
-
if (!showTables && !showIndexes)
|
|
944
|
-
showTables = showIndexes = true;
|
|
945
|
-
const mixed = showTables && showIndexes;
|
|
946
|
-
let sql = 'SELECT n.nspname as "Schema",\n' +
|
|
947
|
-
' c.relname as "Name",\n' +
|
|
948
|
-
' pg_catalog.pg_get_userbyid(c.relowner) as "Owner"';
|
|
949
|
-
if (mixed) {
|
|
950
|
-
sql +=
|
|
951
|
-
",\n CASE c.relkind" +
|
|
952
|
-
" WHEN 'p' THEN 'partitioned table'" +
|
|
953
|
-
" WHEN 'I' THEN 'partitioned index'" +
|
|
954
|
-
' END as "Type"';
|
|
955
|
-
}
|
|
956
|
-
if (showNested || pattern !== undefined) {
|
|
957
|
-
sql += ',\n inh.inhparent::pg_catalog.regclass as "Parent name"';
|
|
958
|
-
}
|
|
959
|
-
if (showIndexes) {
|
|
960
|
-
sql += ',\n c2.oid::pg_catalog.regclass as "Table"';
|
|
961
|
-
}
|
|
962
|
-
if (verbose) {
|
|
963
|
-
sql += ',\n am.amname as "Access method"';
|
|
964
|
-
if (showNested) {
|
|
965
|
-
sql += ',\n s.dps as "Leaf partition size"';
|
|
966
|
-
sql += ',\n s.tps as "Total size"';
|
|
967
|
-
}
|
|
968
|
-
else {
|
|
969
|
-
sql += ',\n s.tps as "Total size"';
|
|
970
|
-
}
|
|
971
|
-
sql +=
|
|
972
|
-
",\n pg_catalog.obj_description(c.oid, 'pg_class') as \"Description\"";
|
|
973
|
-
}
|
|
974
|
-
sql +=
|
|
975
|
-
"\nFROM pg_catalog.pg_class c" +
|
|
976
|
-
"\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace";
|
|
977
|
-
if (showIndexes) {
|
|
978
|
-
sql +=
|
|
979
|
-
"\n LEFT JOIN pg_catalog.pg_index i ON i.indexrelid = c.oid" +
|
|
980
|
-
"\n LEFT JOIN pg_catalog.pg_class c2 ON i.indrelid = c2.oid";
|
|
981
|
-
}
|
|
982
|
-
if (showNested || pattern !== undefined) {
|
|
983
|
-
sql +=
|
|
984
|
-
"\n LEFT JOIN pg_catalog.pg_inherits inh ON c.oid = inh.inhrelid";
|
|
985
|
-
}
|
|
986
|
-
if (verbose) {
|
|
987
|
-
sql += "\n LEFT JOIN pg_catalog.pg_am am ON c.relam = am.oid";
|
|
988
|
-
if (serverLess(serverVersion, PG_12)) {
|
|
989
|
-
sql +=
|
|
990
|
-
",\n LATERAL (WITH RECURSIVE d AS (\n" +
|
|
991
|
-
" SELECT inhrelid AS oid, 1 AS level FROM pg_catalog.pg_inherits WHERE inhparent = c.oid\n" +
|
|
992
|
-
" UNION ALL\n" +
|
|
993
|
-
" SELECT inhrelid, level + 1 FROM pg_catalog.pg_inherits i JOIN d ON i.inhparent = d.oid)\n" +
|
|
994
|
-
" SELECT pg_catalog.pg_size_pretty(sum(pg_catalog.pg_table_size(d.oid))) AS tps,\n" +
|
|
995
|
-
" pg_catalog.pg_size_pretty(sum(CASE WHEN d.level = 1 THEN pg_catalog.pg_table_size(d.oid) ELSE 0 END)) AS dps\n" +
|
|
996
|
-
" FROM d) s";
|
|
997
|
-
}
|
|
998
|
-
else {
|
|
999
|
-
sql +=
|
|
1000
|
-
",\n LATERAL (SELECT pg_catalog.pg_size_pretty(sum(\n" +
|
|
1001
|
-
" CASE WHEN ppt.isleaf AND ppt.level = 1\n" +
|
|
1002
|
-
" THEN pg_catalog.pg_table_size(ppt.relid) ELSE 0 END)) AS dps,\n" +
|
|
1003
|
-
" pg_catalog.pg_size_pretty(sum(pg_catalog.pg_table_size(ppt.relid))) AS tps\n" +
|
|
1004
|
-
" FROM pg_catalog.pg_partition_tree(c.oid) ppt) s";
|
|
1005
|
-
}
|
|
1006
|
-
}
|
|
1007
|
-
sql += "\nWHERE c.relkind IN (";
|
|
1008
|
-
const kinds = [];
|
|
1009
|
-
if (showTables)
|
|
1010
|
-
kinds.push("'p'");
|
|
1011
|
-
if (showIndexes)
|
|
1012
|
-
kinds.push("'I'");
|
|
1013
|
-
kinds.push("''");
|
|
1014
|
-
sql += kinds.join(",") + ")\n";
|
|
1015
|
-
if (!showNested && pattern === undefined) {
|
|
1016
|
-
sql += " AND NOT c.relispartition\n";
|
|
1017
|
-
}
|
|
1018
|
-
if (pattern === undefined) {
|
|
1019
|
-
sql +=
|
|
1020
|
-
" AND n.nspname <> 'pg_catalog'\n" +
|
|
1021
|
-
" AND n.nspname !~ '^pg_toast'\n" +
|
|
1022
|
-
" AND n.nspname <> 'information_schema'\n";
|
|
1023
|
-
}
|
|
1024
|
-
sql += patternStub(true, "n.nspname", "c.relname");
|
|
1025
|
-
sql += `ORDER BY "Schema", ${mixed ? '"Type" DESC, ' : ""}${showNested || pattern !== undefined ? '"Parent name" NULLS FIRST, ' : ""}"Name";`;
|
|
1026
|
-
// Mirror upstream's `tabletitle` switch: `\dPi*` lists indexes,
|
|
1027
|
-
// `\dPt*` lists tables, and any mixed/empty form lists relations.
|
|
1028
|
-
const description = showIndexes && !showTables
|
|
1029
|
-
? "List of partitioned indexes"
|
|
1030
|
-
: showTables && !showIndexes
|
|
1031
|
-
? "List of partitioned tables"
|
|
1032
|
-
: "List of partitioned relations";
|
|
1033
|
-
return {
|
|
1034
|
-
sql,
|
|
1035
|
-
params: params(),
|
|
1036
|
-
description,
|
|
1037
|
-
};
|
|
1038
|
-
};
|
|
1039
|
-
/* ------------------------------------------------------------------ */
|
|
1040
|
-
/* \dL — listLanguages */
|
|
1041
|
-
/* ------------------------------------------------------------------ */
|
|
1042
|
-
export const listLanguages = (opts) => {
|
|
1043
|
-
const { verbose, showSystem, pattern } = opts;
|
|
1044
|
-
let sql = 'SELECT l.lanname AS "Name",\n' +
|
|
1045
|
-
' pg_catalog.pg_get_userbyid(l.lanowner) as "Owner",\n' +
|
|
1046
|
-
' l.lanpltrusted AS "Trusted"';
|
|
1047
|
-
if (verbose) {
|
|
1048
|
-
sql +=
|
|
1049
|
-
',\n NOT l.lanispl AS "Internal language",\n' +
|
|
1050
|
-
' l.lanplcallfoid::pg_catalog.regprocedure AS "Call handler",\n' +
|
|
1051
|
-
' l.lanvalidator::pg_catalog.regprocedure AS "Validator",\n ' +
|
|
1052
|
-
'l.laninline::pg_catalog.regprocedure AS "Inline handler",\n ' +
|
|
1053
|
-
aclColumn("l.lanacl");
|
|
1054
|
-
}
|
|
1055
|
-
sql +=
|
|
1056
|
-
',\n d.description AS "Description"\n' +
|
|
1057
|
-
"FROM pg_catalog.pg_language l\n" +
|
|
1058
|
-
"LEFT JOIN pg_catalog.pg_description d\n" +
|
|
1059
|
-
" ON d.classoid = l.tableoid AND d.objoid = l.oid AND d.objsubid = 0\n";
|
|
1060
|
-
let hasWhere = false;
|
|
1061
|
-
if (pattern !== undefined) {
|
|
1062
|
-
sql += patternStub(hasWhere, undefined, "l.lanname");
|
|
1063
|
-
hasWhere = true;
|
|
1064
|
-
}
|
|
1065
|
-
if (!showSystem && pattern === undefined) {
|
|
1066
|
-
sql += "WHERE l.lanplcallfoid != 0\n";
|
|
1067
|
-
hasWhere = true;
|
|
1068
|
-
}
|
|
1069
|
-
sql += orderBy("1");
|
|
1070
|
-
return { sql, params: params(), description: "List of languages" };
|
|
1071
|
-
};
|
|
1072
|
-
/* ------------------------------------------------------------------ */
|
|
1073
|
-
/* \dD — listDomains */
|
|
1074
|
-
/* ------------------------------------------------------------------ */
|
|
1075
|
-
export const listDomains = (opts) => {
|
|
1076
|
-
const { verbose, showSystem, pattern } = opts;
|
|
1077
|
-
let sql = 'SELECT n.nspname as "Schema",\n' +
|
|
1078
|
-
' t.typname as "Name",\n' +
|
|
1079
|
-
' pg_catalog.format_type(t.typbasetype, t.typtypmod) as "Type",\n' +
|
|
1080
|
-
" (SELECT c.collname FROM pg_catalog.pg_collation c, pg_catalog.pg_type bt\n" +
|
|
1081
|
-
' WHERE c.oid = t.typcollation AND bt.oid = t.typbasetype AND t.typcollation <> bt.typcollation) as "Collation",\n' +
|
|
1082
|
-
" CASE WHEN t.typnotnull THEN 'not null' END as \"Nullable\",\n" +
|
|
1083
|
-
' t.typdefault as "Default",\n' +
|
|
1084
|
-
" pg_catalog.array_to_string(ARRAY(\n SELECT pg_catalog.pg_get_constraintdef(r.oid, true) FROM pg_catalog.pg_constraint r WHERE t.oid = r.contypid AND r.contype = 'c' ORDER BY r.conname\n ), ' ') as \"Check\"";
|
|
1085
|
-
if (verbose) {
|
|
1086
|
-
sql += ",\n " + aclColumn("t.typacl");
|
|
1087
|
-
sql += ',\n d.description as "Description"';
|
|
1088
|
-
}
|
|
1089
|
-
sql +=
|
|
1090
|
-
"\nFROM pg_catalog.pg_type t\n" +
|
|
1091
|
-
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n";
|
|
1092
|
-
if (verbose) {
|
|
1093
|
-
sql +=
|
|
1094
|
-
" LEFT JOIN pg_catalog.pg_description d ON d.classoid = t.tableoid AND d.objoid = t.oid AND d.objsubid = 0\n";
|
|
1095
|
-
}
|
|
1096
|
-
sql += "WHERE t.typtype = 'd'\n";
|
|
1097
|
-
if (!showSystem && pattern === undefined) {
|
|
1098
|
-
sql +=
|
|
1099
|
-
" AND n.nspname <> 'pg_catalog'\n AND n.nspname <> 'information_schema'\n";
|
|
1100
|
-
}
|
|
1101
|
-
sql += patternStub(true, "n.nspname", "t.typname");
|
|
1102
|
-
sql += orderBy("1, 2");
|
|
1103
|
-
return { sql, params: params(), description: "List of domains" };
|
|
1104
|
-
};
|
|
1105
|
-
/* ------------------------------------------------------------------ */
|
|
1106
|
-
/* \dc — listConversions */
|
|
1107
|
-
/* ------------------------------------------------------------------ */
|
|
1108
|
-
export const listConversions = (opts) => {
|
|
1109
|
-
const { verbose, showSystem, pattern } = opts;
|
|
1110
|
-
let sql = 'SELECT n.nspname AS "Schema",\n' +
|
|
1111
|
-
' c.conname AS "Name",\n' +
|
|
1112
|
-
' pg_catalog.pg_encoding_to_char(c.conforencoding) AS "Source",\n' +
|
|
1113
|
-
' pg_catalog.pg_encoding_to_char(c.contoencoding) AS "Destination",\n' +
|
|
1114
|
-
" CASE WHEN c.condefault THEN 'yes' ELSE 'no' END AS \"Default?\"";
|
|
1115
|
-
if (verbose)
|
|
1116
|
-
sql += ',\n d.description AS "Description"';
|
|
1117
|
-
sql +=
|
|
1118
|
-
"\nFROM pg_catalog.pg_conversion c\n" +
|
|
1119
|
-
" JOIN pg_catalog.pg_namespace n ON n.oid = c.connamespace\n";
|
|
1120
|
-
if (verbose) {
|
|
1121
|
-
sql +=
|
|
1122
|
-
"LEFT JOIN pg_catalog.pg_description d ON d.classoid = c.tableoid AND d.objoid = c.oid AND d.objsubid = 0\n";
|
|
1123
|
-
}
|
|
1124
|
-
sql += "WHERE true\n";
|
|
1125
|
-
if (!showSystem && pattern === undefined) {
|
|
1126
|
-
sql +=
|
|
1127
|
-
" AND n.nspname <> 'pg_catalog'\n AND n.nspname <> 'information_schema'\n";
|
|
1128
|
-
}
|
|
1129
|
-
sql += patternStub(true, "n.nspname", "c.conname");
|
|
1130
|
-
sql += orderBy("1, 2");
|
|
1131
|
-
return { sql, params: params(), description: "List of conversions" };
|
|
1132
|
-
};
|
|
1133
|
-
/* ------------------------------------------------------------------ */
|
|
1134
|
-
/* \dconfig — describeConfigurationParameters */
|
|
1135
|
-
/* ------------------------------------------------------------------ */
|
|
1136
|
-
export const describeConfigurationParameters = (opts) => {
|
|
1137
|
-
const { verbose, pattern, serverVersion } = opts;
|
|
1138
|
-
let sql = 'SELECT s.name AS "Parameter", pg_catalog.current_setting(s.name) AS "Value"';
|
|
1139
|
-
if (verbose) {
|
|
1140
|
-
sql += ', s.vartype AS "Type", s.context AS "Context", ';
|
|
1141
|
-
if (serverAtLeast(serverVersion, PG_15)) {
|
|
1142
|
-
sql += aclColumn("p.paracl");
|
|
1143
|
-
}
|
|
1144
|
-
else {
|
|
1145
|
-
sql += 'NULL AS "Access privileges"';
|
|
1146
|
-
}
|
|
1147
|
-
}
|
|
1148
|
-
sql += "\nFROM pg_catalog.pg_settings s\n";
|
|
1149
|
-
if (verbose && serverAtLeast(serverVersion, PG_15)) {
|
|
1150
|
-
sql +=
|
|
1151
|
-
" LEFT JOIN pg_catalog.pg_parameter_acl p ON pg_catalog.lower(s.name) = p.parname\n";
|
|
1152
|
-
}
|
|
1153
|
-
if (pattern !== undefined) {
|
|
1154
|
-
sql += patternStub(false, undefined, "pg_catalog.lower(s.name)");
|
|
1155
|
-
}
|
|
1156
|
-
else {
|
|
1157
|
-
sql +=
|
|
1158
|
-
"WHERE s.source <> 'default' AND s.setting IS DISTINCT FROM s.boot_val\n";
|
|
1159
|
-
}
|
|
1160
|
-
sql += orderBy("1");
|
|
1161
|
-
return {
|
|
1162
|
-
sql,
|
|
1163
|
-
params: params(),
|
|
1164
|
-
description: pattern !== undefined
|
|
1165
|
-
? "List of configuration parameters"
|
|
1166
|
-
: "List of non-default configuration parameters",
|
|
1167
|
-
};
|
|
1168
|
-
};
|
|
1169
|
-
/* ------------------------------------------------------------------ */
|
|
1170
|
-
/* \dy — listEventTriggers */
|
|
1171
|
-
/* ------------------------------------------------------------------ */
|
|
1172
|
-
export const listEventTriggers = (opts) => {
|
|
1173
|
-
const { verbose } = opts;
|
|
1174
|
-
let sql = 'SELECT evtname as "Name", evtevent as "Event", pg_catalog.pg_get_userbyid(e.evtowner) as "Owner",\n' +
|
|
1175
|
-
" case evtenabled when 'O' then 'enabled' when 'R' then 'replica' when 'A' then 'always' when 'D' then 'disabled' end as \"Enabled\",\n" +
|
|
1176
|
-
' e.evtfoid::pg_catalog.regproc as "Function", ' +
|
|
1177
|
-
"pg_catalog.array_to_string(array(select x from pg_catalog.unnest(evttags) as t(x)), ', ') as \"Tags\"";
|
|
1178
|
-
if (verbose) {
|
|
1179
|
-
sql +=
|
|
1180
|
-
",\npg_catalog.obj_description(e.oid, 'pg_event_trigger') as \"Description\"";
|
|
1181
|
-
}
|
|
1182
|
-
sql += "\nFROM pg_catalog.pg_event_trigger e\n";
|
|
1183
|
-
sql += patternStub(false, undefined, "evtname");
|
|
1184
|
-
sql += orderBy("1");
|
|
1185
|
-
return { sql, params: params(), description: "List of event triggers" };
|
|
1186
|
-
};
|
|
1187
|
-
/* ------------------------------------------------------------------ */
|
|
1188
|
-
/* \dX — listExtendedStats */
|
|
1189
|
-
/* ------------------------------------------------------------------ */
|
|
1190
|
-
export const listExtendedStats = (opts) => {
|
|
1191
|
-
const { verbose, serverVersion } = opts;
|
|
1192
|
-
if (serverLess(serverVersion, PG_10)) {
|
|
1193
|
-
return {
|
|
1194
|
-
sql: "/* server < 10 does not support extended statistics */ SELECT 1 WHERE false;",
|
|
1195
|
-
params: [],
|
|
1196
|
-
description: "List of extended statistics",
|
|
1197
|
-
};
|
|
1198
|
-
}
|
|
1199
|
-
let sql = "SELECT\n" +
|
|
1200
|
-
'es.stxnamespace::pg_catalog.regnamespace::pg_catalog.text AS "Schema",\n' +
|
|
1201
|
-
'es.stxname AS "Name",\n';
|
|
1202
|
-
if (serverAtLeast(serverVersion, PG_14)) {
|
|
1203
|
-
sql +=
|
|
1204
|
-
"pg_catalog.format('%s FROM %s', pg_catalog.pg_get_statisticsobjdef_columns(es.oid), es.stxrelid::pg_catalog.regclass) AS \"Definition\"";
|
|
1205
|
-
}
|
|
1206
|
-
else {
|
|
1207
|
-
sql +=
|
|
1208
|
-
"pg_catalog.format('%s FROM %s',\n" +
|
|
1209
|
-
" (SELECT pg_catalog.string_agg(pg_catalog.quote_ident(a.attname),', ')\n" +
|
|
1210
|
-
" FROM pg_catalog.unnest(es.stxkeys) s(attnum)\n" +
|
|
1211
|
-
" JOIN pg_catalog.pg_attribute a\n" +
|
|
1212
|
-
" ON (es.stxrelid = a.attrelid AND a.attnum = s.attnum AND NOT a.attisdropped)),\n" +
|
|
1213
|
-
'es.stxrelid::pg_catalog.regclass) AS "Definition"';
|
|
1214
|
-
}
|
|
1215
|
-
sql +=
|
|
1216
|
-
",\nCASE WHEN 'd' = any(es.stxkind) THEN 'defined' END AS \"Ndistinct\",\n" +
|
|
1217
|
-
"CASE WHEN 'f' = any(es.stxkind) THEN 'defined' END AS \"Dependencies\"";
|
|
1218
|
-
if (serverAtLeast(serverVersion, PG_12)) {
|
|
1219
|
-
sql +=
|
|
1220
|
-
",\nCASE WHEN 'm' = any(es.stxkind) THEN 'defined' END AS \"MCV\"";
|
|
1221
|
-
}
|
|
1222
|
-
if (verbose) {
|
|
1223
|
-
sql +=
|
|
1224
|
-
", \npg_catalog.obj_description(oid, 'pg_statistic_ext') AS \"Description\"";
|
|
1225
|
-
}
|
|
1226
|
-
sql += "\nFROM pg_catalog.pg_statistic_ext es\n";
|
|
1227
|
-
sql += patternStub(false, "es.stxnamespace::pg_catalog.regnamespace::pg_catalog.text", "es.stxname");
|
|
1228
|
-
sql += orderBy("1, 2");
|
|
1229
|
-
return {
|
|
1230
|
-
sql,
|
|
1231
|
-
params: params(),
|
|
1232
|
-
description: "List of extended statistics",
|
|
1233
|
-
};
|
|
1234
|
-
};
|
|
1235
|
-
/* ------------------------------------------------------------------ */
|
|
1236
|
-
/* \dC — listCasts */
|
|
1237
|
-
/* ------------------------------------------------------------------ */
|
|
1238
|
-
export const listCasts = (opts) => {
|
|
1239
|
-
const { verbose, serverVersion } = opts;
|
|
1240
|
-
let sql = 'SELECT pg_catalog.format_type(castsource, NULL) AS "Source type",\n' +
|
|
1241
|
-
' pg_catalog.format_type(casttarget, NULL) AS "Target type",\n' +
|
|
1242
|
-
" CASE WHEN c.castmethod = 'b' THEN '(binary coercible)'\n" +
|
|
1243
|
-
" WHEN c.castmethod = 'i' THEN '(with inout)'\n" +
|
|
1244
|
-
" ELSE p.proname\n" +
|
|
1245
|
-
' END AS "Function",\n' +
|
|
1246
|
-
" CASE WHEN c.castcontext = 'e' THEN 'no'\n" +
|
|
1247
|
-
" WHEN c.castcontext = 'a' THEN 'in assignment'\n" +
|
|
1248
|
-
" ELSE 'yes'\n" +
|
|
1249
|
-
' END AS "Implicit?"';
|
|
1250
|
-
if (verbose) {
|
|
1251
|
-
// PG 18 added "Leakproof?" to verbose `\dC+`. The pg_proc join
|
|
1252
|
-
// already exists for the Function column, so emitting the cast's
|
|
1253
|
-
// function's `proleakproof` is incremental.
|
|
1254
|
-
if (serverAtLeast(serverVersion, PG_18)) {
|
|
1255
|
-
sql +=
|
|
1256
|
-
",\n CASE WHEN p.proleakproof THEN 'yes' ELSE 'no' END AS \"Leakproof?\"";
|
|
1257
|
-
}
|
|
1258
|
-
sql += ',\n d.description AS "Description"';
|
|
1259
|
-
}
|
|
1260
|
-
sql +=
|
|
1261
|
-
"\nFROM pg_catalog.pg_cast c LEFT JOIN pg_catalog.pg_proc p\n" +
|
|
1262
|
-
" ON c.castfunc = p.oid\n" +
|
|
1263
|
-
" LEFT JOIN pg_catalog.pg_type ts ON c.castsource = ts.oid\n" +
|
|
1264
|
-
" LEFT JOIN pg_catalog.pg_namespace ns ON ns.oid = ts.typnamespace\n" +
|
|
1265
|
-
" LEFT JOIN pg_catalog.pg_type tt ON c.casttarget = tt.oid\n" +
|
|
1266
|
-
" LEFT JOIN pg_catalog.pg_namespace nt ON nt.oid = tt.typnamespace\n";
|
|
1267
|
-
if (verbose) {
|
|
1268
|
-
sql +=
|
|
1269
|
-
" LEFT JOIN pg_catalog.pg_description d ON d.classoid = c.tableoid AND d.objoid = c.oid AND d.objsubid = 0\n";
|
|
1270
|
-
}
|
|
1271
|
-
sql += "WHERE ( (true";
|
|
1272
|
-
sql += patternStub(true, "ns.nspname", "ts.typname");
|
|
1273
|
-
sql += ") OR (true";
|
|
1274
|
-
sql += patternStub(true, "nt.nspname", "tt.typname");
|
|
1275
|
-
sql += ") )\n";
|
|
1276
|
-
sql += orderBy("1, 2");
|
|
1277
|
-
return { sql, params: params(), description: "List of casts" };
|
|
1278
|
-
};
|
|
1279
|
-
/* ------------------------------------------------------------------ */
|
|
1280
|
-
/* \dO — listCollations */
|
|
1281
|
-
/* ------------------------------------------------------------------ */
|
|
1282
|
-
export const listCollations = (opts) => {
|
|
1283
|
-
const { verbose, showSystem, pattern, serverVersion } = opts;
|
|
1284
|
-
let sql = 'SELECT\n n.nspname AS "Schema",\n c.collname AS "Name",\n';
|
|
1285
|
-
if (serverAtLeast(serverVersion, PG_10)) {
|
|
1286
|
-
sql +=
|
|
1287
|
-
" CASE c.collprovider" +
|
|
1288
|
-
" WHEN 'd' THEN 'default'" +
|
|
1289
|
-
" WHEN 'b' THEN 'builtin'" +
|
|
1290
|
-
" WHEN 'c' THEN 'libc'" +
|
|
1291
|
-
" WHEN 'i' THEN 'icu'" +
|
|
1292
|
-
' END AS "Provider",\n';
|
|
1293
|
-
}
|
|
1294
|
-
else {
|
|
1295
|
-
sql += " 'libc' AS \"Provider\",\n";
|
|
1296
|
-
}
|
|
1297
|
-
sql += ' c.collcollate AS "Collate",\n c.collctype AS "Ctype",\n';
|
|
1298
|
-
if (serverAtLeast(serverVersion, PG_17)) {
|
|
1299
|
-
sql += ' c.colllocale AS "Locale",\n';
|
|
1300
|
-
}
|
|
1301
|
-
else if (serverAtLeast(serverVersion, PG_15)) {
|
|
1302
|
-
sql += ' c.colliculocale AS "Locale",\n';
|
|
1303
|
-
}
|
|
1304
|
-
else {
|
|
1305
|
-
sql += ' c.collcollate AS "Locale",\n';
|
|
1306
|
-
}
|
|
1307
|
-
if (serverAtLeast(serverVersion, PG_16)) {
|
|
1308
|
-
sql += ' c.collicurules AS "ICU Rules",\n';
|
|
1309
|
-
}
|
|
1310
|
-
else {
|
|
1311
|
-
sql += ' NULL AS "ICU Rules",\n';
|
|
1312
|
-
}
|
|
1313
|
-
if (serverAtLeast(serverVersion, PG_12)) {
|
|
1314
|
-
sql +=
|
|
1315
|
-
" CASE WHEN c.collisdeterministic THEN 'yes' ELSE 'no' END AS \"Deterministic?\"";
|
|
1316
|
-
}
|
|
1317
|
-
else {
|
|
1318
|
-
sql += " 'yes' AS \"Deterministic?\"";
|
|
1319
|
-
}
|
|
1320
|
-
if (verbose) {
|
|
1321
|
-
sql +=
|
|
1322
|
-
",\n pg_catalog.obj_description(c.oid, 'pg_collation') AS \"Description\"";
|
|
1323
|
-
}
|
|
1324
|
-
sql +=
|
|
1325
|
-
"\nFROM pg_catalog.pg_collation c, pg_catalog.pg_namespace n\n" +
|
|
1326
|
-
"WHERE n.oid = c.collnamespace\n";
|
|
1327
|
-
if (!showSystem && pattern === undefined) {
|
|
1328
|
-
sql +=
|
|
1329
|
-
" AND n.nspname <> 'pg_catalog'\n AND n.nspname <> 'information_schema'\n";
|
|
1330
|
-
}
|
|
1331
|
-
sql +=
|
|
1332
|
-
" AND c.collencoding IN (-1, pg_catalog.pg_char_to_encoding(pg_catalog.getdatabaseencoding()))\n";
|
|
1333
|
-
sql += patternStub(true, "n.nspname", "c.collname");
|
|
1334
|
-
sql += orderBy("1, 2");
|
|
1335
|
-
return { sql, params: params(), description: "List of collations" };
|
|
1336
|
-
};
|
|
1337
|
-
/* ------------------------------------------------------------------ */
|
|
1338
|
-
/* \dn — listSchemas */
|
|
1339
|
-
/* ------------------------------------------------------------------ */
|
|
1340
|
-
export const listSchemas = (opts) => {
|
|
1341
|
-
const { verbose, showSystem, pattern } = opts;
|
|
1342
|
-
let sql = 'SELECT n.nspname AS "Name",\n' +
|
|
1343
|
-
' pg_catalog.pg_get_userbyid(n.nspowner) AS "Owner"';
|
|
1344
|
-
if (verbose) {
|
|
1345
|
-
sql += ",\n " + aclColumn("n.nspacl");
|
|
1346
|
-
sql +=
|
|
1347
|
-
",\n pg_catalog.obj_description(n.oid, 'pg_namespace') AS \"Description\"";
|
|
1348
|
-
}
|
|
1349
|
-
sql += "\nFROM pg_catalog.pg_namespace n\n";
|
|
1350
|
-
if (!showSystem && pattern === undefined) {
|
|
1351
|
-
sql +=
|
|
1352
|
-
"WHERE n.nspname !~ '^pg_' AND n.nspname <> 'information_schema'\n";
|
|
1353
|
-
}
|
|
1354
|
-
sql += patternStub(!showSystem && pattern === undefined, undefined, "n.nspname");
|
|
1355
|
-
sql += orderBy("1");
|
|
1356
|
-
return { sql, params: params(), description: "List of schemas" };
|
|
1357
|
-
};
|
|
1358
|
-
/* ------------------------------------------------------------------ */
|
|
1359
|
-
/* \dFp — listTSParsers */
|
|
1360
|
-
/* ------------------------------------------------------------------ */
|
|
1361
|
-
export const listTSParsers = (opts) => {
|
|
1362
|
-
const { verbose } = opts;
|
|
1363
|
-
if (verbose) {
|
|
1364
|
-
// Verbose form: fetch (oid, schema, name) so the renderer can issue
|
|
1365
|
-
// per-parser detail queries (see describeOneTSParser below). WP-20 will
|
|
1366
|
-
// wire the iteration.
|
|
1367
|
-
let sql = "SELECT p.oid,\n n.nspname,\n p.prsname\n" +
|
|
1368
|
-
"FROM pg_catalog.pg_ts_parser p\n" +
|
|
1369
|
-
"LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace\n";
|
|
1370
|
-
sql += patternStub(false, "n.nspname", "p.prsname");
|
|
1371
|
-
sql += orderBy("1, 2");
|
|
1372
|
-
return {
|
|
1373
|
-
sql,
|
|
1374
|
-
params: params(),
|
|
1375
|
-
description: "List of text search parsers (verbose)",
|
|
1376
|
-
};
|
|
1377
|
-
}
|
|
1378
|
-
let sql = 'SELECT\n n.nspname as "Schema",\n p.prsname as "Name",\n' +
|
|
1379
|
-
" pg_catalog.obj_description(p.oid, 'pg_ts_parser') as \"Description\"\n" +
|
|
1380
|
-
"FROM pg_catalog.pg_ts_parser p\n" +
|
|
1381
|
-
"LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace\n";
|
|
1382
|
-
sql += patternStub(false, "n.nspname", "p.prsname");
|
|
1383
|
-
sql += orderBy("1, 2");
|
|
1384
|
-
return {
|
|
1385
|
-
sql,
|
|
1386
|
-
params: params(),
|
|
1387
|
-
description: "List of text search parsers",
|
|
1388
|
-
};
|
|
31
|
+
const describeAggregates = (opts) => {
|
|
32
|
+
const { showSystem, pattern, serverVersion } = opts;
|
|
33
|
+
let sql = "";
|
|
34
|
+
sql += "SELECT n.nspname as \"Schema\",\n p.proname AS \"Name\",\n pg_catalog.format_type(p.prorettype, NULL) AS \"Result data type\",\n CASE WHEN p.pronargs = 0\n THEN CAST('*' AS pg_catalog.text)\n ELSE pg_catalog.pg_get_function_arguments(p.oid)\n END AS \"Argument data types\",\n pg_catalog.obj_description(p.oid, 'pg_proc') as \"Description\"\nFROM pg_catalog.pg_proc p\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n";
|
|
35
|
+
sql += serverAtLeast(serverVersion, 11e4) ? "WHERE p.prokind = 'a'\n" : "WHERE p.proisagg\n";
|
|
36
|
+
if (!showSystem && pattern === void 0) sql += " AND n.nspname <> 'pg_catalog'\n AND n.nspname <> 'information_schema'\n";
|
|
37
|
+
sql += patternStub(true, "n.nspname", "p.proname");
|
|
38
|
+
sql += orderBy("1, 2, 4");
|
|
39
|
+
return {
|
|
40
|
+
sql,
|
|
41
|
+
params: params(),
|
|
42
|
+
description: "List of aggregate functions"
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
const describeAccessMethods = (opts) => {
|
|
46
|
+
const { verbose, serverVersion } = opts;
|
|
47
|
+
if (serverLess(serverVersion, 9, 6)) return {
|
|
48
|
+
sql: "/* server < 9.6 does not support access methods */ SELECT 1 WHERE false;",
|
|
49
|
+
params: [],
|
|
50
|
+
description: "List of access methods"
|
|
51
|
+
};
|
|
52
|
+
let sql = "SELECT amname AS \"Name\",\n CASE amtype WHEN 'i' THEN 'Index' WHEN 't' THEN 'Table' END AS \"Type\"";
|
|
53
|
+
if (verbose) sql += ",\n amhandler AS \"Handler\",\n pg_catalog.obj_description(oid, 'pg_am') AS \"Description\"";
|
|
54
|
+
sql += "\nFROM pg_catalog.pg_am\n";
|
|
55
|
+
sql += patternStub(false, void 0, "amname");
|
|
56
|
+
sql += orderBy("1");
|
|
57
|
+
return {
|
|
58
|
+
sql,
|
|
59
|
+
params: params(),
|
|
60
|
+
description: "List of access methods"
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
const describeTablespaces = (opts) => {
|
|
64
|
+
const { verbose } = opts;
|
|
65
|
+
let sql = "SELECT spcname AS \"Name\",\n pg_catalog.pg_get_userbyid(spcowner) AS \"Owner\",\n pg_catalog.pg_tablespace_location(oid) AS \"Location\"";
|
|
66
|
+
if (verbose) {
|
|
67
|
+
sql += ",\n " + aclColumn("spcacl");
|
|
68
|
+
sql += ",\n spcoptions AS \"Options\",\n pg_catalog.pg_size_pretty(pg_catalog.pg_tablespace_size(oid)) AS \"Size\",\n pg_catalog.shobj_description(oid, 'pg_tablespace') AS \"Description\"";
|
|
69
|
+
}
|
|
70
|
+
sql += "\nFROM pg_catalog.pg_tablespace\n";
|
|
71
|
+
sql += patternStub(false, void 0, "spcname");
|
|
72
|
+
sql += orderBy("1");
|
|
73
|
+
return {
|
|
74
|
+
sql,
|
|
75
|
+
params: params(),
|
|
76
|
+
description: "List of tablespaces"
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
const describeFunctions = (opts) => {
|
|
80
|
+
const { verbose, showSystem, pattern, serverVersion } = opts;
|
|
81
|
+
const functypes = opts.functypes ?? "";
|
|
82
|
+
const argPatterns = opts.argPatterns ?? [];
|
|
83
|
+
let showAgg = functypes.includes("a");
|
|
84
|
+
let showNorm = functypes.includes("n");
|
|
85
|
+
let showProc = functypes.includes("p");
|
|
86
|
+
let showTrig = functypes.includes("t");
|
|
87
|
+
let showWin = functypes.includes("w");
|
|
88
|
+
if (!showAgg && !showNorm && !showProc && !showTrig && !showWin) {
|
|
89
|
+
showAgg = showNorm = showTrig = showWin = true;
|
|
90
|
+
if (serverAtLeast(serverVersion, 11e4)) showProc = true;
|
|
91
|
+
}
|
|
92
|
+
let sql = "SELECT n.nspname as \"Schema\",\n p.proname as \"Name\",\n";
|
|
93
|
+
if (serverAtLeast(serverVersion, 11e4)) sql += " pg_catalog.pg_get_function_result(p.oid) as \"Result data type\",\n pg_catalog.pg_get_function_arguments(p.oid) as \"Argument data types\",\n CASE p.prokind\n WHEN 'a' THEN 'agg'\n WHEN 'w' THEN 'window'\n WHEN 'p' THEN 'proc'\n ELSE 'func'\n END as \"Type\"";
|
|
94
|
+
else sql += " pg_catalog.pg_get_function_result(p.oid) as \"Result data type\",\n pg_catalog.pg_get_function_arguments(p.oid) as \"Argument data types\",\n CASE\n WHEN p.proisagg THEN 'agg'\n WHEN p.proiswindow THEN 'window'\n WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN 'trigger'\n ELSE 'func'\n END as \"Type\"";
|
|
95
|
+
if (verbose) {
|
|
96
|
+
sql += ",\n CASE\n WHEN p.provolatile = 'i' THEN 'immutable'\n WHEN p.provolatile = 's' THEN 'stable'\n WHEN p.provolatile = 'v' THEN 'volatile'\n END as \"Volatility\"";
|
|
97
|
+
if (serverAtLeast(serverVersion, 90600)) sql += ",\n CASE\n WHEN p.proparallel = 'r' THEN 'restricted'\n WHEN p.proparallel = 's' THEN 'safe'\n WHEN p.proparallel = 'u' THEN 'unsafe'\n END as \"Parallel\"";
|
|
98
|
+
sql += ",\n pg_catalog.pg_get_userbyid(p.proowner) as \"Owner\",\n CASE WHEN prosecdef THEN 'definer' ELSE 'invoker' END AS \"Security\"";
|
|
99
|
+
if (serverAtLeast(serverVersion, 18e4)) sql += ",\n CASE WHEN p.proleakproof THEN 'yes' ELSE 'no' END as \"Leakproof?\"";
|
|
100
|
+
sql += ",\n " + aclColumn("p.proacl");
|
|
101
|
+
sql += ",\n l.lanname as \"Language\",\n CASE WHEN l.lanname IN ('internal', 'c') THEN p.prosrc END as \"Internal name\",\n pg_catalog.obj_description(p.oid, 'pg_proc') as \"Description\"";
|
|
102
|
+
}
|
|
103
|
+
sql += "\nFROM pg_catalog.pg_proc p\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n";
|
|
104
|
+
for (let i = 0; i < argPatterns.length; i++) sql += ` LEFT JOIN pg_catalog.pg_type t${i} ON t${i}.oid = p.proargtypes[${i}]\n LEFT JOIN pg_catalog.pg_namespace nt${i} ON nt${i}.oid = t${i}.typnamespace\n`;
|
|
105
|
+
if (verbose) sql += " LEFT JOIN pg_catalog.pg_language l ON l.oid = p.prolang\n";
|
|
106
|
+
let hasWhere = false;
|
|
107
|
+
const allTypes = showAgg && showNorm && showProc && showTrig && showWin;
|
|
108
|
+
if (!allTypes && showNorm) {
|
|
109
|
+
if (!showAgg) {
|
|
110
|
+
sql += hasWhere ? " AND " : "WHERE ";
|
|
111
|
+
hasWhere = true;
|
|
112
|
+
sql += serverAtLeast(serverVersion, 11e4) ? "p.prokind <> 'a'\n" : "NOT p.proisagg\n";
|
|
113
|
+
}
|
|
114
|
+
if (!showProc && serverAtLeast(serverVersion, 11e4)) {
|
|
115
|
+
sql += hasWhere ? " AND " : "WHERE ";
|
|
116
|
+
hasWhere = true;
|
|
117
|
+
sql += "p.prokind <> 'p'\n";
|
|
118
|
+
}
|
|
119
|
+
if (!showTrig) {
|
|
120
|
+
sql += hasWhere ? " AND " : "WHERE ";
|
|
121
|
+
hasWhere = true;
|
|
122
|
+
sql += "p.prorettype <> 'pg_catalog.trigger'::pg_catalog.regtype\n";
|
|
123
|
+
}
|
|
124
|
+
if (!showWin) {
|
|
125
|
+
sql += hasWhere ? " AND " : "WHERE ";
|
|
126
|
+
hasWhere = true;
|
|
127
|
+
sql += serverAtLeast(serverVersion, 11e4) ? "p.prokind <> 'w'\n" : "NOT p.proiswindow\n";
|
|
128
|
+
}
|
|
129
|
+
} else if (!allTypes) {
|
|
130
|
+
sql += "WHERE (\n ";
|
|
131
|
+
hasWhere = true;
|
|
132
|
+
const parts = [];
|
|
133
|
+
if (showAgg) parts.push(serverAtLeast(serverVersion, 11e4) ? "p.prokind = 'a'" : "p.proisagg");
|
|
134
|
+
if (showTrig) parts.push("p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype");
|
|
135
|
+
if (showProc) parts.push("p.prokind = 'p'");
|
|
136
|
+
if (showWin) parts.push(serverAtLeast(serverVersion, 11e4) ? "p.prokind = 'w'" : "p.proiswindow");
|
|
137
|
+
sql += parts.join("\n OR ") + "\n )\n";
|
|
138
|
+
}
|
|
139
|
+
sql += patternStub(hasWhere, "n.nspname", "p.proname");
|
|
140
|
+
for (let i = 0; i < argPatterns.length; i++) if (argPatterns[i] === "-") sql += ` AND t${i}.typname IS NULL\n`;
|
|
141
|
+
else sql += ` AND ${argPatternStub(i)}\n`;
|
|
142
|
+
if (!showSystem && pattern === void 0) sql += " AND n.nspname <> 'pg_catalog'\n AND n.nspname <> 'information_schema'\n";
|
|
143
|
+
sql += orderBy("1, 2, 4");
|
|
144
|
+
return {
|
|
145
|
+
sql,
|
|
146
|
+
params: params(),
|
|
147
|
+
description: "List of functions"
|
|
148
|
+
};
|
|
149
|
+
};
|
|
150
|
+
const describeTypes = (opts) => {
|
|
151
|
+
const { verbose, showSystem, pattern } = opts;
|
|
152
|
+
let sql = "SELECT n.nspname as \"Schema\",\n pg_catalog.format_type(t.oid, NULL) AS \"Name\",\n";
|
|
153
|
+
if (verbose) sql += " t.typname AS \"Internal name\",\n CASE WHEN t.typrelid != 0\n THEN CAST('tuple' AS pg_catalog.text)\n WHEN t.typlen < 0\n THEN CAST('var' AS pg_catalog.text)\n ELSE CAST(t.typlen AS pg_catalog.text)\n END AS \"Size\",\n pg_catalog.array_to_string(\n ARRAY(\n SELECT e.enumlabel\n FROM pg_catalog.pg_enum e\n WHERE e.enumtypid = t.oid\n ORDER BY e.enumsortorder\n ),\n E'\\n'\n ) AS \"Elements\",\n pg_catalog.pg_get_userbyid(t.typowner) AS \"Owner\",\n " + aclColumn("t.typacl") + ",\n ";
|
|
154
|
+
sql += " pg_catalog.obj_description(t.oid, 'pg_type') as \"Description\"\n";
|
|
155
|
+
sql += "FROM pg_catalog.pg_type t\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n";
|
|
156
|
+
sql += "WHERE (t.typrelid = 0 ";
|
|
157
|
+
sql += "OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid))\n";
|
|
158
|
+
if (!pattern?.includes("[]")) sql += " AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid)\n";
|
|
159
|
+
if (!showSystem && pattern === void 0) sql += " AND n.nspname <> 'pg_catalog'\n AND n.nspname <> 'information_schema'\n";
|
|
160
|
+
sql += patternStub(true, "n.nspname", "t.typname");
|
|
161
|
+
sql += orderBy("1, 2");
|
|
162
|
+
return {
|
|
163
|
+
sql,
|
|
164
|
+
params: params(),
|
|
165
|
+
description: "List of data types"
|
|
166
|
+
};
|
|
167
|
+
};
|
|
168
|
+
const describeOperators = (opts) => {
|
|
169
|
+
const { verbose, showSystem, pattern, serverVersion } = opts;
|
|
170
|
+
let argPatterns = opts.argPatterns ?? [];
|
|
171
|
+
if (argPatterns.length > 2) argPatterns = argPatterns.slice(0, 2);
|
|
172
|
+
let sql = "SELECT n.nspname as \"Schema\",\n o.oprname AS \"Name\",\n CASE WHEN o.oprkind='l' THEN NULL ELSE pg_catalog.format_type(o.oprleft, NULL) END AS \"Left arg type\",\n CASE WHEN o.oprkind='r' THEN NULL ELSE pg_catalog.format_type(o.oprright, NULL) END AS \"Right arg type\",\n pg_catalog.format_type(o.oprresult, NULL) AS \"Result type\",\n";
|
|
173
|
+
if (verbose) {
|
|
174
|
+
sql += " o.oprcode AS \"Function\",\n";
|
|
175
|
+
if (serverAtLeast(serverVersion, 18e4)) sql += " CASE WHEN p.proleakproof THEN 'yes' ELSE 'no' END AS \"Leakproof?\",\n";
|
|
176
|
+
}
|
|
177
|
+
sql += " coalesce(pg_catalog.obj_description(o.oid, 'pg_operator'),\n pg_catalog.obj_description(o.oprcode, 'pg_proc')) AS \"Description\"\nFROM pg_catalog.pg_operator o\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n";
|
|
178
|
+
if (argPatterns.length === 1) sql += " LEFT JOIN pg_catalog.pg_type t0 ON t0.oid = o.oprright\n LEFT JOIN pg_catalog.pg_namespace nt0 ON nt0.oid = t0.typnamespace\n";
|
|
179
|
+
else if (argPatterns.length >= 2) sql += " LEFT JOIN pg_catalog.pg_type t0 ON t0.oid = o.oprleft\n LEFT JOIN pg_catalog.pg_namespace nt0 ON nt0.oid = t0.typnamespace\n LEFT JOIN pg_catalog.pg_type t1 ON t1.oid = o.oprright\n LEFT JOIN pg_catalog.pg_namespace nt1 ON nt1.oid = t1.typnamespace\n";
|
|
180
|
+
if (verbose && serverAtLeast(serverVersion, 18e4)) sql += " LEFT JOIN pg_catalog.pg_proc p ON p.oid = o.oprcode\n";
|
|
181
|
+
let hasWhere = false;
|
|
182
|
+
if (!showSystem && pattern === void 0) {
|
|
183
|
+
sql += "WHERE n.nspname <> 'pg_catalog'\n AND n.nspname <> 'information_schema'\n";
|
|
184
|
+
hasWhere = true;
|
|
185
|
+
}
|
|
186
|
+
sql += patternStub(hasWhere, "n.nspname", "o.oprname");
|
|
187
|
+
if (argPatterns.length === 1) sql += " AND o.oprleft = 0\n";
|
|
188
|
+
for (let i = 0; i < argPatterns.length; i++) if (argPatterns[i] === "-") sql += ` AND t${i}.typname IS NULL\n`;
|
|
189
|
+
else sql += ` AND ${argPatternStub(i)}\n`;
|
|
190
|
+
sql += orderBy("1, 2, 3, 4");
|
|
191
|
+
return {
|
|
192
|
+
sql,
|
|
193
|
+
params: params(),
|
|
194
|
+
description: "List of operators"
|
|
195
|
+
};
|
|
196
|
+
};
|
|
197
|
+
const listAllDbs = (opts) => {
|
|
198
|
+
const { verbose, serverVersion } = opts;
|
|
199
|
+
let sql = "SELECT\n d.datname as \"Name\",\n pg_catalog.pg_get_userbyid(d.datdba) as \"Owner\",\n pg_catalog.pg_encoding_to_char(d.encoding) as \"Encoding\",\n";
|
|
200
|
+
if (serverAtLeast(serverVersion, 15e4)) sql += " CASE d.datlocprovider WHEN 'b' THEN 'builtin' WHEN 'c' THEN 'libc' WHEN 'i' THEN 'icu' END AS \"Locale Provider\",\n";
|
|
201
|
+
else sql += " 'libc' AS \"Locale Provider\",\n";
|
|
202
|
+
sql += " d.datcollate as \"Collate\",\n d.datctype as \"Ctype\",\n";
|
|
203
|
+
if (serverAtLeast(serverVersion, 17e4)) sql += " d.datlocale as \"Locale\",\n";
|
|
204
|
+
else if (serverAtLeast(serverVersion, 15e4)) sql += " d.daticulocale as \"Locale\",\n";
|
|
205
|
+
else sql += " NULL as \"Locale\",\n";
|
|
206
|
+
if (serverAtLeast(serverVersion, 16e4)) sql += " d.daticurules as \"ICU Rules\",\n";
|
|
207
|
+
else sql += " NULL as \"ICU Rules\",\n";
|
|
208
|
+
sql += " " + aclColumn("d.datacl");
|
|
209
|
+
if (verbose) sql += ",\n CASE WHEN pg_catalog.has_database_privilege(d.datname, 'CONNECT')\n THEN pg_catalog.pg_size_pretty(pg_catalog.pg_database_size(d.datname))\n ELSE 'No Access'\n END as \"Size\",\n t.spcname as \"Tablespace\",\n pg_catalog.shobj_description(d.oid, 'pg_database') as \"Description\"";
|
|
210
|
+
sql += "\nFROM pg_catalog.pg_database d\n";
|
|
211
|
+
if (verbose) sql += " JOIN pg_catalog.pg_tablespace t on d.dattablespace = t.oid\n";
|
|
212
|
+
if (opts.pattern !== void 0) sql += patternStub(false, void 0, "d.datname");
|
|
213
|
+
sql += orderBy("1");
|
|
214
|
+
return {
|
|
215
|
+
sql,
|
|
216
|
+
params: params(),
|
|
217
|
+
description: "List of databases"
|
|
218
|
+
};
|
|
219
|
+
};
|
|
220
|
+
const permissionsList = (opts) => {
|
|
221
|
+
const { showSystem, pattern, serverVersion } = opts;
|
|
222
|
+
let sql = "SELECT n.nspname as \"Schema\",\n c.relname as \"Name\",\n CASE c.relkind WHEN 'r' THEN 'table' WHEN 'v' THEN 'view' WHEN 'm' THEN 'materialized view' WHEN 'S' THEN 'sequence' WHEN 'f' THEN 'foreign table' WHEN 'p' THEN 'partitioned table' END as \"Type\",\n ";
|
|
223
|
+
sql += aclColumn("c.relacl");
|
|
224
|
+
sql += ",\n pg_catalog.array_to_string(ARRAY(\n SELECT attname || E':\\n ' || pg_catalog.array_to_string(attacl, E'\\n ')\n FROM pg_catalog.pg_attribute a\n WHERE attrelid = c.oid AND NOT attisdropped AND attacl IS NOT NULL\n ), E'\\n') AS \"Column privileges\"";
|
|
225
|
+
if (serverAtLeast(serverVersion, 1e5)) sql += ",\n pg_catalog.array_to_string(ARRAY(\n SELECT polname\n || CASE WHEN NOT polpermissive THEN E' (RESTRICTIVE)' ELSE '' END\n || CASE WHEN polcmd != '*' THEN E' (' || polcmd::pg_catalog.text || E'):' ELSE E':' END\n || CASE WHEN polqual IS NOT NULL THEN E'\\n (u): ' || pg_catalog.pg_get_expr(polqual, polrelid) ELSE E'' END\n || CASE WHEN polwithcheck IS NOT NULL THEN E'\\n (c): ' || pg_catalog.pg_get_expr(polwithcheck, polrelid) ELSE E'' END\n || CASE WHEN polroles <> '{0}' THEN E'\\n to: ' || pg_catalog.array_to_string(\n ARRAY(SELECT rolname FROM pg_catalog.pg_roles WHERE oid = ANY (polroles) ORDER BY 1)\n , E', ') ELSE E'' END\n FROM pg_catalog.pg_policy pol\n WHERE polrelid = c.oid), E'\\n') AS \"Policies\"";
|
|
226
|
+
else if (serverAtLeast(serverVersion, 90500)) sql += ",\n pg_catalog.array_to_string(ARRAY(\n SELECT polname\n || CASE WHEN polcmd != '*' THEN E' (' || polcmd::pg_catalog.text || E'):' ELSE E':' END\n || CASE WHEN polqual IS NOT NULL THEN E'\\n (u): ' || pg_catalog.pg_get_expr(polqual, polrelid) ELSE E'' END\n || CASE WHEN polwithcheck IS NOT NULL THEN E'\\n (c): ' || pg_catalog.pg_get_expr(polwithcheck, polrelid) ELSE E'' END\n || CASE WHEN polroles <> '{0}' THEN E'\\n to: ' || pg_catalog.array_to_string(\n ARRAY(SELECT rolname FROM pg_catalog.pg_roles WHERE oid = ANY (polroles) ORDER BY 1)\n , E', ') ELSE E'' END\n FROM pg_catalog.pg_policy pol\n WHERE polrelid = c.oid), E'\\n') AS \"Policies\"";
|
|
227
|
+
sql += "\nFROM pg_catalog.pg_class c\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\nWHERE c.relkind IN ('r','v','m','S','f','p')\n";
|
|
228
|
+
if (!showSystem && pattern === void 0) sql += " AND n.nspname <> 'pg_catalog'\n AND n.nspname <> 'information_schema'\n";
|
|
229
|
+
sql += patternStub(true, "n.nspname", "c.relname");
|
|
230
|
+
sql += orderBy("1, 2");
|
|
231
|
+
return {
|
|
232
|
+
sql,
|
|
233
|
+
params: params(),
|
|
234
|
+
description: "Access privileges"
|
|
235
|
+
};
|
|
236
|
+
};
|
|
237
|
+
const listDefaultACLs = (opts) => {
|
|
238
|
+
const { serverVersion } = opts;
|
|
239
|
+
let sql = "SELECT pg_catalog.pg_get_userbyid(d.defaclrole) AS \"Owner\",\n n.nspname AS \"Schema\",\n CASE d.defaclobjtype WHEN 'r' THEN 'table' WHEN 'S' THEN 'sequence' WHEN 'f' THEN 'function' WHEN 'T' THEN 'type' WHEN 'n' THEN 'schema'";
|
|
240
|
+
if (serverAtLeast(serverVersion, 18e4)) sql += " WHEN 'L' THEN 'large object'";
|
|
241
|
+
sql += " END AS \"Type\",\n ";
|
|
242
|
+
sql += aclColumn("d.defaclacl");
|
|
243
|
+
sql += "\nFROM pg_catalog.pg_default_acl d\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.defaclnamespace\n";
|
|
244
|
+
sql += patternStub(false, "n.nspname", "pg_catalog.pg_get_userbyid(d.defaclrole)");
|
|
245
|
+
sql += orderBy("1, 2, 3");
|
|
246
|
+
return {
|
|
247
|
+
sql,
|
|
248
|
+
params: params(),
|
|
249
|
+
description: "Default access privileges"
|
|
250
|
+
};
|
|
251
|
+
};
|
|
252
|
+
const objectDescription = (opts) => {
|
|
253
|
+
const sysPart = (objLabel) => !opts.showSystem && opts.pattern === void 0 ? `WHERE n.nspname <> 'pg_catalog' AND n.nspname <> 'information_schema' /* ${objLabel} */ ` : `WHERE true /* ${objLabel} */ `;
|
|
254
|
+
let sql = "SELECT DISTINCT tt.nspname AS \"Schema\", tt.name AS \"Name\", tt.object AS \"Object\", d.description AS \"Description\"\nFROM (\n";
|
|
255
|
+
sql += " SELECT pgc.oid as oid, pgc.tableoid AS tableoid, n.nspname as nspname,\n CAST(pgc.conname AS pg_catalog.text) as name, CAST('table constraint' AS pg_catalog.text) as object\n FROM pg_catalog.pg_constraint pgc\n JOIN pg_catalog.pg_class c ON c.oid = pgc.conrelid\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n" + sysPart("table constraint") + "\n";
|
|
256
|
+
sql += "UNION ALL\n SELECT pgc.oid, pgc.tableoid, n.nspname,\n CAST(pgc.conname AS pg_catalog.text), CAST('domain constraint' AS pg_catalog.text)\n FROM pg_catalog.pg_constraint pgc\n JOIN pg_catalog.pg_type t ON t.oid = pgc.contypid\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n" + sysPart("domain constraint") + "\n";
|
|
257
|
+
sql += "UNION ALL\n SELECT o.oid, o.tableoid, n.nspname,\n CAST(o.opcname AS pg_catalog.text), CAST('operator class' AS pg_catalog.text)\n FROM pg_catalog.pg_opclass o\n JOIN pg_catalog.pg_am am ON o.opcmethod = am.oid\n JOIN pg_catalog.pg_namespace n ON n.oid = o.opcnamespace\n" + sysPart("operator class") + "\n";
|
|
258
|
+
sql += "UNION ALL\n SELECT opf.oid, opf.tableoid, n.nspname,\n CAST(opf.opfname AS pg_catalog.text), CAST('operator family' AS pg_catalog.text)\n FROM pg_catalog.pg_opfamily opf\n JOIN pg_catalog.pg_am am ON opf.opfmethod = am.oid\n JOIN pg_catalog.pg_namespace n ON opf.opfnamespace = n.oid\n" + sysPart("operator family") + "\n";
|
|
259
|
+
sql += "UNION ALL\n SELECT r.oid, r.tableoid, n.nspname,\n CAST(r.rulename AS pg_catalog.text), CAST('rule' AS pg_catalog.text)\n FROM pg_catalog.pg_rewrite r\n JOIN pg_catalog.pg_class c ON c.oid = r.ev_class\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n WHERE r.rulename != '_RETURN'\n";
|
|
260
|
+
sql += "UNION ALL\n SELECT t.oid, t.tableoid, n.nspname,\n CAST(t.tgname AS pg_catalog.text), CAST('trigger' AS pg_catalog.text)\n FROM pg_catalog.pg_trigger t\n JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n" + sysPart("trigger") + "\n";
|
|
261
|
+
sql += ") AS tt\n JOIN pg_catalog.pg_description d ON (tt.oid = d.objoid AND tt.tableoid = d.classoid AND d.objsubid = 0)\n";
|
|
262
|
+
sql += orderBy("1, 2, 3");
|
|
263
|
+
return {
|
|
264
|
+
sql,
|
|
265
|
+
params: params(),
|
|
266
|
+
description: "Object descriptions"
|
|
267
|
+
};
|
|
268
|
+
};
|
|
269
|
+
const describeTableDetails = (opts) => {
|
|
270
|
+
const { verbose, showSystem, pattern, serverVersion } = opts;
|
|
271
|
+
const hideTableam = opts.hideTableam ?? false;
|
|
272
|
+
let sql = "SELECT n.nspname as \"Schema\",\n c.relname as \"Name\",\n CASE c.relkind WHEN 'r' THEN 'table' WHEN 'v' THEN 'view' WHEN 'm' THEN 'materialized view' WHEN 'i' THEN 'index' WHEN 'S' THEN 'sequence' WHEN 't' THEN 'TOAST table' WHEN 'f' THEN 'foreign table' WHEN 'p' THEN 'partitioned table' WHEN 'I' THEN 'partitioned index' END as \"Type\",\n pg_catalog.pg_get_userbyid(c.relowner) as \"Owner\"";
|
|
273
|
+
if (verbose) {
|
|
274
|
+
sql += ",\n CASE c.relpersistence WHEN 'p' THEN 'permanent' WHEN 't' THEN 'temporary' WHEN 'u' THEN 'unlogged' END as \"Persistence\"";
|
|
275
|
+
if (!hideTableam && serverAtLeast(serverVersion, 12e4)) sql += ",\n am.amname as \"Access method\"";
|
|
276
|
+
sql += ",\n pg_catalog.pg_size_pretty(pg_catalog.pg_total_relation_size(c.oid)) as \"Size\",\n pg_catalog.obj_description(c.oid, 'pg_class') as \"Description\"";
|
|
277
|
+
}
|
|
278
|
+
sql += "\nFROM pg_catalog.pg_class c\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace";
|
|
279
|
+
if (verbose && !hideTableam && serverAtLeast(serverVersion, 12e4)) sql += "\n LEFT JOIN pg_catalog.pg_am am ON am.oid = c.relam";
|
|
280
|
+
sql += "\nWHERE c.relkind IN ('r','p','v','m','S','f','')\n";
|
|
281
|
+
if (!showSystem && pattern === void 0) sql += " AND n.nspname <> 'pg_catalog'\n AND n.nspname !~ '^pg_toast'\n AND n.nspname <> 'information_schema'\n";
|
|
282
|
+
sql += patternStub(true, "n.nspname", "c.relname");
|
|
283
|
+
sql += orderBy("1,2");
|
|
284
|
+
return {
|
|
285
|
+
sql,
|
|
286
|
+
params: params(),
|
|
287
|
+
description: "List of relations"
|
|
288
|
+
};
|
|
1389
289
|
};
|
|
1390
290
|
/**
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
}
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
}
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
};
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
};
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
291
|
+
* Upstream `describeRoles` (psql/describe.c) fetches the raw boolean
|
|
292
|
+
* columns then builds the cooked "Attributes" cell client-side from
|
|
293
|
+
* fixed per-flag strings. We do that aggregation in SQL via a
|
|
294
|
+
* NULL-skipping array_to_string so the printer sees only the final
|
|
295
|
+
* two visible columns ("Role name", "Attributes") plus an optional
|
|
296
|
+
* "Description" column when `+` is used. This matches the column
|
|
297
|
+
* layout, header banner ("List of roles"), and content ordering of
|
|
298
|
+
* vanilla psql 18, including the `Cannot login`-only rows produced by
|
|
299
|
+
* `\du regress_du_role*` in `src/test/regress/expected/psql.out`.
|
|
300
|
+
*/
|
|
301
|
+
const describeRoles = (opts) => {
|
|
302
|
+
const { verbose, showSystem, pattern, serverVersion } = opts;
|
|
303
|
+
const attrParts = [
|
|
304
|
+
"CASE WHEN r.rolsuper THEN 'Superuser' END",
|
|
305
|
+
"CASE WHEN NOT r.rolinherit THEN 'No inheritance' END",
|
|
306
|
+
"CASE WHEN r.rolcreaterole THEN 'Create role' END",
|
|
307
|
+
"CASE WHEN r.rolcreatedb THEN 'Create DB' END",
|
|
308
|
+
"CASE WHEN NOT r.rolcanlogin THEN 'Cannot login' END",
|
|
309
|
+
"CASE WHEN r.rolreplication THEN 'Replication' END"
|
|
310
|
+
];
|
|
311
|
+
if (serverAtLeast(serverVersion, 90500)) attrParts.push("CASE WHEN r.rolbypassrls THEN 'Bypass RLS' END");
|
|
312
|
+
attrParts.push("CASE WHEN r.rolconnlimit >= 0 THEN pg_catalog.format('%s connection%s', r.rolconnlimit, CASE WHEN r.rolconnlimit = 1 THEN '' ELSE 's' END) END");
|
|
313
|
+
attrParts.push("CASE WHEN r.rolvaliduntil IS NOT NULL THEN pg_catalog.format('Password valid until %s', r.rolvaliduntil) END");
|
|
314
|
+
let sql = `SELECT r.rolname AS "Role name",
|
|
315
|
+
pg_catalog.array_to_string(ARRAY(
|
|
316
|
+
SELECT a FROM (VALUES
|
|
317
|
+
${attrParts.map((p) => `(${p})`).join(",\n ")}\n ) AS x(a)
|
|
318
|
+
WHERE a IS NOT NULL
|
|
319
|
+
), ', ') AS "Attributes"`;
|
|
320
|
+
if (verbose) sql += ",\n pg_catalog.shobj_description(r.oid, 'pg_authid') AS \"Description\"";
|
|
321
|
+
sql += "\nFROM pg_catalog.pg_roles r\n";
|
|
322
|
+
let hasWhere = false;
|
|
323
|
+
if (!showSystem && pattern === void 0) {
|
|
324
|
+
sql += "WHERE r.rolname !~ '^pg_'\n";
|
|
325
|
+
hasWhere = true;
|
|
326
|
+
}
|
|
327
|
+
sql += patternStub(hasWhere, void 0, "r.rolname");
|
|
328
|
+
sql += orderBy("1");
|
|
329
|
+
return {
|
|
330
|
+
sql,
|
|
331
|
+
params: params(),
|
|
332
|
+
description: "List of roles"
|
|
333
|
+
};
|
|
334
|
+
};
|
|
335
|
+
const listDbRoleSettings = (opts) => {
|
|
336
|
+
let sql = "SELECT rolname AS \"Role\", datname AS \"Database\",\npg_catalog.array_to_string(setconfig, E'\\n') AS \"Settings\"\nFROM pg_catalog.pg_db_role_setting s\nLEFT JOIN pg_catalog.pg_database d ON d.oid = setdatabase\nLEFT JOIN pg_catalog.pg_roles r ON r.oid = setrole\n";
|
|
337
|
+
let hasWhere = false;
|
|
338
|
+
if (opts.pattern !== void 0) {
|
|
339
|
+
sql += patternStub(hasWhere, void 0, "r.rolname");
|
|
340
|
+
hasWhere = true;
|
|
341
|
+
}
|
|
342
|
+
if (opts.pattern2 !== void 0) sql += patternStub(hasWhere, void 0, "d.datname");
|
|
343
|
+
sql += orderBy("1, 2");
|
|
344
|
+
const ps = [];
|
|
345
|
+
if (opts.pattern !== void 0) ps.push(opts.pattern);
|
|
346
|
+
if (opts.pattern2 !== void 0) ps.push(opts.pattern2);
|
|
347
|
+
return {
|
|
348
|
+
sql,
|
|
349
|
+
params: ps,
|
|
350
|
+
description: "List of settings"
|
|
351
|
+
};
|
|
352
|
+
};
|
|
353
|
+
const describeRoleGrants = (opts) => {
|
|
354
|
+
const { showSystem, pattern, serverVersion } = opts;
|
|
355
|
+
let sql = "SELECT m.rolname AS \"Role name\", r.rolname AS \"Member of\",\n pg_catalog.concat_ws(', ',\n";
|
|
356
|
+
if (serverAtLeast(serverVersion, 16e4)) sql += " CASE WHEN pam.admin_option THEN 'ADMIN' END,\n CASE WHEN pam.inherit_option THEN 'INHERIT' END,\n CASE WHEN pam.set_option THEN 'SET' END\n";
|
|
357
|
+
else sql += " CASE WHEN pam.admin_option THEN 'ADMIN' END,\n CASE WHEN m.rolinherit THEN 'INHERIT' END,\n 'SET'\n";
|
|
358
|
+
sql += " ) AS \"Options\",\n g.rolname AS \"Grantor\"\n";
|
|
359
|
+
sql += "FROM pg_catalog.pg_roles m\n JOIN pg_catalog.pg_auth_members pam ON (pam.member = m.oid)\n LEFT JOIN pg_catalog.pg_roles r ON (pam.roleid = r.oid)\n LEFT JOIN pg_catalog.pg_roles g ON (pam.grantor = g.oid)\n";
|
|
360
|
+
let hasWhere = false;
|
|
361
|
+
if (!showSystem && pattern === void 0) {
|
|
362
|
+
sql += "WHERE m.rolname !~ '^pg_'\n";
|
|
363
|
+
hasWhere = true;
|
|
364
|
+
}
|
|
365
|
+
sql += patternStub(hasWhere, void 0, "m.rolname");
|
|
366
|
+
sql += orderBy("1, 2, 4");
|
|
367
|
+
return {
|
|
368
|
+
sql,
|
|
369
|
+
params: params(),
|
|
370
|
+
description: "List of role grants"
|
|
371
|
+
};
|
|
372
|
+
};
|
|
373
|
+
const listTables = (opts) => {
|
|
374
|
+
const { verbose, showSystem, pattern, serverVersion } = opts;
|
|
375
|
+
const hideTableam = opts.hideTableam ?? false;
|
|
376
|
+
const tt = opts.tabtypes ?? "";
|
|
377
|
+
let showTables = tt.includes("t");
|
|
378
|
+
const showIndexes = tt.includes("i");
|
|
379
|
+
let showViews = tt.includes("v");
|
|
380
|
+
let showMatViews = tt.includes("m");
|
|
381
|
+
let showSeq = tt.includes("s");
|
|
382
|
+
let showForeign = tt.includes("E");
|
|
383
|
+
const ntypes = +showTables + +showIndexes + +showViews + +showMatViews + +showSeq + +showForeign;
|
|
384
|
+
if (ntypes === 0) showTables = showViews = showMatViews = showSeq = showForeign = true;
|
|
385
|
+
let sql = "SELECT n.nspname as \"Schema\",\n c.relname as \"Name\",\n CASE c.relkind WHEN 'r' THEN 'table' WHEN 'v' THEN 'view' WHEN 'm' THEN 'materialized view' WHEN 'i' THEN 'index' WHEN 'S' THEN 'sequence' WHEN 't' THEN 'TOAST table' WHEN 'f' THEN 'foreign table' WHEN 'p' THEN 'partitioned table' WHEN 'I' THEN 'partitioned index' END as \"Type\",\n pg_catalog.pg_get_userbyid(c.relowner) as \"Owner\"";
|
|
386
|
+
if (showIndexes) sql += ",\n c2.relname as \"Table\"";
|
|
387
|
+
if (verbose) {
|
|
388
|
+
sql += ",\n CASE c.relpersistence WHEN 'p' THEN 'permanent' WHEN 't' THEN 'temporary' WHEN 'u' THEN 'unlogged' END as \"Persistence\"";
|
|
389
|
+
if (!hideTableam && serverAtLeast(serverVersion, 12e4) && (showTables || showMatViews || showIndexes)) sql += ",\n am.amname as \"Access method\"";
|
|
390
|
+
sql += ",\n pg_catalog.pg_size_pretty(pg_catalog.pg_total_relation_size(c.oid)) as \"Size\",\n pg_catalog.obj_description(c.oid, 'pg_class') as \"Description\"";
|
|
391
|
+
}
|
|
392
|
+
sql += "\nFROM pg_catalog.pg_class c\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace";
|
|
393
|
+
if (verbose && !hideTableam && serverAtLeast(serverVersion, 12e4) && (showTables || showMatViews || showIndexes)) sql += "\n LEFT JOIN pg_catalog.pg_am am ON am.oid = c.relam";
|
|
394
|
+
if (showIndexes) sql += "\n LEFT JOIN pg_catalog.pg_index i ON i.indexrelid = c.oid\n LEFT JOIN pg_catalog.pg_class c2 ON i.indrelid = c2.oid";
|
|
395
|
+
sql += "\nWHERE c.relkind IN (";
|
|
396
|
+
const kinds = [];
|
|
397
|
+
if (showTables) {
|
|
398
|
+
kinds.push("'r'", "'p'");
|
|
399
|
+
if (showSystem || pattern !== void 0) kinds.push("'t'");
|
|
400
|
+
}
|
|
401
|
+
if (showViews) kinds.push("'v'");
|
|
402
|
+
if (showMatViews) kinds.push("'m'");
|
|
403
|
+
if (showIndexes) kinds.push("'i'", "'I'");
|
|
404
|
+
if (showSeq) kinds.push("'S'");
|
|
405
|
+
if (showSystem || pattern !== void 0) kinds.push("'s'");
|
|
406
|
+
if (showForeign) kinds.push("'f'");
|
|
407
|
+
kinds.push("''");
|
|
408
|
+
sql += kinds.join(",") + ")\n";
|
|
409
|
+
if (!showSystem && pattern === void 0) sql += " AND n.nspname <> 'pg_catalog'\n AND n.nspname !~ '^pg_toast'\n AND n.nspname <> 'information_schema'\n";
|
|
410
|
+
sql += patternStub(true, "n.nspname", "c.relname");
|
|
411
|
+
sql += orderBy("1,2");
|
|
412
|
+
let description = "List of relations";
|
|
413
|
+
if (ntypes === 1) {
|
|
414
|
+
if (showTables) description = "List of tables";
|
|
415
|
+
else if (showIndexes) description = "List of indexes";
|
|
416
|
+
else if (showViews) description = "List of views";
|
|
417
|
+
else if (showMatViews) description = "List of materialized views";
|
|
418
|
+
else if (showSeq) description = "List of sequences";
|
|
419
|
+
else if (showForeign) description = "List of foreign tables";
|
|
420
|
+
}
|
|
421
|
+
return {
|
|
422
|
+
sql,
|
|
423
|
+
params: params(),
|
|
424
|
+
description
|
|
425
|
+
};
|
|
426
|
+
};
|
|
427
|
+
const listPartitionedTables = (opts) => {
|
|
428
|
+
const { verbose, pattern, serverVersion } = opts;
|
|
429
|
+
if (serverLess(serverVersion, 1e5)) return {
|
|
430
|
+
sql: "/* server < 10 does not support declarative partitioning */ SELECT 1 WHERE false;",
|
|
431
|
+
params: [],
|
|
432
|
+
description: "List of partitioned relations"
|
|
433
|
+
};
|
|
434
|
+
const rt = opts.reltypes ?? "";
|
|
435
|
+
let showTables = rt.includes("t");
|
|
436
|
+
let showIndexes = rt.includes("i");
|
|
437
|
+
const showNested = rt.includes("n");
|
|
438
|
+
if (!showTables && !showIndexes) showTables = showIndexes = true;
|
|
439
|
+
const mixed = showTables && showIndexes;
|
|
440
|
+
let sql = "SELECT n.nspname as \"Schema\",\n c.relname as \"Name\",\n pg_catalog.pg_get_userbyid(c.relowner) as \"Owner\"";
|
|
441
|
+
if (mixed) sql += ",\n CASE c.relkind WHEN 'p' THEN 'partitioned table' WHEN 'I' THEN 'partitioned index' END as \"Type\"";
|
|
442
|
+
if (showNested || pattern !== void 0) sql += ",\n inh.inhparent::pg_catalog.regclass as \"Parent name\"";
|
|
443
|
+
if (showIndexes) sql += ",\n c2.oid::pg_catalog.regclass as \"Table\"";
|
|
444
|
+
if (verbose) {
|
|
445
|
+
sql += ",\n am.amname as \"Access method\"";
|
|
446
|
+
if (showNested) {
|
|
447
|
+
sql += ",\n s.dps as \"Leaf partition size\"";
|
|
448
|
+
sql += ",\n s.tps as \"Total size\"";
|
|
449
|
+
} else sql += ",\n s.tps as \"Total size\"";
|
|
450
|
+
sql += ",\n pg_catalog.obj_description(c.oid, 'pg_class') as \"Description\"";
|
|
451
|
+
}
|
|
452
|
+
sql += "\nFROM pg_catalog.pg_class c\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace";
|
|
453
|
+
if (showIndexes) sql += "\n LEFT JOIN pg_catalog.pg_index i ON i.indexrelid = c.oid\n LEFT JOIN pg_catalog.pg_class c2 ON i.indrelid = c2.oid";
|
|
454
|
+
if (showNested || pattern !== void 0) sql += "\n LEFT JOIN pg_catalog.pg_inherits inh ON c.oid = inh.inhrelid";
|
|
455
|
+
if (verbose) {
|
|
456
|
+
sql += "\n LEFT JOIN pg_catalog.pg_am am ON c.relam = am.oid";
|
|
457
|
+
if (serverLess(serverVersion, 12e4)) sql += ",\n LATERAL (WITH RECURSIVE d AS (\n SELECT inhrelid AS oid, 1 AS level FROM pg_catalog.pg_inherits WHERE inhparent = c.oid\n UNION ALL\n SELECT inhrelid, level + 1 FROM pg_catalog.pg_inherits i JOIN d ON i.inhparent = d.oid)\n SELECT pg_catalog.pg_size_pretty(sum(pg_catalog.pg_table_size(d.oid))) AS tps,\n pg_catalog.pg_size_pretty(sum(CASE WHEN d.level = 1 THEN pg_catalog.pg_table_size(d.oid) ELSE 0 END)) AS dps\n FROM d) s";
|
|
458
|
+
else sql += ",\n LATERAL (SELECT pg_catalog.pg_size_pretty(sum(\n CASE WHEN ppt.isleaf AND ppt.level = 1\n THEN pg_catalog.pg_table_size(ppt.relid) ELSE 0 END)) AS dps,\n pg_catalog.pg_size_pretty(sum(pg_catalog.pg_table_size(ppt.relid))) AS tps\n FROM pg_catalog.pg_partition_tree(c.oid) ppt) s";
|
|
459
|
+
}
|
|
460
|
+
sql += "\nWHERE c.relkind IN (";
|
|
461
|
+
const kinds = [];
|
|
462
|
+
if (showTables) kinds.push("'p'");
|
|
463
|
+
if (showIndexes) kinds.push("'I'");
|
|
464
|
+
kinds.push("''");
|
|
465
|
+
sql += kinds.join(",") + ")\n";
|
|
466
|
+
if (!showNested && pattern === void 0) sql += " AND NOT c.relispartition\n";
|
|
467
|
+
if (pattern === void 0) sql += " AND n.nspname <> 'pg_catalog'\n AND n.nspname !~ '^pg_toast'\n AND n.nspname <> 'information_schema'\n";
|
|
468
|
+
sql += patternStub(true, "n.nspname", "c.relname");
|
|
469
|
+
sql += `ORDER BY "Schema", ${mixed ? "\"Type\" DESC, " : ""}${showNested || pattern !== void 0 ? "\"Parent name\" NULLS FIRST, " : ""}"Name";`;
|
|
470
|
+
const description = showIndexes && !showTables ? "List of partitioned indexes" : showTables && !showIndexes ? "List of partitioned tables" : "List of partitioned relations";
|
|
471
|
+
return {
|
|
472
|
+
sql,
|
|
473
|
+
params: params(),
|
|
474
|
+
description
|
|
475
|
+
};
|
|
476
|
+
};
|
|
477
|
+
const listLanguages = (opts) => {
|
|
478
|
+
const { verbose, showSystem, pattern } = opts;
|
|
479
|
+
let sql = "SELECT l.lanname AS \"Name\",\n pg_catalog.pg_get_userbyid(l.lanowner) as \"Owner\",\n l.lanpltrusted AS \"Trusted\"";
|
|
480
|
+
if (verbose) sql += ",\n NOT l.lanispl AS \"Internal language\",\n l.lanplcallfoid::pg_catalog.regprocedure AS \"Call handler\",\n l.lanvalidator::pg_catalog.regprocedure AS \"Validator\",\n l.laninline::pg_catalog.regprocedure AS \"Inline handler\",\n " + aclColumn("l.lanacl");
|
|
481
|
+
sql += ",\n d.description AS \"Description\"\nFROM pg_catalog.pg_language l\nLEFT JOIN pg_catalog.pg_description d\n ON d.classoid = l.tableoid AND d.objoid = l.oid AND d.objsubid = 0\n";
|
|
482
|
+
let hasWhere = false;
|
|
483
|
+
if (pattern !== void 0) {
|
|
484
|
+
sql += patternStub(hasWhere, void 0, "l.lanname");
|
|
485
|
+
hasWhere = true;
|
|
486
|
+
}
|
|
487
|
+
if (!showSystem && pattern === void 0) {
|
|
488
|
+
sql += "WHERE l.lanplcallfoid != 0\n";
|
|
489
|
+
hasWhere = true;
|
|
490
|
+
}
|
|
491
|
+
sql += orderBy("1");
|
|
492
|
+
return {
|
|
493
|
+
sql,
|
|
494
|
+
params: params(),
|
|
495
|
+
description: "List of languages"
|
|
496
|
+
};
|
|
497
|
+
};
|
|
498
|
+
const listDomains = (opts) => {
|
|
499
|
+
const { verbose, showSystem, pattern } = opts;
|
|
500
|
+
let sql = "SELECT n.nspname as \"Schema\",\n t.typname as \"Name\",\n pg_catalog.format_type(t.typbasetype, t.typtypmod) as \"Type\",\n (SELECT c.collname FROM pg_catalog.pg_collation c, pg_catalog.pg_type bt\n WHERE c.oid = t.typcollation AND bt.oid = t.typbasetype AND t.typcollation <> bt.typcollation) as \"Collation\",\n CASE WHEN t.typnotnull THEN 'not null' END as \"Nullable\",\n t.typdefault as \"Default\",\n pg_catalog.array_to_string(ARRAY(\n SELECT pg_catalog.pg_get_constraintdef(r.oid, true) FROM pg_catalog.pg_constraint r WHERE t.oid = r.contypid AND r.contype = 'c' ORDER BY r.conname\n ), ' ') as \"Check\"";
|
|
501
|
+
if (verbose) {
|
|
502
|
+
sql += ",\n " + aclColumn("t.typacl");
|
|
503
|
+
sql += ",\n d.description as \"Description\"";
|
|
504
|
+
}
|
|
505
|
+
sql += "\nFROM pg_catalog.pg_type t\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n";
|
|
506
|
+
if (verbose) sql += " LEFT JOIN pg_catalog.pg_description d ON d.classoid = t.tableoid AND d.objoid = t.oid AND d.objsubid = 0\n";
|
|
507
|
+
sql += "WHERE t.typtype = 'd'\n";
|
|
508
|
+
if (!showSystem && pattern === void 0) sql += " AND n.nspname <> 'pg_catalog'\n AND n.nspname <> 'information_schema'\n";
|
|
509
|
+
sql += patternStub(true, "n.nspname", "t.typname");
|
|
510
|
+
sql += orderBy("1, 2");
|
|
511
|
+
return {
|
|
512
|
+
sql,
|
|
513
|
+
params: params(),
|
|
514
|
+
description: "List of domains"
|
|
515
|
+
};
|
|
516
|
+
};
|
|
517
|
+
const listConversions = (opts) => {
|
|
518
|
+
const { verbose, showSystem, pattern } = opts;
|
|
519
|
+
let sql = "SELECT n.nspname AS \"Schema\",\n c.conname AS \"Name\",\n pg_catalog.pg_encoding_to_char(c.conforencoding) AS \"Source\",\n pg_catalog.pg_encoding_to_char(c.contoencoding) AS \"Destination\",\n CASE WHEN c.condefault THEN 'yes' ELSE 'no' END AS \"Default?\"";
|
|
520
|
+
if (verbose) sql += ",\n d.description AS \"Description\"";
|
|
521
|
+
sql += "\nFROM pg_catalog.pg_conversion c\n JOIN pg_catalog.pg_namespace n ON n.oid = c.connamespace\n";
|
|
522
|
+
if (verbose) sql += "LEFT JOIN pg_catalog.pg_description d ON d.classoid = c.tableoid AND d.objoid = c.oid AND d.objsubid = 0\n";
|
|
523
|
+
sql += "WHERE true\n";
|
|
524
|
+
if (!showSystem && pattern === void 0) sql += " AND n.nspname <> 'pg_catalog'\n AND n.nspname <> 'information_schema'\n";
|
|
525
|
+
sql += patternStub(true, "n.nspname", "c.conname");
|
|
526
|
+
sql += orderBy("1, 2");
|
|
527
|
+
return {
|
|
528
|
+
sql,
|
|
529
|
+
params: params(),
|
|
530
|
+
description: "List of conversions"
|
|
531
|
+
};
|
|
532
|
+
};
|
|
533
|
+
const describeConfigurationParameters = (opts) => {
|
|
534
|
+
const { verbose, pattern, serverVersion } = opts;
|
|
535
|
+
let sql = "SELECT s.name AS \"Parameter\", pg_catalog.current_setting(s.name) AS \"Value\"";
|
|
536
|
+
if (verbose) {
|
|
537
|
+
sql += ", s.vartype AS \"Type\", s.context AS \"Context\", ";
|
|
538
|
+
if (serverAtLeast(serverVersion, 15e4)) sql += aclColumn("p.paracl");
|
|
539
|
+
else sql += "NULL AS \"Access privileges\"";
|
|
540
|
+
}
|
|
541
|
+
sql += "\nFROM pg_catalog.pg_settings s\n";
|
|
542
|
+
if (verbose && serverAtLeast(serverVersion, 15e4)) sql += " LEFT JOIN pg_catalog.pg_parameter_acl p ON pg_catalog.lower(s.name) = p.parname\n";
|
|
543
|
+
if (pattern !== void 0) sql += patternStub(false, void 0, "pg_catalog.lower(s.name)");
|
|
544
|
+
else sql += "WHERE s.source <> 'default' AND s.setting IS DISTINCT FROM s.boot_val\n";
|
|
545
|
+
sql += orderBy("1");
|
|
546
|
+
return {
|
|
547
|
+
sql,
|
|
548
|
+
params: params(),
|
|
549
|
+
description: pattern !== void 0 ? "List of configuration parameters" : "List of non-default configuration parameters"
|
|
550
|
+
};
|
|
551
|
+
};
|
|
552
|
+
const listEventTriggers = (opts) => {
|
|
553
|
+
const { verbose } = opts;
|
|
554
|
+
let sql = "SELECT evtname as \"Name\", evtevent as \"Event\", pg_catalog.pg_get_userbyid(e.evtowner) as \"Owner\",\n case evtenabled when 'O' then 'enabled' when 'R' then 'replica' when 'A' then 'always' when 'D' then 'disabled' end as \"Enabled\",\n e.evtfoid::pg_catalog.regproc as \"Function\", pg_catalog.array_to_string(array(select x from pg_catalog.unnest(evttags) as t(x)), ', ') as \"Tags\"";
|
|
555
|
+
if (verbose) sql += ",\npg_catalog.obj_description(e.oid, 'pg_event_trigger') as \"Description\"";
|
|
556
|
+
sql += "\nFROM pg_catalog.pg_event_trigger e\n";
|
|
557
|
+
sql += patternStub(false, void 0, "evtname");
|
|
558
|
+
sql += orderBy("1");
|
|
559
|
+
return {
|
|
560
|
+
sql,
|
|
561
|
+
params: params(),
|
|
562
|
+
description: "List of event triggers"
|
|
563
|
+
};
|
|
564
|
+
};
|
|
565
|
+
const listExtendedStats = (opts) => {
|
|
566
|
+
const { verbose, serverVersion } = opts;
|
|
567
|
+
if (serverLess(serverVersion, 1e5)) return {
|
|
568
|
+
sql: "/* server < 10 does not support extended statistics */ SELECT 1 WHERE false;",
|
|
569
|
+
params: [],
|
|
570
|
+
description: "List of extended statistics"
|
|
571
|
+
};
|
|
572
|
+
let sql = "SELECT\nes.stxnamespace::pg_catalog.regnamespace::pg_catalog.text AS \"Schema\",\nes.stxname AS \"Name\",\n";
|
|
573
|
+
if (serverAtLeast(serverVersion, 14e4)) sql += "pg_catalog.format('%s FROM %s', pg_catalog.pg_get_statisticsobjdef_columns(es.oid), es.stxrelid::pg_catalog.regclass) AS \"Definition\"";
|
|
574
|
+
else sql += "pg_catalog.format('%s FROM %s',\n (SELECT pg_catalog.string_agg(pg_catalog.quote_ident(a.attname),', ')\n FROM pg_catalog.unnest(es.stxkeys) s(attnum)\n JOIN pg_catalog.pg_attribute a\n ON (es.stxrelid = a.attrelid AND a.attnum = s.attnum AND NOT a.attisdropped)),\nes.stxrelid::pg_catalog.regclass) AS \"Definition\"";
|
|
575
|
+
sql += ",\nCASE WHEN 'd' = any(es.stxkind) THEN 'defined' END AS \"Ndistinct\",\nCASE WHEN 'f' = any(es.stxkind) THEN 'defined' END AS \"Dependencies\"";
|
|
576
|
+
if (serverAtLeast(serverVersion, 12e4)) sql += ",\nCASE WHEN 'm' = any(es.stxkind) THEN 'defined' END AS \"MCV\"";
|
|
577
|
+
if (verbose) sql += ", \npg_catalog.obj_description(oid, 'pg_statistic_ext') AS \"Description\"";
|
|
578
|
+
sql += "\nFROM pg_catalog.pg_statistic_ext es\n";
|
|
579
|
+
sql += patternStub(false, "es.stxnamespace::pg_catalog.regnamespace::pg_catalog.text", "es.stxname");
|
|
580
|
+
sql += orderBy("1, 2");
|
|
581
|
+
return {
|
|
582
|
+
sql,
|
|
583
|
+
params: params(),
|
|
584
|
+
description: "List of extended statistics"
|
|
585
|
+
};
|
|
586
|
+
};
|
|
587
|
+
const listCasts = (opts) => {
|
|
588
|
+
const { verbose, serverVersion } = opts;
|
|
589
|
+
let sql = "SELECT pg_catalog.format_type(castsource, NULL) AS \"Source type\",\n pg_catalog.format_type(casttarget, NULL) AS \"Target type\",\n CASE WHEN c.castmethod = 'b' THEN '(binary coercible)'\n WHEN c.castmethod = 'i' THEN '(with inout)'\n ELSE p.proname\n END AS \"Function\",\n CASE WHEN c.castcontext = 'e' THEN 'no'\n WHEN c.castcontext = 'a' THEN 'in assignment'\n ELSE 'yes'\n END AS \"Implicit?\"";
|
|
590
|
+
if (verbose) {
|
|
591
|
+
if (serverAtLeast(serverVersion, 18e4)) sql += ",\n CASE WHEN p.proleakproof THEN 'yes' ELSE 'no' END AS \"Leakproof?\"";
|
|
592
|
+
sql += ",\n d.description AS \"Description\"";
|
|
593
|
+
}
|
|
594
|
+
sql += "\nFROM pg_catalog.pg_cast c LEFT JOIN pg_catalog.pg_proc p\n ON c.castfunc = p.oid\n LEFT JOIN pg_catalog.pg_type ts ON c.castsource = ts.oid\n LEFT JOIN pg_catalog.pg_namespace ns ON ns.oid = ts.typnamespace\n LEFT JOIN pg_catalog.pg_type tt ON c.casttarget = tt.oid\n LEFT JOIN pg_catalog.pg_namespace nt ON nt.oid = tt.typnamespace\n";
|
|
595
|
+
if (verbose) sql += " LEFT JOIN pg_catalog.pg_description d ON d.classoid = c.tableoid AND d.objoid = c.oid AND d.objsubid = 0\n";
|
|
596
|
+
sql += "WHERE ( (true";
|
|
597
|
+
sql += patternStub(true, "ns.nspname", "ts.typname");
|
|
598
|
+
sql += ") OR (true";
|
|
599
|
+
sql += patternStub(true, "nt.nspname", "tt.typname");
|
|
600
|
+
sql += ") )\n";
|
|
601
|
+
sql += orderBy("1, 2");
|
|
602
|
+
return {
|
|
603
|
+
sql,
|
|
604
|
+
params: params(),
|
|
605
|
+
description: "List of casts"
|
|
606
|
+
};
|
|
607
|
+
};
|
|
608
|
+
const listCollations = (opts) => {
|
|
609
|
+
const { verbose, showSystem, pattern, serverVersion } = opts;
|
|
610
|
+
let sql = "SELECT\n n.nspname AS \"Schema\",\n c.collname AS \"Name\",\n";
|
|
611
|
+
if (serverAtLeast(serverVersion, 1e5)) sql += " CASE c.collprovider WHEN 'd' THEN 'default' WHEN 'b' THEN 'builtin' WHEN 'c' THEN 'libc' WHEN 'i' THEN 'icu' END AS \"Provider\",\n";
|
|
612
|
+
else sql += " 'libc' AS \"Provider\",\n";
|
|
613
|
+
sql += " c.collcollate AS \"Collate\",\n c.collctype AS \"Ctype\",\n";
|
|
614
|
+
if (serverAtLeast(serverVersion, 17e4)) sql += " c.colllocale AS \"Locale\",\n";
|
|
615
|
+
else if (serverAtLeast(serverVersion, 15e4)) sql += " c.colliculocale AS \"Locale\",\n";
|
|
616
|
+
else sql += " c.collcollate AS \"Locale\",\n";
|
|
617
|
+
if (serverAtLeast(serverVersion, 16e4)) sql += " c.collicurules AS \"ICU Rules\",\n";
|
|
618
|
+
else sql += " NULL AS \"ICU Rules\",\n";
|
|
619
|
+
if (serverAtLeast(serverVersion, 12e4)) sql += " CASE WHEN c.collisdeterministic THEN 'yes' ELSE 'no' END AS \"Deterministic?\"";
|
|
620
|
+
else sql += " 'yes' AS \"Deterministic?\"";
|
|
621
|
+
if (verbose) sql += ",\n pg_catalog.obj_description(c.oid, 'pg_collation') AS \"Description\"";
|
|
622
|
+
sql += "\nFROM pg_catalog.pg_collation c, pg_catalog.pg_namespace n\nWHERE n.oid = c.collnamespace\n";
|
|
623
|
+
if (!showSystem && pattern === void 0) sql += " AND n.nspname <> 'pg_catalog'\n AND n.nspname <> 'information_schema'\n";
|
|
624
|
+
sql += " AND c.collencoding IN (-1, pg_catalog.pg_char_to_encoding(pg_catalog.getdatabaseencoding()))\n";
|
|
625
|
+
sql += patternStub(true, "n.nspname", "c.collname");
|
|
626
|
+
sql += orderBy("1, 2");
|
|
627
|
+
return {
|
|
628
|
+
sql,
|
|
629
|
+
params: params(),
|
|
630
|
+
description: "List of collations"
|
|
631
|
+
};
|
|
632
|
+
};
|
|
633
|
+
const listSchemas = (opts) => {
|
|
634
|
+
const { verbose, showSystem, pattern } = opts;
|
|
635
|
+
let sql = "SELECT n.nspname AS \"Name\",\n pg_catalog.pg_get_userbyid(n.nspowner) AS \"Owner\"";
|
|
636
|
+
if (verbose) {
|
|
637
|
+
sql += ",\n " + aclColumn("n.nspacl");
|
|
638
|
+
sql += ",\n pg_catalog.obj_description(n.oid, 'pg_namespace') AS \"Description\"";
|
|
639
|
+
}
|
|
640
|
+
sql += "\nFROM pg_catalog.pg_namespace n\n";
|
|
641
|
+
if (!showSystem && pattern === void 0) sql += "WHERE n.nspname !~ '^pg_' AND n.nspname <> 'information_schema'\n";
|
|
642
|
+
sql += patternStub(!showSystem && pattern === void 0, void 0, "n.nspname");
|
|
643
|
+
sql += orderBy("1");
|
|
644
|
+
return {
|
|
645
|
+
sql,
|
|
646
|
+
params: params(),
|
|
647
|
+
description: "List of schemas"
|
|
648
|
+
};
|
|
649
|
+
};
|
|
650
|
+
const listTSParsers = (opts) => {
|
|
651
|
+
const { verbose } = opts;
|
|
652
|
+
if (verbose) {
|
|
653
|
+
let sql = "SELECT p.oid,\n n.nspname,\n p.prsname\nFROM pg_catalog.pg_ts_parser p\nLEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace\n";
|
|
654
|
+
sql += patternStub(false, "n.nspname", "p.prsname");
|
|
655
|
+
sql += orderBy("1, 2");
|
|
656
|
+
return {
|
|
657
|
+
sql,
|
|
658
|
+
params: params(),
|
|
659
|
+
description: "List of text search parsers (verbose)"
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
let sql = "SELECT\n n.nspname as \"Schema\",\n p.prsname as \"Name\",\n pg_catalog.obj_description(p.oid, 'pg_ts_parser') as \"Description\"\nFROM pg_catalog.pg_ts_parser p\nLEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace\n";
|
|
663
|
+
sql += patternStub(false, "n.nspname", "p.prsname");
|
|
664
|
+
sql += orderBy("1, 2");
|
|
665
|
+
return {
|
|
666
|
+
sql,
|
|
667
|
+
params: params(),
|
|
668
|
+
description: "List of text search parsers"
|
|
669
|
+
};
|
|
1642
670
|
};
|
|
1643
671
|
/**
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
672
|
+
* Per-parser detail (one row per phase). Caller binds the parser oid.
|
|
673
|
+
* Two queries upstream; we emit both as a UNION via a single string.
|
|
674
|
+
*/
|
|
675
|
+
const describeOneTSParser = (opts) => {
|
|
676
|
+
const { oid } = opts;
|
|
677
|
+
return {
|
|
678
|
+
sql: `SELECT 'Start parse' AS "Method",
|
|
679
|
+
p.prsstart::pg_catalog.regproc AS "Function",
|
|
680
|
+
pg_catalog.obj_description(p.prsstart, 'pg_proc') as "Description"
|
|
681
|
+
FROM pg_catalog.pg_ts_parser p WHERE p.oid = '${oid}'\nUNION ALL\nSELECT 'Get next token', p.prstoken::pg_catalog.regproc, pg_catalog.obj_description(p.prstoken, 'pg_proc')\n FROM pg_catalog.pg_ts_parser p WHERE p.oid = '${oid}'\nUNION ALL\nSELECT 'End parse', p.prsend::pg_catalog.regproc, pg_catalog.obj_description(p.prsend, 'pg_proc')\n FROM pg_catalog.pg_ts_parser p WHERE p.oid = '${oid}'\nUNION ALL\nSELECT 'Get headline', p.prsheadline::pg_catalog.regproc, pg_catalog.obj_description(p.prsheadline, 'pg_proc')\n FROM pg_catalog.pg_ts_parser p WHERE p.oid = '${oid}'\nUNION ALL\nSELECT 'Get token types', p.prslextype::pg_catalog.regproc, pg_catalog.obj_description(p.prslextype, 'pg_proc')\n FROM pg_catalog.pg_ts_parser p WHERE p.oid = '${oid}';`,
|
|
682
|
+
params: [],
|
|
683
|
+
description: "Text search parser details"
|
|
684
|
+
};
|
|
685
|
+
};
|
|
686
|
+
const listTSDictionaries = (opts) => {
|
|
687
|
+
const { verbose } = opts;
|
|
688
|
+
let sql = "SELECT\n n.nspname as \"Schema\",\n d.dictname as \"Name\",\n";
|
|
689
|
+
if (verbose) sql += " ( SELECT COALESCE(nt.nspname, '(null)')::pg_catalog.text || '.' || t.tmplname FROM\n pg_catalog.pg_ts_template t\n LEFT JOIN pg_catalog.pg_namespace nt ON nt.oid = t.tmplnamespace\n WHERE d.dicttemplate = t.oid ) AS \"Template\",\n d.dictinitoption as \"Init options\",\n";
|
|
690
|
+
sql += " pg_catalog.obj_description(d.oid, 'pg_ts_dict') as \"Description\"\nFROM pg_catalog.pg_ts_dict d\nLEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.dictnamespace\n";
|
|
691
|
+
sql += patternStub(false, "n.nspname", "d.dictname");
|
|
692
|
+
sql += orderBy("1, 2");
|
|
693
|
+
return {
|
|
694
|
+
sql,
|
|
695
|
+
params: params(),
|
|
696
|
+
description: "List of text search dictionaries"
|
|
697
|
+
};
|
|
698
|
+
};
|
|
699
|
+
const listTSTemplates = (opts) => {
|
|
700
|
+
const { verbose } = opts;
|
|
701
|
+
let sql;
|
|
702
|
+
if (verbose) sql = "SELECT\n n.nspname AS \"Schema\",\n t.tmplname AS \"Name\",\n t.tmplinit::pg_catalog.regproc AS \"Init\",\n t.tmpllexize::pg_catalog.regproc AS \"Lexize\",\n pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \"Description\"\n";
|
|
703
|
+
else sql = "SELECT\n n.nspname AS \"Schema\",\n t.tmplname AS \"Name\",\n pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \"Description\"\n";
|
|
704
|
+
sql += "FROM pg_catalog.pg_ts_template t\nLEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.tmplnamespace\n";
|
|
705
|
+
sql += patternStub(false, "n.nspname", "t.tmplname");
|
|
706
|
+
sql += orderBy("1, 2");
|
|
707
|
+
return {
|
|
708
|
+
sql,
|
|
709
|
+
params: params(),
|
|
710
|
+
description: "List of text search templates"
|
|
711
|
+
};
|
|
712
|
+
};
|
|
713
|
+
const listTSConfigs = (opts) => {
|
|
714
|
+
const { verbose } = opts;
|
|
715
|
+
if (verbose) {
|
|
716
|
+
let sql = "SELECT c.oid, c.cfgname, n.nspname, p.prsname, np.nspname as pnspname\nFROM pg_catalog.pg_ts_config c\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace,\n pg_catalog.pg_ts_parser p\n LEFT JOIN pg_catalog.pg_namespace np ON np.oid = p.prsnamespace\nWHERE p.oid = c.cfgparser\n";
|
|
717
|
+
sql += patternStub(true, "n.nspname", "c.cfgname");
|
|
718
|
+
sql += orderBy("3, 2");
|
|
719
|
+
return {
|
|
720
|
+
sql,
|
|
721
|
+
params: params(),
|
|
722
|
+
description: "List of text search configurations (verbose)"
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
let sql = "SELECT\n n.nspname as \"Schema\",\n c.cfgname as \"Name\",\n pg_catalog.obj_description(c.oid, 'pg_ts_config') as \"Description\"\nFROM pg_catalog.pg_ts_config c\nLEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace\n";
|
|
726
|
+
sql += patternStub(false, "n.nspname", "c.cfgname");
|
|
727
|
+
sql += orderBy("1, 2");
|
|
728
|
+
return {
|
|
729
|
+
sql,
|
|
730
|
+
params: params(),
|
|
731
|
+
description: "List of text search configurations"
|
|
732
|
+
};
|
|
733
|
+
};
|
|
734
|
+
const listForeignDataWrappers = (opts) => {
|
|
735
|
+
const { verbose } = opts;
|
|
736
|
+
let sql = "SELECT fdw.fdwname AS \"Name\",\n pg_catalog.pg_get_userbyid(fdw.fdwowner) AS \"Owner\",\n fdw.fdwhandler::pg_catalog.regproc AS \"Handler\",\n fdw.fdwvalidator::pg_catalog.regproc AS \"Validator\"";
|
|
737
|
+
if (verbose) {
|
|
738
|
+
sql += ",\n " + aclColumn("fdwacl");
|
|
739
|
+
sql += ",\n CASE WHEN fdwoptions IS NULL THEN '' ELSE\n '(' || pg_catalog.array_to_string(ARRAY(SELECT pg_catalog.quote_ident(option_name) || ' ' || pg_catalog.quote_literal(option_value) FROM pg_catalog.pg_options_to_table(fdwoptions)), ', ') || ')'\n END AS \"FDW options\",\n d.description AS \"Description\" ";
|
|
740
|
+
}
|
|
741
|
+
sql += "\nFROM pg_catalog.pg_foreign_data_wrapper fdw\n";
|
|
742
|
+
if (verbose) sql += "LEFT JOIN pg_catalog.pg_description d ON d.classoid = fdw.tableoid AND d.objoid = fdw.oid AND d.objsubid = 0\n";
|
|
743
|
+
sql += patternStub(false, void 0, "fdwname");
|
|
744
|
+
sql += orderBy("1");
|
|
745
|
+
return {
|
|
746
|
+
sql,
|
|
747
|
+
params: params(),
|
|
748
|
+
description: "List of foreign-data wrappers"
|
|
749
|
+
};
|
|
750
|
+
};
|
|
751
|
+
const listForeignServers = (opts) => {
|
|
752
|
+
const { verbose } = opts;
|
|
753
|
+
let sql = "SELECT s.srvname AS \"Name\",\n pg_catalog.pg_get_userbyid(s.srvowner) AS \"Owner\",\n f.fdwname AS \"Foreign-data wrapper\"";
|
|
754
|
+
if (verbose) {
|
|
755
|
+
sql += ",\n " + aclColumn("s.srvacl");
|
|
756
|
+
sql += ",\n s.srvtype AS \"Type\",\n s.srvversion AS \"Version\",\n CASE WHEN srvoptions IS NULL THEN '' ELSE\n '(' || pg_catalog.array_to_string(ARRAY(SELECT pg_catalog.quote_ident(option_name) || ' ' || pg_catalog.quote_literal(option_value) FROM pg_catalog.pg_options_to_table(srvoptions)), ', ') || ')'\n END AS \"FDW options\",\n d.description AS \"Description\"";
|
|
757
|
+
}
|
|
758
|
+
sql += "\nFROM pg_catalog.pg_foreign_server s\n JOIN pg_catalog.pg_foreign_data_wrapper f ON f.oid=s.srvfdw\n";
|
|
759
|
+
if (verbose) sql += "LEFT JOIN pg_catalog.pg_description d ON d.classoid = s.tableoid AND d.objoid = s.oid AND d.objsubid = 0\n";
|
|
760
|
+
sql += patternStub(false, void 0, "s.srvname");
|
|
761
|
+
sql += orderBy("1");
|
|
762
|
+
return {
|
|
763
|
+
sql,
|
|
764
|
+
params: params(),
|
|
765
|
+
description: "List of foreign servers"
|
|
766
|
+
};
|
|
767
|
+
};
|
|
768
|
+
const listUserMappings = (opts) => {
|
|
769
|
+
const { verbose } = opts;
|
|
770
|
+
let sql = "SELECT um.srvname AS \"Server\",\n um.usename AS \"User name\"";
|
|
771
|
+
if (verbose) sql += ",\n CASE WHEN umoptions IS NULL THEN '' ELSE\n '(' || pg_catalog.array_to_string(ARRAY(SELECT pg_catalog.quote_ident(option_name) || ' ' || pg_catalog.quote_literal(option_value) FROM pg_catalog.pg_options_to_table(umoptions)), ', ') || ')'\n END AS \"FDW options\"";
|
|
772
|
+
sql += "\nFROM pg_catalog.pg_user_mappings um\n";
|
|
773
|
+
sql += patternStub(false, void 0, "um.srvname");
|
|
774
|
+
sql += orderBy("1, 2");
|
|
775
|
+
return {
|
|
776
|
+
sql,
|
|
777
|
+
params: params(),
|
|
778
|
+
description: "List of user mappings"
|
|
779
|
+
};
|
|
780
|
+
};
|
|
781
|
+
const listForeignTables = (opts) => {
|
|
782
|
+
const { verbose } = opts;
|
|
783
|
+
let sql = "SELECT n.nspname AS \"Schema\",\n c.relname AS \"Table\",\n s.srvname AS \"Server\"";
|
|
784
|
+
if (verbose) sql += ",\n CASE WHEN ftoptions IS NULL THEN '' ELSE\n '(' || pg_catalog.array_to_string(ARRAY(SELECT pg_catalog.quote_ident(option_name) || ' ' || pg_catalog.quote_literal(option_value) FROM pg_catalog.pg_options_to_table(ftoptions)), ', ') || ')'\n END AS \"FDW options\",\n d.description AS \"Description\"";
|
|
785
|
+
sql += "\nFROM pg_catalog.pg_foreign_table ft\n INNER JOIN pg_catalog.pg_class c ON c.oid = ft.ftrelid\n INNER JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n INNER JOIN pg_catalog.pg_foreign_server s ON s.oid = ft.ftserver\n";
|
|
786
|
+
if (verbose) sql += " LEFT JOIN pg_catalog.pg_description d ON d.classoid = c.tableoid AND d.objoid = c.oid AND d.objsubid = 0\n";
|
|
787
|
+
sql += patternStub(false, "n.nspname", "c.relname");
|
|
788
|
+
sql += orderBy("1, 2");
|
|
789
|
+
return {
|
|
790
|
+
sql,
|
|
791
|
+
params: params(),
|
|
792
|
+
description: "List of foreign tables"
|
|
793
|
+
};
|
|
794
|
+
};
|
|
795
|
+
const listExtensions = (opts) => {
|
|
796
|
+
const { serverVersion } = opts;
|
|
797
|
+
const hasDefaultVersion = serverAtLeast(serverVersion, PG_18);
|
|
798
|
+
let sql = "SELECT e.extname AS \"Name\", e.extversion AS \"Version\", ";
|
|
799
|
+
if (hasDefaultVersion) sql += "ae.default_version AS \"Default version\",";
|
|
800
|
+
sql += "n.nspname AS \"Schema\", d.description AS \"Description\"\nFROM pg_catalog.pg_extension e LEFT JOIN pg_catalog.pg_namespace n ON n.oid = e.extnamespace LEFT JOIN pg_catalog.pg_description d ON d.objoid = e.oid AND d.classoid = 'pg_catalog.pg_extension'::pg_catalog.regclass";
|
|
801
|
+
if (hasDefaultVersion) sql += " LEFT JOIN pg_catalog.pg_available_extensions() ae(name, default_version, comment) ON ae.name = e.extname";
|
|
802
|
+
sql += "\n";
|
|
803
|
+
sql += patternStub(false, void 0, "e.extname");
|
|
804
|
+
sql += orderBy("1");
|
|
805
|
+
return {
|
|
806
|
+
sql,
|
|
807
|
+
params: params(),
|
|
808
|
+
description: "List of installed extensions"
|
|
809
|
+
};
|
|
810
|
+
};
|
|
811
|
+
const listExtensionContents = () => {
|
|
812
|
+
let sql = "SELECT e.extname, e.oid\nFROM pg_catalog.pg_extension e\n";
|
|
813
|
+
sql += patternStub(false, void 0, "e.extname");
|
|
814
|
+
sql += orderBy("1");
|
|
815
|
+
return {
|
|
816
|
+
sql,
|
|
817
|
+
params: params(),
|
|
818
|
+
description: "Get matching extensions to list contents for"
|
|
819
|
+
};
|
|
1690
820
|
};
|
|
1691
821
|
/**
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
return { sql, params: params(), description: "Details of publications" };
|
|
1726
|
-
};
|
|
1727
|
-
/* ------------------------------------------------------------------ */
|
|
1728
|
-
/* \dRs — describeSubscriptions */
|
|
1729
|
-
/* ------------------------------------------------------------------ */
|
|
1730
|
-
export const describeSubscriptions = (opts) => {
|
|
1731
|
-
const { verbose, serverVersion } = opts;
|
|
1732
|
-
if (serverLess(serverVersion, PG_10)) {
|
|
1733
|
-
return {
|
|
1734
|
-
sql: "/* server < 10 does not support subscriptions */ SELECT 1 WHERE false;",
|
|
1735
|
-
params: [],
|
|
1736
|
-
description: "List of subscriptions",
|
|
1737
|
-
};
|
|
1738
|
-
}
|
|
1739
|
-
let sql = 'SELECT subname AS "Name"\n' +
|
|
1740
|
-
', pg_catalog.pg_get_userbyid(subowner) AS "Owner"\n' +
|
|
1741
|
-
', subenabled AS "Enabled"\n' +
|
|
1742
|
-
', subpublications AS "Publication"\n';
|
|
1743
|
-
if (verbose) {
|
|
1744
|
-
if (serverAtLeast(serverVersion, PG_14)) {
|
|
1745
|
-
sql += ', subbinary AS "Binary"\n';
|
|
1746
|
-
if (serverAtLeast(serverVersion, PG_16)) {
|
|
1747
|
-
sql +=
|
|
1748
|
-
", (CASE substream\n" +
|
|
1749
|
-
" WHEN 'f' THEN 'off'\n" +
|
|
1750
|
-
" WHEN 't' THEN 'on'\n" +
|
|
1751
|
-
" WHEN 'p' THEN 'parallel'\n" +
|
|
1752
|
-
' END) AS "Streaming"\n';
|
|
1753
|
-
}
|
|
1754
|
-
else {
|
|
1755
|
-
sql += ', substream AS "Streaming"\n';
|
|
1756
|
-
}
|
|
1757
|
-
}
|
|
1758
|
-
if (serverAtLeast(serverVersion, PG_15)) {
|
|
1759
|
-
sql +=
|
|
1760
|
-
', subtwophasestate AS "Two-phase commit"\n' +
|
|
1761
|
-
', subdisableonerr AS "Disable on error"\n';
|
|
1762
|
-
}
|
|
1763
|
-
if (serverAtLeast(serverVersion, PG_16)) {
|
|
1764
|
-
sql +=
|
|
1765
|
-
', suborigin AS "Origin"\n' +
|
|
1766
|
-
', subpasswordrequired AS "Password required"\n' +
|
|
1767
|
-
', subrunasowner AS "Run as owner?"\n';
|
|
1768
|
-
}
|
|
1769
|
-
if (serverAtLeast(serverVersion, PG_17)) {
|
|
1770
|
-
sql += ', subfailover AS "Failover"\n';
|
|
1771
|
-
}
|
|
1772
|
-
// PG 19 added foreign-server-backed subscriptions and dead-tuple
|
|
1773
|
-
// retention. Upstream surfaces these five columns in `\dRs+`:
|
|
1774
|
-
// the source server name (resolved from subserver), the retention
|
|
1775
|
-
// toggles/limits, and the WAL-receiver timeout (placed after
|
|
1776
|
-
// Conninfo, matching describe.c).
|
|
1777
|
-
if (serverAtLeast(serverVersion, PG_19)) {
|
|
1778
|
-
sql +=
|
|
1779
|
-
', (select srvname from pg_foreign_server where oid=subserver) AS "Server"\n' +
|
|
1780
|
-
', subretaindeadtuples AS "Retain dead tuples"\n' +
|
|
1781
|
-
', submaxretention AS "Max retention duration"\n' +
|
|
1782
|
-
', subretentionactive AS "Retention active"\n';
|
|
1783
|
-
}
|
|
1784
|
-
sql +=
|
|
1785
|
-
', subsynccommit AS "Synchronous commit"\n' +
|
|
1786
|
-
', subconninfo AS "Conninfo"\n';
|
|
1787
|
-
if (serverAtLeast(serverVersion, PG_19)) {
|
|
1788
|
-
sql += ', subwalrcvtimeout AS "Receiver timeout"\n';
|
|
1789
|
-
}
|
|
1790
|
-
if (serverAtLeast(serverVersion, PG_15)) {
|
|
1791
|
-
sql += ', subskiplsn AS "Skip LSN"\n';
|
|
1792
|
-
}
|
|
1793
|
-
sql +=
|
|
1794
|
-
", pg_catalog.obj_description(oid, 'pg_subscription') AS \"Description\"\n";
|
|
1795
|
-
}
|
|
1796
|
-
sql +=
|
|
1797
|
-
"FROM pg_catalog.pg_subscription\n" +
|
|
1798
|
-
"WHERE subdbid = (SELECT oid FROM pg_catalog.pg_database WHERE datname = pg_catalog.current_database())";
|
|
1799
|
-
sql += patternStub(true, undefined, "subname");
|
|
1800
|
-
sql += orderBy("1");
|
|
1801
|
-
return { sql, params: params(), description: "List of subscriptions" };
|
|
1802
|
-
};
|
|
1803
|
-
export const listOperatorClasses = (opts) => {
|
|
1804
|
-
const { verbose } = opts;
|
|
1805
|
-
let sql = 'SELECT\n am.amname AS "AM",\n' +
|
|
1806
|
-
' pg_catalog.format_type(c.opcintype, NULL) AS "Input type",\n' +
|
|
1807
|
-
" CASE\n" +
|
|
1808
|
-
" WHEN c.opckeytype <> 0 AND c.opckeytype <> c.opcintype\n" +
|
|
1809
|
-
" THEN pg_catalog.format_type(c.opckeytype, NULL)\n" +
|
|
1810
|
-
" ELSE NULL\n" +
|
|
1811
|
-
' END AS "Storage type",\n' +
|
|
1812
|
-
" CASE\n" +
|
|
1813
|
-
" WHEN pg_catalog.pg_opclass_is_visible(c.oid)\n" +
|
|
1814
|
-
" THEN pg_catalog.format('%I', c.opcname)\n" +
|
|
1815
|
-
" ELSE pg_catalog.format('%I.%I', n.nspname, c.opcname)\n" +
|
|
1816
|
-
' END AS "Operator class",\n' +
|
|
1817
|
-
" (CASE WHEN c.opcdefault THEN 'yes' ELSE 'no' END) AS \"Default?\"";
|
|
1818
|
-
if (verbose) {
|
|
1819
|
-
sql +=
|
|
1820
|
-
",\n CASE\n" +
|
|
1821
|
-
" WHEN pg_catalog.pg_opfamily_is_visible(of.oid)\n" +
|
|
1822
|
-
" THEN pg_catalog.format('%I', of.opfname)\n" +
|
|
1823
|
-
" ELSE pg_catalog.format('%I.%I', ofn.nspname, of.opfname)\n" +
|
|
1824
|
-
' END AS "Operator family",\n' +
|
|
1825
|
-
' pg_catalog.pg_get_userbyid(c.opcowner) AS "Owner"\n';
|
|
1826
|
-
}
|
|
1827
|
-
sql +=
|
|
1828
|
-
"\nFROM pg_catalog.pg_opclass c\n" +
|
|
1829
|
-
" LEFT JOIN pg_catalog.pg_am am on am.oid = c.opcmethod\n" +
|
|
1830
|
-
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.opcnamespace\n" +
|
|
1831
|
-
" LEFT JOIN pg_catalog.pg_type t ON t.oid = c.opcintype\n" +
|
|
1832
|
-
" LEFT JOIN pg_catalog.pg_namespace tn ON tn.oid = t.typnamespace\n";
|
|
1833
|
-
if (verbose) {
|
|
1834
|
-
sql +=
|
|
1835
|
-
" LEFT JOIN pg_catalog.pg_opfamily of ON of.oid = c.opcfamily\n" +
|
|
1836
|
-
" LEFT JOIN pg_catalog.pg_namespace ofn ON ofn.oid = of.opfnamespace\n";
|
|
1837
|
-
}
|
|
1838
|
-
let hasWhere = false;
|
|
1839
|
-
if (opts.amPattern !== undefined) {
|
|
1840
|
-
sql += patternStub(hasWhere, undefined, "am.amname");
|
|
1841
|
-
hasWhere = true;
|
|
1842
|
-
}
|
|
1843
|
-
if (opts.typePattern !== undefined) {
|
|
1844
|
-
sql += patternStub(hasWhere, "tn.nspname", "t.typname");
|
|
1845
|
-
}
|
|
1846
|
-
sql += orderBy("1, 2, 4");
|
|
1847
|
-
const ps = [];
|
|
1848
|
-
if (opts.amPattern !== undefined)
|
|
1849
|
-
ps.push(opts.amPattern);
|
|
1850
|
-
if (opts.typePattern !== undefined)
|
|
1851
|
-
ps.push(opts.typePattern);
|
|
1852
|
-
return { sql, params: ps, description: "List of operator classes" };
|
|
1853
|
-
};
|
|
1854
|
-
/* ------------------------------------------------------------------ */
|
|
1855
|
-
/* \dAf — listOperatorFamilies */
|
|
1856
|
-
/* ------------------------------------------------------------------ */
|
|
1857
|
-
export const listOperatorFamilies = (opts) => {
|
|
1858
|
-
const { verbose } = opts;
|
|
1859
|
-
let sql = 'SELECT\n am.amname AS "AM",\n' +
|
|
1860
|
-
" CASE\n" +
|
|
1861
|
-
" WHEN pg_catalog.pg_opfamily_is_visible(f.oid)\n" +
|
|
1862
|
-
" THEN pg_catalog.format('%I', f.opfname)\n" +
|
|
1863
|
-
" ELSE pg_catalog.format('%I.%I', n.nspname, f.opfname)\n" +
|
|
1864
|
-
' END AS "Operator family",\n' +
|
|
1865
|
-
" (SELECT\n" +
|
|
1866
|
-
" pg_catalog.string_agg(pg_catalog.format_type(oc.opcintype, NULL), ', ')\n" +
|
|
1867
|
-
" FROM pg_catalog.pg_opclass oc\n" +
|
|
1868
|
-
' WHERE oc.opcfamily = f.oid) "Applicable types"';
|
|
1869
|
-
if (verbose) {
|
|
1870
|
-
sql += ',\n pg_catalog.pg_get_userbyid(f.opfowner) AS "Owner"\n';
|
|
1871
|
-
}
|
|
1872
|
-
sql +=
|
|
1873
|
-
"\nFROM pg_catalog.pg_opfamily f\n" +
|
|
1874
|
-
" LEFT JOIN pg_catalog.pg_am am on am.oid = f.opfmethod\n" +
|
|
1875
|
-
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = f.opfnamespace\n";
|
|
1876
|
-
let hasWhere = false;
|
|
1877
|
-
if (opts.amPattern !== undefined) {
|
|
1878
|
-
sql += patternStub(hasWhere, undefined, "am.amname");
|
|
1879
|
-
hasWhere = true;
|
|
1880
|
-
}
|
|
1881
|
-
if (opts.typePattern !== undefined) {
|
|
1882
|
-
sql +=
|
|
1883
|
-
` ${hasWhere ? "AND" : "WHERE"} EXISTS (\n` +
|
|
1884
|
-
" SELECT 1 FROM pg_catalog.pg_type t\n" +
|
|
1885
|
-
" JOIN pg_catalog.pg_opclass oc ON oc.opcintype = t.oid\n" +
|
|
1886
|
-
" LEFT JOIN pg_catalog.pg_namespace tn ON tn.oid = t.typnamespace\n" +
|
|
1887
|
-
" WHERE oc.opcfamily = f.oid\n" +
|
|
1888
|
-
patternStub(true, "tn.nspname", "t.typname") +
|
|
1889
|
-
" )\n";
|
|
1890
|
-
}
|
|
1891
|
-
sql += orderBy("1, 2");
|
|
1892
|
-
const ps = [];
|
|
1893
|
-
if (opts.amPattern !== undefined)
|
|
1894
|
-
ps.push(opts.amPattern);
|
|
1895
|
-
if (opts.typePattern !== undefined)
|
|
1896
|
-
ps.push(opts.typePattern);
|
|
1897
|
-
return { sql, params: ps, description: "List of operator families" };
|
|
1898
|
-
};
|
|
1899
|
-
export const listOpFamilyOperators = (opts) => {
|
|
1900
|
-
const { verbose, serverVersion } = opts;
|
|
1901
|
-
let sql = 'SELECT\n am.amname AS "AM",\n' +
|
|
1902
|
-
" CASE\n" +
|
|
1903
|
-
" WHEN pg_catalog.pg_opfamily_is_visible(of.oid)\n" +
|
|
1904
|
-
" THEN pg_catalog.format('%I', of.opfname)\n" +
|
|
1905
|
-
" ELSE pg_catalog.format('%I.%I', nsf.nspname, of.opfname)\n" +
|
|
1906
|
-
' END AS "Operator family",\n' +
|
|
1907
|
-
' o.amopopr::pg_catalog.regoperator AS "Operator"\n,' +
|
|
1908
|
-
' o.amopstrategy AS "Strategy",\n' +
|
|
1909
|
-
" CASE o.amoppurpose\n" +
|
|
1910
|
-
" WHEN 'o' THEN 'ordering'\n" +
|
|
1911
|
-
" WHEN 's' THEN 'search'\n" +
|
|
1912
|
-
' END AS "Purpose"\n';
|
|
1913
|
-
if (verbose) {
|
|
1914
|
-
sql += ', ofs.opfname AS "Sort opfamily"';
|
|
1915
|
-
// PG 18 added "Leakproof?" to verbose `\dAo+`. Same pattern as
|
|
1916
|
-
// `\df+` — the operator's underlying function's proleakproof.
|
|
1917
|
-
if (serverAtLeast(serverVersion, PG_18)) {
|
|
1918
|
-
sql +=
|
|
1919
|
-
",\n CASE WHEN p.proleakproof THEN 'yes' ELSE 'no' END AS \"Leakproof?\"";
|
|
1920
|
-
}
|
|
1921
|
-
sql += "\n";
|
|
1922
|
-
}
|
|
1923
|
-
sql +=
|
|
1924
|
-
"FROM pg_catalog.pg_amop o\n" +
|
|
1925
|
-
" LEFT JOIN pg_catalog.pg_opfamily of ON of.oid = o.amopfamily\n" +
|
|
1926
|
-
" LEFT JOIN pg_catalog.pg_am am ON am.oid = of.opfmethod AND am.oid = o.amopmethod\n" +
|
|
1927
|
-
" LEFT JOIN pg_catalog.pg_namespace nsf ON of.opfnamespace = nsf.oid\n";
|
|
1928
|
-
if (verbose) {
|
|
1929
|
-
sql +=
|
|
1930
|
-
" LEFT JOIN pg_catalog.pg_opfamily ofs ON ofs.oid = o.amopsortfamily\n";
|
|
1931
|
-
if (serverAtLeast(serverVersion, PG_18)) {
|
|
1932
|
-
sql +=
|
|
1933
|
-
" LEFT JOIN pg_catalog.pg_operator op ON op.oid = o.amopopr\n" +
|
|
1934
|
-
" LEFT JOIN pg_catalog.pg_proc p ON p.oid = op.oprcode\n";
|
|
1935
|
-
}
|
|
1936
|
-
}
|
|
1937
|
-
let hasWhere = false;
|
|
1938
|
-
if (opts.amPattern !== undefined) {
|
|
1939
|
-
sql += patternStub(hasWhere, undefined, "am.amname");
|
|
1940
|
-
hasWhere = true;
|
|
1941
|
-
}
|
|
1942
|
-
if (opts.familyPattern !== undefined) {
|
|
1943
|
-
sql += patternStub(hasWhere, "nsf.nspname", "of.opfname");
|
|
1944
|
-
}
|
|
1945
|
-
sql +=
|
|
1946
|
-
"ORDER BY 1, 2,\n" +
|
|
1947
|
-
" o.amoplefttype = o.amoprighttype DESC,\n" +
|
|
1948
|
-
" pg_catalog.format_type(o.amoplefttype, NULL),\n" +
|
|
1949
|
-
" pg_catalog.format_type(o.amoprighttype, NULL),\n" +
|
|
1950
|
-
" o.amopstrategy;";
|
|
1951
|
-
const ps = [];
|
|
1952
|
-
if (opts.amPattern !== undefined)
|
|
1953
|
-
ps.push(opts.amPattern);
|
|
1954
|
-
if (opts.familyPattern !== undefined)
|
|
1955
|
-
ps.push(opts.familyPattern);
|
|
1956
|
-
return {
|
|
1957
|
-
sql,
|
|
1958
|
-
params: ps,
|
|
1959
|
-
description: "List of operators of operator families",
|
|
1960
|
-
};
|
|
1961
|
-
};
|
|
1962
|
-
/* ------------------------------------------------------------------ */
|
|
1963
|
-
/* \dAp — listOpFamilyFunctions */
|
|
1964
|
-
/* ------------------------------------------------------------------ */
|
|
1965
|
-
export const listOpFamilyFunctions = (opts) => {
|
|
1966
|
-
const { verbose } = opts;
|
|
1967
|
-
let sql = 'SELECT\n am.amname AS "AM",\n' +
|
|
1968
|
-
" CASE\n" +
|
|
1969
|
-
" WHEN pg_catalog.pg_opfamily_is_visible(of.oid)\n" +
|
|
1970
|
-
" THEN pg_catalog.format('%I', of.opfname)\n" +
|
|
1971
|
-
" ELSE pg_catalog.format('%I.%I', ns.nspname, of.opfname)\n" +
|
|
1972
|
-
' END AS "Operator family",\n' +
|
|
1973
|
-
' pg_catalog.format_type(ap.amproclefttype, NULL) AS "Registered left type",\n' +
|
|
1974
|
-
' pg_catalog.format_type(ap.amprocrighttype, NULL) AS "Registered right type",\n' +
|
|
1975
|
-
' ap.amprocnum AS "Number"\n';
|
|
1976
|
-
sql += verbose
|
|
1977
|
-
? ', ap.amproc::pg_catalog.regprocedure AS "Function"\n'
|
|
1978
|
-
: ', p.proname AS "Function"\n';
|
|
1979
|
-
sql +=
|
|
1980
|
-
"FROM pg_catalog.pg_amproc ap\n" +
|
|
1981
|
-
" LEFT JOIN pg_catalog.pg_opfamily of ON of.oid = ap.amprocfamily\n" +
|
|
1982
|
-
" LEFT JOIN pg_catalog.pg_am am ON am.oid = of.opfmethod\n" +
|
|
1983
|
-
" LEFT JOIN pg_catalog.pg_namespace ns ON of.opfnamespace = ns.oid\n" +
|
|
1984
|
-
" LEFT JOIN pg_catalog.pg_proc p ON ap.amproc = p.oid\n";
|
|
1985
|
-
let hasWhere = false;
|
|
1986
|
-
if (opts.amPattern !== undefined) {
|
|
1987
|
-
sql += patternStub(hasWhere, undefined, "am.amname");
|
|
1988
|
-
hasWhere = true;
|
|
1989
|
-
}
|
|
1990
|
-
if (opts.familyPattern !== undefined) {
|
|
1991
|
-
sql += patternStub(hasWhere, "ns.nspname", "of.opfname");
|
|
1992
|
-
}
|
|
1993
|
-
sql +=
|
|
1994
|
-
"ORDER BY 1, 2,\n ap.amproclefttype = ap.amprocrighttype DESC,\n 3, 4, 5;";
|
|
1995
|
-
const ps = [];
|
|
1996
|
-
if (opts.amPattern !== undefined)
|
|
1997
|
-
ps.push(opts.amPattern);
|
|
1998
|
-
if (opts.familyPattern !== undefined)
|
|
1999
|
-
ps.push(opts.familyPattern);
|
|
2000
|
-
return {
|
|
2001
|
-
sql,
|
|
2002
|
-
params: ps,
|
|
2003
|
-
description: "List of support functions of operator families",
|
|
2004
|
-
};
|
|
2005
|
-
};
|
|
2006
|
-
/* ------------------------------------------------------------------ */
|
|
2007
|
-
/* \dl / \lo_list — listLargeObjects */
|
|
2008
|
-
/* ------------------------------------------------------------------ */
|
|
2009
|
-
export const listLargeObjects = (opts) => {
|
|
2010
|
-
const { verbose } = opts;
|
|
2011
|
-
let sql = 'SELECT oid as "ID",\n pg_catalog.pg_get_userbyid(lomowner) as "Owner",\n ';
|
|
2012
|
-
if (verbose) {
|
|
2013
|
-
sql += aclColumn("lomacl") + ",\n ";
|
|
2014
|
-
}
|
|
2015
|
-
sql +=
|
|
2016
|
-
"pg_catalog.obj_description(oid, 'pg_largeobject') as \"Description\"\n" +
|
|
2017
|
-
"FROM pg_catalog.pg_largeobject_metadata\n" +
|
|
2018
|
-
"ORDER BY oid";
|
|
2019
|
-
return { sql, params: [], description: "Large objects" };
|
|
2020
|
-
};
|
|
2021
|
-
/* ------------------------------------------------------------------ */
|
|
2022
|
-
/* \sf — show function definition */
|
|
2023
|
-
/* \sv — show view definition */
|
|
2024
|
-
/* These are command-level (in command.c) but the SQL is trivial and */
|
|
2025
|
-
/* belongs with the rest of the describe SQL. */
|
|
2026
|
-
/* ------------------------------------------------------------------ */
|
|
822
|
+
* Per-extension contents (`\dx+ foo`). Caller binds the extension oid.
|
|
823
|
+
*/
|
|
824
|
+
const listOneExtensionContents = (opts) => {
|
|
825
|
+
return {
|
|
826
|
+
sql: `SELECT pg_catalog.pg_describe_object(classid, objid, 0) AS "Object description"
|
|
827
|
+
FROM pg_catalog.pg_depend
|
|
828
|
+
WHERE refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass AND refobjid = '${opts.oid}' AND deptype = 'e'\nORDER BY 1;`,
|
|
829
|
+
params: [],
|
|
830
|
+
description: "Objects in extension"
|
|
831
|
+
};
|
|
832
|
+
};
|
|
833
|
+
const listPublications = (opts) => {
|
|
834
|
+
const { serverVersion } = opts;
|
|
835
|
+
if (serverLess(serverVersion, 1e5)) return {
|
|
836
|
+
sql: "/* server < 10 does not support publications */ SELECT 1 WHERE false;",
|
|
837
|
+
params: [],
|
|
838
|
+
description: "List of publications"
|
|
839
|
+
};
|
|
840
|
+
let sql = "SELECT pubname AS \"Name\",\n pg_catalog.pg_get_userbyid(pubowner) AS \"Owner\",\n puballtables AS \"All tables\"";
|
|
841
|
+
if (serverAtLeast(serverVersion, 19e4)) sql += ",\n puballsequences AS \"All sequences\"";
|
|
842
|
+
sql += ",\n pubinsert AS \"Inserts\",\n pubupdate AS \"Updates\",\n pubdelete AS \"Deletes\"";
|
|
843
|
+
if (serverAtLeast(serverVersion, 11e4)) sql += ",\n pubtruncate AS \"Truncates\"";
|
|
844
|
+
if (serverAtLeast(serverVersion, 18e4)) sql += ",\n (CASE pubgencols WHEN 'n' THEN 'none' WHEN 's' THEN 'stored' END) AS \"Generated columns\"";
|
|
845
|
+
if (serverAtLeast(serverVersion, 13e4)) sql += ",\n pubviaroot AS \"Via root\"";
|
|
846
|
+
sql += "\nFROM pg_catalog.pg_publication\n";
|
|
847
|
+
sql += patternStub(false, void 0, "pubname");
|
|
848
|
+
sql += orderBy("1");
|
|
849
|
+
return {
|
|
850
|
+
sql,
|
|
851
|
+
params: params(),
|
|
852
|
+
description: "List of publications"
|
|
853
|
+
};
|
|
854
|
+
};
|
|
2027
855
|
/**
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
856
|
+
* Detail-lookup query for `\dRp+`. Output columns match the unmodified
|
|
857
|
+
* `describePublications` upstream lookup (positional columns are then
|
|
858
|
+
* fanned-out into per-publication detail blocks by WP-20).
|
|
859
|
+
*/
|
|
860
|
+
const describePublications = (opts) => {
|
|
861
|
+
const { serverVersion } = opts;
|
|
862
|
+
if (serverLess(serverVersion, 1e5)) return {
|
|
863
|
+
sql: "/* server < 10 does not support publications */ SELECT 1 WHERE false;",
|
|
864
|
+
params: [],
|
|
865
|
+
description: "Details of publications"
|
|
866
|
+
};
|
|
867
|
+
const hasSeq = serverAtLeast(serverVersion, PG_19);
|
|
868
|
+
const hasTrunc = serverAtLeast(serverVersion, PG_11);
|
|
869
|
+
const hasGen = serverAtLeast(serverVersion, PG_18);
|
|
870
|
+
const hasViaRoot = serverAtLeast(serverVersion, PG_13);
|
|
871
|
+
let sql = "SELECT oid, pubname,\n pg_catalog.pg_get_userbyid(pubowner) AS owner,\n puballtables";
|
|
872
|
+
sql += hasSeq ? ", puballsequences" : ", false AS puballsequences";
|
|
873
|
+
sql += ", pubinsert, pubupdate, pubdelete";
|
|
874
|
+
sql += hasTrunc ? ", pubtruncate" : ", false AS pubtruncate";
|
|
875
|
+
if (hasGen) sql += ", (CASE pubgencols WHEN 'n' THEN 'none' WHEN 's' THEN 'stored' END) AS pubgencols";
|
|
876
|
+
else sql += ", 'none' AS pubgencols";
|
|
877
|
+
sql += hasViaRoot ? ", pubviaroot" : ", false AS pubviaroot";
|
|
878
|
+
sql += ", pg_catalog.obj_description(oid, 'pg_publication')";
|
|
879
|
+
sql += "\nFROM pg_catalog.pg_publication\n";
|
|
880
|
+
sql += patternStub(false, void 0, "pubname");
|
|
881
|
+
sql += orderBy("2");
|
|
882
|
+
return {
|
|
883
|
+
sql,
|
|
884
|
+
params: params(),
|
|
885
|
+
description: "Details of publications"
|
|
886
|
+
};
|
|
887
|
+
};
|
|
888
|
+
const describeSubscriptions = (opts) => {
|
|
889
|
+
const { verbose, serverVersion } = opts;
|
|
890
|
+
if (serverLess(serverVersion, 1e5)) return {
|
|
891
|
+
sql: "/* server < 10 does not support subscriptions */ SELECT 1 WHERE false;",
|
|
892
|
+
params: [],
|
|
893
|
+
description: "List of subscriptions"
|
|
894
|
+
};
|
|
895
|
+
let sql = "SELECT subname AS \"Name\"\n, pg_catalog.pg_get_userbyid(subowner) AS \"Owner\"\n, subenabled AS \"Enabled\"\n, subpublications AS \"Publication\"\n";
|
|
896
|
+
if (verbose) {
|
|
897
|
+
if (serverAtLeast(serverVersion, 14e4)) {
|
|
898
|
+
sql += ", subbinary AS \"Binary\"\n";
|
|
899
|
+
if (serverAtLeast(serverVersion, 16e4)) sql += ", (CASE substream\n WHEN 'f' THEN 'off'\n WHEN 't' THEN 'on'\n WHEN 'p' THEN 'parallel'\n END) AS \"Streaming\"\n";
|
|
900
|
+
else sql += ", substream AS \"Streaming\"\n";
|
|
901
|
+
}
|
|
902
|
+
if (serverAtLeast(serverVersion, 15e4)) sql += ", subtwophasestate AS \"Two-phase commit\"\n, subdisableonerr AS \"Disable on error\"\n";
|
|
903
|
+
if (serverAtLeast(serverVersion, 16e4)) sql += ", suborigin AS \"Origin\"\n, subpasswordrequired AS \"Password required\"\n, subrunasowner AS \"Run as owner?\"\n";
|
|
904
|
+
if (serverAtLeast(serverVersion, 17e4)) sql += ", subfailover AS \"Failover\"\n";
|
|
905
|
+
if (serverAtLeast(serverVersion, 19e4)) sql += ", (select srvname from pg_foreign_server where oid=subserver) AS \"Server\"\n, subretaindeadtuples AS \"Retain dead tuples\"\n, submaxretention AS \"Max retention duration\"\n, subretentionactive AS \"Retention active\"\n";
|
|
906
|
+
sql += ", subsynccommit AS \"Synchronous commit\"\n, subconninfo AS \"Conninfo\"\n";
|
|
907
|
+
if (serverAtLeast(serverVersion, 19e4)) sql += ", subwalrcvtimeout AS \"Receiver timeout\"\n";
|
|
908
|
+
if (serverAtLeast(serverVersion, 15e4)) sql += ", subskiplsn AS \"Skip LSN\"\n";
|
|
909
|
+
sql += ", pg_catalog.obj_description(oid, 'pg_subscription') AS \"Description\"\n";
|
|
910
|
+
}
|
|
911
|
+
sql += "FROM pg_catalog.pg_subscription\nWHERE subdbid = (SELECT oid FROM pg_catalog.pg_database WHERE datname = pg_catalog.current_database())";
|
|
912
|
+
sql += patternStub(true, void 0, "subname");
|
|
913
|
+
sql += orderBy("1");
|
|
914
|
+
return {
|
|
915
|
+
sql,
|
|
916
|
+
params: params(),
|
|
917
|
+
description: "List of subscriptions"
|
|
918
|
+
};
|
|
919
|
+
};
|
|
920
|
+
const listOperatorClasses = (opts) => {
|
|
921
|
+
const { verbose } = opts;
|
|
922
|
+
let sql = "SELECT\n am.amname AS \"AM\",\n pg_catalog.format_type(c.opcintype, NULL) AS \"Input type\",\n CASE\n WHEN c.opckeytype <> 0 AND c.opckeytype <> c.opcintype\n THEN pg_catalog.format_type(c.opckeytype, NULL)\n ELSE NULL\n END AS \"Storage type\",\n CASE\n WHEN pg_catalog.pg_opclass_is_visible(c.oid)\n THEN pg_catalog.format('%I', c.opcname)\n ELSE pg_catalog.format('%I.%I', n.nspname, c.opcname)\n END AS \"Operator class\",\n (CASE WHEN c.opcdefault THEN 'yes' ELSE 'no' END) AS \"Default?\"";
|
|
923
|
+
if (verbose) sql += ",\n CASE\n WHEN pg_catalog.pg_opfamily_is_visible(of.oid)\n THEN pg_catalog.format('%I', of.opfname)\n ELSE pg_catalog.format('%I.%I', ofn.nspname, of.opfname)\n END AS \"Operator family\",\n pg_catalog.pg_get_userbyid(c.opcowner) AS \"Owner\"\n";
|
|
924
|
+
sql += "\nFROM pg_catalog.pg_opclass c\n LEFT JOIN pg_catalog.pg_am am on am.oid = c.opcmethod\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.opcnamespace\n LEFT JOIN pg_catalog.pg_type t ON t.oid = c.opcintype\n LEFT JOIN pg_catalog.pg_namespace tn ON tn.oid = t.typnamespace\n";
|
|
925
|
+
if (verbose) sql += " LEFT JOIN pg_catalog.pg_opfamily of ON of.oid = c.opcfamily\n LEFT JOIN pg_catalog.pg_namespace ofn ON ofn.oid = of.opfnamespace\n";
|
|
926
|
+
let hasWhere = false;
|
|
927
|
+
if (opts.amPattern !== void 0) {
|
|
928
|
+
sql += patternStub(hasWhere, void 0, "am.amname");
|
|
929
|
+
hasWhere = true;
|
|
930
|
+
}
|
|
931
|
+
if (opts.typePattern !== void 0) sql += patternStub(hasWhere, "tn.nspname", "t.typname");
|
|
932
|
+
sql += orderBy("1, 2, 4");
|
|
933
|
+
const ps = [];
|
|
934
|
+
if (opts.amPattern !== void 0) ps.push(opts.amPattern);
|
|
935
|
+
if (opts.typePattern !== void 0) ps.push(opts.typePattern);
|
|
936
|
+
return {
|
|
937
|
+
sql,
|
|
938
|
+
params: ps,
|
|
939
|
+
description: "List of operator classes"
|
|
940
|
+
};
|
|
941
|
+
};
|
|
942
|
+
const listOperatorFamilies = (opts) => {
|
|
943
|
+
const { verbose } = opts;
|
|
944
|
+
let sql = "SELECT\n am.amname AS \"AM\",\n CASE\n WHEN pg_catalog.pg_opfamily_is_visible(f.oid)\n THEN pg_catalog.format('%I', f.opfname)\n ELSE pg_catalog.format('%I.%I', n.nspname, f.opfname)\n END AS \"Operator family\",\n (SELECT\n pg_catalog.string_agg(pg_catalog.format_type(oc.opcintype, NULL), ', ')\n FROM pg_catalog.pg_opclass oc\n WHERE oc.opcfamily = f.oid) \"Applicable types\"";
|
|
945
|
+
if (verbose) sql += ",\n pg_catalog.pg_get_userbyid(f.opfowner) AS \"Owner\"\n";
|
|
946
|
+
sql += "\nFROM pg_catalog.pg_opfamily f\n LEFT JOIN pg_catalog.pg_am am on am.oid = f.opfmethod\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = f.opfnamespace\n";
|
|
947
|
+
let hasWhere = false;
|
|
948
|
+
if (opts.amPattern !== void 0) {
|
|
949
|
+
sql += patternStub(hasWhere, void 0, "am.amname");
|
|
950
|
+
hasWhere = true;
|
|
951
|
+
}
|
|
952
|
+
if (opts.typePattern !== void 0) sql += ` ${hasWhere ? "AND" : "WHERE"} EXISTS (\n SELECT 1 FROM pg_catalog.pg_type t
|
|
953
|
+
JOIN pg_catalog.pg_opclass oc ON oc.opcintype = t.oid
|
|
954
|
+
LEFT JOIN pg_catalog.pg_namespace tn ON tn.oid = t.typnamespace
|
|
955
|
+
WHERE oc.opcfamily = f.oid
|
|
956
|
+
` + patternStub(true, "tn.nspname", "t.typname") + " )\n";
|
|
957
|
+
sql += orderBy("1, 2");
|
|
958
|
+
const ps = [];
|
|
959
|
+
if (opts.amPattern !== void 0) ps.push(opts.amPattern);
|
|
960
|
+
if (opts.typePattern !== void 0) ps.push(opts.typePattern);
|
|
961
|
+
return {
|
|
962
|
+
sql,
|
|
963
|
+
params: ps,
|
|
964
|
+
description: "List of operator families"
|
|
965
|
+
};
|
|
966
|
+
};
|
|
967
|
+
const listOpFamilyOperators = (opts) => {
|
|
968
|
+
const { verbose, serverVersion } = opts;
|
|
969
|
+
let sql = "SELECT\n am.amname AS \"AM\",\n CASE\n WHEN pg_catalog.pg_opfamily_is_visible(of.oid)\n THEN pg_catalog.format('%I', of.opfname)\n ELSE pg_catalog.format('%I.%I', nsf.nspname, of.opfname)\n END AS \"Operator family\",\n o.amopopr::pg_catalog.regoperator AS \"Operator\"\n, o.amopstrategy AS \"Strategy\",\n CASE o.amoppurpose\n WHEN 'o' THEN 'ordering'\n WHEN 's' THEN 'search'\n END AS \"Purpose\"\n";
|
|
970
|
+
if (verbose) {
|
|
971
|
+
sql += ", ofs.opfname AS \"Sort opfamily\"";
|
|
972
|
+
if (serverAtLeast(serverVersion, 18e4)) sql += ",\n CASE WHEN p.proleakproof THEN 'yes' ELSE 'no' END AS \"Leakproof?\"";
|
|
973
|
+
sql += "\n";
|
|
974
|
+
}
|
|
975
|
+
sql += "FROM pg_catalog.pg_amop o\n LEFT JOIN pg_catalog.pg_opfamily of ON of.oid = o.amopfamily\n LEFT JOIN pg_catalog.pg_am am ON am.oid = of.opfmethod AND am.oid = o.amopmethod\n LEFT JOIN pg_catalog.pg_namespace nsf ON of.opfnamespace = nsf.oid\n";
|
|
976
|
+
if (verbose) {
|
|
977
|
+
sql += " LEFT JOIN pg_catalog.pg_opfamily ofs ON ofs.oid = o.amopsortfamily\n";
|
|
978
|
+
if (serverAtLeast(serverVersion, 18e4)) sql += " LEFT JOIN pg_catalog.pg_operator op ON op.oid = o.amopopr\n LEFT JOIN pg_catalog.pg_proc p ON p.oid = op.oprcode\n";
|
|
979
|
+
}
|
|
980
|
+
let hasWhere = false;
|
|
981
|
+
if (opts.amPattern !== void 0) {
|
|
982
|
+
sql += patternStub(hasWhere, void 0, "am.amname");
|
|
983
|
+
hasWhere = true;
|
|
984
|
+
}
|
|
985
|
+
if (opts.familyPattern !== void 0) sql += patternStub(hasWhere, "nsf.nspname", "of.opfname");
|
|
986
|
+
sql += "ORDER BY 1, 2,\n o.amoplefttype = o.amoprighttype DESC,\n pg_catalog.format_type(o.amoplefttype, NULL),\n pg_catalog.format_type(o.amoprighttype, NULL),\n o.amopstrategy;";
|
|
987
|
+
const ps = [];
|
|
988
|
+
if (opts.amPattern !== void 0) ps.push(opts.amPattern);
|
|
989
|
+
if (opts.familyPattern !== void 0) ps.push(opts.familyPattern);
|
|
990
|
+
return {
|
|
991
|
+
sql,
|
|
992
|
+
params: ps,
|
|
993
|
+
description: "List of operators of operator families"
|
|
994
|
+
};
|
|
995
|
+
};
|
|
996
|
+
const listOpFamilyFunctions = (opts) => {
|
|
997
|
+
const { verbose } = opts;
|
|
998
|
+
let sql = "SELECT\n am.amname AS \"AM\",\n CASE\n WHEN pg_catalog.pg_opfamily_is_visible(of.oid)\n THEN pg_catalog.format('%I', of.opfname)\n ELSE pg_catalog.format('%I.%I', ns.nspname, of.opfname)\n END AS \"Operator family\",\n pg_catalog.format_type(ap.amproclefttype, NULL) AS \"Registered left type\",\n pg_catalog.format_type(ap.amprocrighttype, NULL) AS \"Registered right type\",\n ap.amprocnum AS \"Number\"\n";
|
|
999
|
+
sql += verbose ? ", ap.amproc::pg_catalog.regprocedure AS \"Function\"\n" : ", p.proname AS \"Function\"\n";
|
|
1000
|
+
sql += "FROM pg_catalog.pg_amproc ap\n LEFT JOIN pg_catalog.pg_opfamily of ON of.oid = ap.amprocfamily\n LEFT JOIN pg_catalog.pg_am am ON am.oid = of.opfmethod\n LEFT JOIN pg_catalog.pg_namespace ns ON of.opfnamespace = ns.oid\n LEFT JOIN pg_catalog.pg_proc p ON ap.amproc = p.oid\n";
|
|
1001
|
+
let hasWhere = false;
|
|
1002
|
+
if (opts.amPattern !== void 0) {
|
|
1003
|
+
sql += patternStub(hasWhere, void 0, "am.amname");
|
|
1004
|
+
hasWhere = true;
|
|
1005
|
+
}
|
|
1006
|
+
if (opts.familyPattern !== void 0) sql += patternStub(hasWhere, "ns.nspname", "of.opfname");
|
|
1007
|
+
sql += "ORDER BY 1, 2,\n ap.amproclefttype = ap.amprocrighttype DESC,\n 3, 4, 5;";
|
|
1008
|
+
const ps = [];
|
|
1009
|
+
if (opts.amPattern !== void 0) ps.push(opts.amPattern);
|
|
1010
|
+
if (opts.familyPattern !== void 0) ps.push(opts.familyPattern);
|
|
1011
|
+
return {
|
|
1012
|
+
sql,
|
|
1013
|
+
params: ps,
|
|
1014
|
+
description: "List of support functions of operator families"
|
|
1015
|
+
};
|
|
1016
|
+
};
|
|
1017
|
+
const listLargeObjects = (opts) => {
|
|
1018
|
+
const { verbose } = opts;
|
|
1019
|
+
let sql = "SELECT oid as \"ID\",\n pg_catalog.pg_get_userbyid(lomowner) as \"Owner\",\n ";
|
|
1020
|
+
if (verbose) sql += aclColumn("lomacl") + ",\n ";
|
|
1021
|
+
sql += "pg_catalog.obj_description(oid, 'pg_largeobject') as \"Description\"\nFROM pg_catalog.pg_largeobject_metadata\nORDER BY oid";
|
|
1022
|
+
return {
|
|
1023
|
+
sql,
|
|
1024
|
+
params: [],
|
|
1025
|
+
description: "Large objects"
|
|
1026
|
+
};
|
|
2037
1027
|
};
|
|
2038
1028
|
/**
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
/* ------------------------------------------------------------------ */
|
|
1029
|
+
* Look up function OID by name for `\sf` / `\sf+`. Caller renders
|
|
1030
|
+
* `pg_catalog.pg_get_functiondef(oid)` afterwards. The lookup itself
|
|
1031
|
+
* uses regprocedure casting via the placeholder; WP-20 will replace.
|
|
1032
|
+
*/
|
|
1033
|
+
const showFunction = (opts) => {
|
|
1034
|
+
return {
|
|
1035
|
+
sql: `SELECT pg_catalog.pg_get_functiondef('${opts.name.replace(/'/g, "''")}'::pg_catalog.regprocedure) AS def;`,
|
|
1036
|
+
params: [],
|
|
1037
|
+
description: "Function definition"
|
|
1038
|
+
};
|
|
1039
|
+
};
|
|
2051
1040
|
/**
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
* relispartition, reltablespace, relam, spcname, amname.
|
|
2061
|
-
*
|
|
2062
|
-
* Pre-PG 9.5 servers don't expose `relrowsecurity` /
|
|
2063
|
-
* `relforcerowsecurity` / `relispartition`; we synthesize false there.
|
|
2064
|
-
* Pre-PG 12 doesn't carry table AMs in pg_class.relam, so we leave the
|
|
2065
|
-
* amname slot null on those servers.
|
|
2066
|
-
*/
|
|
2067
|
-
export const fetchTableInfo = (opts) => {
|
|
2068
|
-
const { oid, serverVersion } = opts;
|
|
2069
|
-
const hasRowSec = serverAtLeast(serverVersion, PG_9_5);
|
|
2070
|
-
const hasIsPart = serverAtLeast(serverVersion, PG_10);
|
|
2071
|
-
const hasRelAm = serverAtLeast(serverVersion, PG_12);
|
|
2072
|
-
const rowSec = hasRowSec
|
|
2073
|
-
? "c.relrowsecurity, c.relforcerowsecurity"
|
|
2074
|
-
: "false AS relrowsecurity, false AS relforcerowsecurity";
|
|
2075
|
-
const isPart = hasIsPart ? "c.relispartition" : "false AS relispartition";
|
|
2076
|
-
const amCol = hasRelAm ? "c.relam" : "0::oid AS relam";
|
|
2077
|
-
const amName = hasRelAm ? "am.amname" : "NULL::name AS amname";
|
|
2078
|
-
const amJoin = hasRelAm
|
|
2079
|
-
? " LEFT JOIN pg_catalog.pg_am am ON am.oid = c.relam\n"
|
|
2080
|
-
: "";
|
|
2081
|
-
const sql = "SELECT " +
|
|
2082
|
-
rowSec +
|
|
2083
|
-
",\n c.relreplident,\n " +
|
|
2084
|
-
isPart +
|
|
2085
|
-
",\n c.reltablespace,\n " +
|
|
2086
|
-
amCol +
|
|
2087
|
-
",\n ts.spcname,\n " +
|
|
2088
|
-
amName +
|
|
2089
|
-
"\nFROM pg_catalog.pg_class c\n" +
|
|
2090
|
-
" LEFT JOIN pg_catalog.pg_tablespace ts ON ts.oid = c.reltablespace\n" +
|
|
2091
|
-
amJoin +
|
|
2092
|
-
`WHERE c.oid = '${oid}';`;
|
|
2093
|
-
return { sql, params: [], description: "Relation footer info" };
|
|
1041
|
+
* Look up view definition for `\sv` / `\sv+`.
|
|
1042
|
+
*/
|
|
1043
|
+
const showView = (opts) => {
|
|
1044
|
+
return {
|
|
1045
|
+
sql: `SELECT pg_catalog.pg_get_viewdef('${opts.name.replace(/'/g, "''")}'::pg_catalog.regclass, true) AS def;`,
|
|
1046
|
+
params: [],
|
|
1047
|
+
description: "View definition"
|
|
1048
|
+
};
|
|
2094
1049
|
};
|
|
2095
1050
|
/**
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
1051
|
+
* Per-relation table-info query. Returns one row carrying the flags
|
|
1052
|
+
* the formatter needs for the optional footer sections: RLS toggles
|
|
1053
|
+
* (relrowsecurity, relforcerowsecurity), replica-identity char,
|
|
1054
|
+
* partition flag, tablespace oid, access-method oid and pre-joined
|
|
1055
|
+
* pg_tablespace.spcname / pg_am.amname so the formatter doesn't have
|
|
1056
|
+
* to fan out for those.
|
|
1057
|
+
*
|
|
1058
|
+
* Columns: relrowsecurity, relforcerowsecurity, relreplident,
|
|
1059
|
+
* relispartition, reltablespace, relam, spcname, amname.
|
|
1060
|
+
*
|
|
1061
|
+
* Pre-PG 9.5 servers don't expose `relrowsecurity` /
|
|
1062
|
+
* `relforcerowsecurity` / `relispartition`; we synthesize false there.
|
|
1063
|
+
* Pre-PG 12 doesn't carry table AMs in pg_class.relam, so we leave the
|
|
1064
|
+
* amname slot null on those servers.
|
|
1065
|
+
*/
|
|
1066
|
+
const fetchTableInfo = (opts) => {
|
|
1067
|
+
const { oid, serverVersion } = opts;
|
|
1068
|
+
const hasRowSec = serverAtLeast(serverVersion, PG_9_5);
|
|
1069
|
+
const hasIsPart = serverAtLeast(serverVersion, PG_10);
|
|
1070
|
+
const hasRelAm = serverAtLeast(serverVersion, PG_12);
|
|
1071
|
+
const rowSec = hasRowSec ? "c.relrowsecurity, c.relforcerowsecurity" : "false AS relrowsecurity, false AS relforcerowsecurity";
|
|
1072
|
+
const isPart = hasIsPart ? "c.relispartition" : "false AS relispartition";
|
|
1073
|
+
const amCol = hasRelAm ? "c.relam" : "0::oid AS relam";
|
|
1074
|
+
const amName = hasRelAm ? "am.amname" : "NULL::name AS amname";
|
|
1075
|
+
const amJoin = hasRelAm ? " LEFT JOIN pg_catalog.pg_am am ON am.oid = c.relam\n" : "";
|
|
1076
|
+
return {
|
|
1077
|
+
sql: "SELECT " + rowSec + ",\n c.relreplident,\n " + isPart + ",\n c.reltablespace,\n " + amCol + ",\n ts.spcname,\n " + amName + "\nFROM pg_catalog.pg_class c\n LEFT JOIN pg_catalog.pg_tablespace ts ON ts.oid = c.reltablespace\n" + amJoin + `WHERE c.oid = '${oid}';`,
|
|
1078
|
+
params: [],
|
|
1079
|
+
description: "Relation footer info"
|
|
1080
|
+
};
|
|
2123
1081
|
};
|
|
2124
1082
|
/**
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
1083
|
+
* Named NOT NULL constraints (`pg_constraint.contype = 'n'`), introduced
|
|
1084
|
+
* in PG 18. Output columns mirror upstream `describeOneTableDetails`
|
|
1085
|
+
* (describe.c ~3104):
|
|
1086
|
+
* conname, attname, connoinherit, conislocal.
|
|
1087
|
+
*
|
|
1088
|
+
* The constraint references a single column via `conkey[1]`; we join
|
|
1089
|
+
* `pg_attribute` on that attnum and order by it so the footer lists the
|
|
1090
|
+
* constraints in column order. On pre-PG-18 servers the catalog never
|
|
1091
|
+
* carries `contype = 'n'` rows, so the query returns empty and the
|
|
1092
|
+
* caller suppresses the footer — no version branch is needed in the SQL.
|
|
1093
|
+
*/
|
|
1094
|
+
const fetchNotNullConstraints = (opts) => {
|
|
1095
|
+
const { oid, serverVersion } = opts;
|
|
1096
|
+
if (serverLess(serverVersion, 18e4)) return {
|
|
1097
|
+
sql: "SELECT NULL::pg_catalog.text, NULL::pg_catalog.text, false, false WHERE false;",
|
|
1098
|
+
params: [],
|
|
1099
|
+
description: "Not-null constraints"
|
|
1100
|
+
};
|
|
1101
|
+
return {
|
|
1102
|
+
sql: `SELECT co.conname, at.attname, co.connoinherit, co.conislocal
|
|
1103
|
+
FROM pg_catalog.pg_constraint co
|
|
1104
|
+
JOIN pg_catalog.pg_attribute at
|
|
1105
|
+
ON (at.attrelid = co.conrelid AND at.attnum = co.conkey[1])
|
|
1106
|
+
WHERE co.contype = 'n' AND co.conrelid = '${oid}'\nORDER BY at.attnum;`,
|
|
1107
|
+
params: [],
|
|
1108
|
+
description: "Not-null constraints"
|
|
1109
|
+
};
|
|
2152
1110
|
};
|
|
2153
1111
|
/**
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
1112
|
+
* RLS policies for a relation. Output columns mirror upstream:
|
|
1113
|
+
* polname, polpermissive, roles (CSV or NULL), polqual, polwithcheck,
|
|
1114
|
+
* polcmd (mapped to text).
|
|
1115
|
+
*
|
|
1116
|
+
* The polcmd→keyword mapping matches upstream: 'r'→SELECT, 'a'→INSERT,
|
|
1117
|
+
* 'w'→UPDATE, 'd'→DELETE, '*'→NULL (i.e. ALL — emitted as no FOR clause).
|
|
1118
|
+
*/
|
|
1119
|
+
const fetchPolicies = (opts) => {
|
|
1120
|
+
const { oid, serverVersion } = opts;
|
|
1121
|
+
return {
|
|
1122
|
+
sql: "SELECT pol.polname,\n " + (serverAtLeast(serverVersion, 1e5) ? "pol.polpermissive" : "'t' AS polpermissive") + `,
|
|
1123
|
+
CASE WHEN pol.polroles = '{0}' THEN NULL ELSE pg_catalog.array_to_string(array(SELECT rolname FROM pg_catalog.pg_roles WHERE oid = ANY (pol.polroles) ORDER BY 1), ', ') END AS roles,
|
|
1124
|
+
pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS qual,
|
|
1125
|
+
pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS withcheck,
|
|
1126
|
+
CASE pol.polcmd
|
|
1127
|
+
WHEN 'r' THEN 'SELECT'
|
|
1128
|
+
WHEN 'a' THEN 'INSERT'
|
|
1129
|
+
WHEN 'w' THEN 'UPDATE'
|
|
1130
|
+
WHEN 'd' THEN 'DELETE'
|
|
1131
|
+
END AS cmd
|
|
1132
|
+
FROM pg_catalog.pg_policy pol
|
|
1133
|
+
WHERE pol.polrelid = '${oid}'\nORDER BY pol.polname;`,
|
|
1134
|
+
params: [],
|
|
1135
|
+
description: "Relation policies"
|
|
1136
|
+
};
|
|
2167
1137
|
};
|
|
2168
1138
|
/**
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
: "NULL::text";
|
|
2185
|
-
const orderBy = hasPartBound
|
|
2186
|
-
? "pg_catalog.pg_get_expr(c.relpartbound, c.oid) = 'DEFAULT'," +
|
|
2187
|
-
" c.oid::pg_catalog.regclass::pg_catalog.text"
|
|
2188
|
-
: "c.oid::pg_catalog.regclass::pg_catalog.text";
|
|
2189
|
-
const sql = "SELECT c.oid::pg_catalog.regclass, c.relkind,\n " +
|
|
2190
|
-
detachCol +
|
|
2191
|
-
",\n " +
|
|
2192
|
-
boundCol +
|
|
2193
|
-
"\nFROM pg_catalog.pg_class c, pg_catalog.pg_inherits i\n" +
|
|
2194
|
-
`WHERE c.oid = i.inhrelid AND i.inhparent = '${oid}'\n` +
|
|
2195
|
-
`ORDER BY ${orderBy};`;
|
|
2196
|
-
return { sql, params: [], description: "Inheriting / child relations" };
|
|
1139
|
+
* Parents from `pg_inherits`. We exclude partitioned parents so
|
|
1140
|
+
* "Inherits:" only lists genuine inheritance (partition parents go in
|
|
1141
|
+
* "Partition of:" instead). Output: one column with a regclass-formatted
|
|
1142
|
+
* parent name per row.
|
|
1143
|
+
*/
|
|
1144
|
+
const fetchInherits = (opts) => {
|
|
1145
|
+
const { oid } = opts;
|
|
1146
|
+
return {
|
|
1147
|
+
sql: `SELECT c.oid::pg_catalog.regclass
|
|
1148
|
+
FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i
|
|
1149
|
+
WHERE c.oid = i.inhparent AND i.inhrelid = '${oid}'\n AND c.relkind NOT IN ('p', 'I')
|
|
1150
|
+
ORDER BY inhseqno;`,
|
|
1151
|
+
params: [],
|
|
1152
|
+
description: "Inherited-from relations"
|
|
1153
|
+
};
|
|
2197
1154
|
};
|
|
2198
1155
|
/**
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
`WHERE c.oid = '${oid}';`;
|
|
2220
|
-
return { sql, params: [], description: "Partition-of details" };
|
|
1156
|
+
* Child tables / partitions from `pg_inherits`. Output columns:
|
|
1157
|
+
* relname (regclass), relkind, inhdetachpending, partition-bound (or NULL).
|
|
1158
|
+
*
|
|
1159
|
+
* Pre-PG 10 servers don't expose `relpartbound`; pre-PG 14 don't have
|
|
1160
|
+
* `inhdetachpending`. We synthesize NULL / false there.
|
|
1161
|
+
*/
|
|
1162
|
+
const fetchInheritedBy = (opts) => {
|
|
1163
|
+
const { oid, serverVersion } = opts;
|
|
1164
|
+
const hasDetach = serverAtLeast(serverVersion, PG_14);
|
|
1165
|
+
const hasPartBound = serverAtLeast(serverVersion, PG_10);
|
|
1166
|
+
const detachCol = hasDetach ? "i.inhdetachpending" : "false AS inhdetachpending";
|
|
1167
|
+
const boundCol = hasPartBound ? "pg_catalog.pg_get_expr(c.relpartbound, c.oid)" : "NULL::text";
|
|
1168
|
+
const orderBy = hasPartBound ? "pg_catalog.pg_get_expr(c.relpartbound, c.oid) = 'DEFAULT', c.oid::pg_catalog.regclass::pg_catalog.text" : "c.oid::pg_catalog.regclass::pg_catalog.text";
|
|
1169
|
+
return {
|
|
1170
|
+
sql: "SELECT c.oid::pg_catalog.regclass, c.relkind,\n " + detachCol + ",\n " + boundCol + `
|
|
1171
|
+
FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i
|
|
1172
|
+
WHERE c.oid = i.inhrelid AND i.inhparent = '${oid}'\nORDER BY ${orderBy};`,
|
|
1173
|
+
params: [],
|
|
1174
|
+
description: "Inheriting / child relations"
|
|
1175
|
+
};
|
|
2221
1176
|
};
|
|
2222
1177
|
/**
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
1178
|
+
* Partition-of details for a child partition (`relispartition = true`).
|
|
1179
|
+
* Returns parent regclass + partition bound (+ partition constraint when
|
|
1180
|
+
* verbose is requested by the caller). Per upstream, this is invoked
|
|
1181
|
+
* unconditionally for child partitions regardless of verbose, with the
|
|
1182
|
+
* partition-constraint column conditionally selected.
|
|
1183
|
+
*/
|
|
1184
|
+
const fetchPartitionOf = (opts) => {
|
|
1185
|
+
const { oid, serverVersion, withConstraint } = opts;
|
|
1186
|
+
let sql = "SELECT inhparent::pg_catalog.regclass,\n pg_catalog.pg_get_expr(c.relpartbound, c.oid),\n " + (serverAtLeast(serverVersion, 14e4) ? "i.inhdetachpending" : "false AS inhdetachpending");
|
|
1187
|
+
if (withConstraint) sql += ",\n pg_catalog.pg_get_partition_constraintdef(c.oid)";
|
|
1188
|
+
sql += `
|
|
1189
|
+
FROM pg_catalog.pg_class c
|
|
1190
|
+
JOIN pg_catalog.pg_inherits i ON c.oid = i.inhrelid
|
|
1191
|
+
WHERE c.oid = '${oid}';`;
|
|
1192
|
+
return {
|
|
1193
|
+
sql,
|
|
1194
|
+
params: [],
|
|
1195
|
+
description: "Partition-of details"
|
|
1196
|
+
};
|
|
2229
1197
|
};
|
|
2230
1198
|
/**
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
" FROM pg_catalog.pg_options_to_table(ftoptions)), ', ') AS ftoptions\n" +
|
|
2241
|
-
"FROM pg_catalog.pg_foreign_table f,\n" +
|
|
2242
|
-
" pg_catalog.pg_foreign_server s\n" +
|
|
2243
|
-
`WHERE f.ftrelid = '${oid}' AND s.oid = f.ftserver;`;
|
|
2244
|
-
return { sql, params: [], description: "Foreign-table footer info" };
|
|
1199
|
+
* Partition-key definition for a partitioned-table parent
|
|
1200
|
+
* (`relkind = 'p'`). One row, one text column.
|
|
1201
|
+
*/
|
|
1202
|
+
const fetchPartitionKey = (opts) => {
|
|
1203
|
+
return {
|
|
1204
|
+
sql: `SELECT pg_catalog.pg_get_partkeydef('${opts.oid}'::pg_catalog.oid);`,
|
|
1205
|
+
params: [],
|
|
1206
|
+
description: "Partition key"
|
|
1207
|
+
};
|
|
2245
1208
|
};
|
|
2246
1209
|
/**
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
1210
|
+
* Foreign-table footer info: server name + ftoptions as a pre-formatted
|
|
1211
|
+
* "key 'val', key 'val'" string. Two-column single-row result; an empty
|
|
1212
|
+
* options string means no FDW options.
|
|
1213
|
+
*/
|
|
1214
|
+
const fetchForeignTableInfo = (opts) => {
|
|
1215
|
+
const { oid } = opts;
|
|
1216
|
+
return {
|
|
1217
|
+
sql: `SELECT s.srvname,
|
|
1218
|
+
pg_catalog.array_to_string(ARRAY(
|
|
1219
|
+
SELECT pg_catalog.quote_ident(option_name) || ' ' || pg_catalog.quote_literal(option_value)
|
|
1220
|
+
FROM pg_catalog.pg_options_to_table(ftoptions)), ', ') AS ftoptions
|
|
1221
|
+
FROM pg_catalog.pg_foreign_table f,
|
|
1222
|
+
pg_catalog.pg_foreign_server s
|
|
1223
|
+
WHERE f.ftrelid = '${oid}' AND s.oid = f.ftserver;`,
|
|
1224
|
+
params: [],
|
|
1225
|
+
description: "Foreign-table footer info"
|
|
1226
|
+
};
|
|
2258
1227
|
};
|
|
2259
1228
|
/**
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
sql: "/* server < 10 does not support extended statistics */ SELECT 1 WHERE false;",
|
|
2274
|
-
params: [],
|
|
2275
|
-
description: "Statistics objects",
|
|
2276
|
-
};
|
|
2277
|
-
}
|
|
2278
|
-
// `pg_get_statisticsobjdef_columns` was added in PG 14. Older servers
|
|
2279
|
-
// reconstruct the column list from `pg_statistic_ext.stxkeys`.
|
|
2280
|
-
const columnsExpr = serverAtLeast(serverVersion, PG_14)
|
|
2281
|
-
? "pg_catalog.pg_get_statisticsobjdef_columns(es.oid)"
|
|
2282
|
-
: "(SELECT pg_catalog.string_agg(pg_catalog.quote_ident(a.attname), ', ')\n" +
|
|
2283
|
-
" FROM pg_catalog.unnest(es.stxkeys) k(attnum)\n" +
|
|
2284
|
-
" JOIN pg_catalog.pg_attribute a ON a.attrelid = es.stxrelid AND a.attnum = k.attnum AND NOT a.attisdropped)";
|
|
2285
|
-
// `pg_statistic_ext.stxstattarget` exists on every supported PG; PG 17
|
|
2286
|
-
// changed its type from int4 to int2 but we just CAST to text.
|
|
2287
|
-
const sql = "SELECT es.stxnamespace::pg_catalog.regnamespace::pg_catalog.text AS stxnsp,\n" +
|
|
2288
|
-
" es.stxname,\n" +
|
|
2289
|
-
" 'd' = any(es.stxkind) AS ndist_enabled,\n" +
|
|
2290
|
-
" 'f' = any(es.stxkind) AS deps_enabled,\n" +
|
|
2291
|
-
" 'm' = any(es.stxkind) AS mcv_enabled,\n" +
|
|
2292
|
-
" " +
|
|
2293
|
-
columnsExpr +
|
|
2294
|
-
" AS columns,\n" +
|
|
2295
|
-
" es.stxrelid::pg_catalog.regclass::pg_catalog.text AS stxrelname,\n" +
|
|
2296
|
-
" es.stxstattarget\n" +
|
|
2297
|
-
"FROM pg_catalog.pg_statistic_ext es\n" +
|
|
2298
|
-
`WHERE es.stxrelid = '${oid}'\n` +
|
|
2299
|
-
"ORDER BY stxnsp, es.stxname;";
|
|
2300
|
-
return { sql, params: [], description: "Statistics objects" };
|
|
1229
|
+
* Pull `indexrelid::regclass` for the index marked as REPLICA IDENTITY
|
|
1230
|
+
* on this relation. Returns at most one row when relreplident = 'i'.
|
|
1231
|
+
*/
|
|
1232
|
+
const fetchReplicaIdentityIndex = (opts) => {
|
|
1233
|
+
const { oid } = opts;
|
|
1234
|
+
return {
|
|
1235
|
+
sql: `SELECT c2.relname
|
|
1236
|
+
FROM pg_catalog.pg_index i
|
|
1237
|
+
JOIN pg_catalog.pg_class c2 ON c2.oid = i.indexrelid
|
|
1238
|
+
WHERE i.indrelid = '${oid}' AND i.indisreplident\nLIMIT 1;`,
|
|
1239
|
+
params: [],
|
|
1240
|
+
description: "Replica-identity index"
|
|
1241
|
+
};
|
|
2301
1242
|
};
|
|
2302
1243
|
/**
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
let sql = "SELECT pub.pubname\n" +
|
|
2329
|
-
"FROM pg_catalog.pg_publication pub\n" +
|
|
2330
|
-
"WHERE pub.puballtables\n" +
|
|
2331
|
-
" OR EXISTS (\n" +
|
|
2332
|
-
" SELECT 1 FROM pg_catalog.pg_publication_rel pr\n" +
|
|
2333
|
-
` WHERE pr.prpubid = pub.oid AND pr.prrelid = '${oid}'${exceptGuard}\n` +
|
|
2334
|
-
" )";
|
|
2335
|
-
if (hasPubNs) {
|
|
2336
|
-
sql +=
|
|
2337
|
-
"\n OR EXISTS (\n" +
|
|
2338
|
-
" SELECT 1 FROM pg_catalog.pg_publication_namespace pn\n" +
|
|
2339
|
-
` JOIN pg_catalog.pg_class c ON c.oid = '${oid}'\n` +
|
|
2340
|
-
" WHERE pn.pnpubid = pub.oid AND pn.pnnspid = c.relnamespace\n" +
|
|
2341
|
-
" )";
|
|
2342
|
-
}
|
|
2343
|
-
sql += "\nORDER BY 1;";
|
|
2344
|
-
return { sql, params: [], description: "Table publications" };
|
|
1244
|
+
* Extended-statistics objects defined on a relation. Mirrors the upstream
|
|
1245
|
+
* verbose-only `\d+` section. Output columns:
|
|
1246
|
+
* stxnsp, stxname, ndist_enabled, deps_enabled, mcv_enabled, columns,
|
|
1247
|
+
* stxrelname, stxstattarget.
|
|
1248
|
+
*
|
|
1249
|
+
* Only meaningful on PG 10+ (the catalog table `pg_statistic_ext` doesn't
|
|
1250
|
+
* exist before then). Caller gates by `relkind in ('r','m','p','f')` and
|
|
1251
|
+
* verbose mode.
|
|
1252
|
+
*/
|
|
1253
|
+
const fetchStatisticsObjects = (opts) => {
|
|
1254
|
+
const { oid, serverVersion } = opts;
|
|
1255
|
+
if (serverLess(serverVersion, 1e5)) return {
|
|
1256
|
+
sql: "/* server < 10 does not support extended statistics */ SELECT 1 WHERE false;",
|
|
1257
|
+
params: [],
|
|
1258
|
+
description: "Statistics objects"
|
|
1259
|
+
};
|
|
1260
|
+
return {
|
|
1261
|
+
sql: "SELECT es.stxnamespace::pg_catalog.regnamespace::pg_catalog.text AS stxnsp,\n es.stxname,\n 'd' = any(es.stxkind) AS ndist_enabled,\n 'f' = any(es.stxkind) AS deps_enabled,\n 'm' = any(es.stxkind) AS mcv_enabled,\n " + (serverAtLeast(serverVersion, 14e4) ? "pg_catalog.pg_get_statisticsobjdef_columns(es.oid)" : "(SELECT pg_catalog.string_agg(pg_catalog.quote_ident(a.attname), ', ')\n FROM pg_catalog.unnest(es.stxkeys) k(attnum)\n JOIN pg_catalog.pg_attribute a ON a.attrelid = es.stxrelid AND a.attnum = k.attnum AND NOT a.attisdropped)") + ` AS columns,
|
|
1262
|
+
es.stxrelid::pg_catalog.regclass::pg_catalog.text AS stxrelname,
|
|
1263
|
+
es.stxstattarget
|
|
1264
|
+
FROM pg_catalog.pg_statistic_ext es
|
|
1265
|
+
WHERE es.stxrelid = '${oid}'\nORDER BY stxnsp, es.stxname;`,
|
|
1266
|
+
params: [],
|
|
1267
|
+
description: "Statistics objects"
|
|
1268
|
+
};
|
|
2345
1269
|
};
|
|
2346
1270
|
/**
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
1271
|
+
* Publications a relation belongs to. Returns one column `pubname` per
|
|
1272
|
+
* publication. Covers the three sources upstream considers:
|
|
1273
|
+
* - explicit `pg_publication_rel` membership
|
|
1274
|
+
* - `puballtables` (FOR ALL TABLES)
|
|
1275
|
+
* - `pg_publication_namespace` (FOR ALL TABLES IN SCHEMA, PG 15+)
|
|
1276
|
+
*
|
|
1277
|
+
* Pre-PG 10 servers return an empty set (publications don't exist).
|
|
1278
|
+
*/
|
|
1279
|
+
const fetchTablePublications = (opts) => {
|
|
1280
|
+
const { oid, serverVersion } = opts;
|
|
1281
|
+
if (serverLess(serverVersion, 1e5)) return {
|
|
1282
|
+
sql: "/* server < 10 does not support publications */ SELECT 1 WHERE false;",
|
|
1283
|
+
params: [],
|
|
1284
|
+
description: "Table publications"
|
|
1285
|
+
};
|
|
1286
|
+
const hasPubNs = serverAtLeast(serverVersion, PG_15);
|
|
1287
|
+
let sql = `SELECT pub.pubname
|
|
1288
|
+
FROM pg_catalog.pg_publication pub
|
|
1289
|
+
WHERE pub.puballtables
|
|
1290
|
+
OR EXISTS (
|
|
1291
|
+
SELECT 1 FROM pg_catalog.pg_publication_rel pr
|
|
1292
|
+
WHERE pr.prpubid = pub.oid AND pr.prrelid = '${oid}'${serverAtLeast(serverVersion, 19e4) ? " AND NOT pr.prexcept" : ""}\n )`;
|
|
1293
|
+
if (hasPubNs) sql += `
|
|
1294
|
+
OR EXISTS (
|
|
1295
|
+
SELECT 1 FROM pg_catalog.pg_publication_namespace pn
|
|
1296
|
+
JOIN pg_catalog.pg_class c ON c.oid = '${oid}'\n WHERE pn.pnpubid = pub.oid AND pn.pnnspid = c.relnamespace
|
|
1297
|
+
)`;
|
|
1298
|
+
sql += "\nORDER BY 1;";
|
|
1299
|
+
return {
|
|
1300
|
+
sql,
|
|
1301
|
+
params: [],
|
|
1302
|
+
description: "Table publications"
|
|
1303
|
+
};
|
|
2369
1304
|
};
|
|
2370
1305
|
/**
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
`WHERE (pr.prrelid = '${oid}' OR pr.prrelid = pg_catalog.pg_partition_root('${oid}'))\n` +
|
|
2394
|
-
"AND pr.prexcept\n" +
|
|
2395
|
-
"ORDER BY 1;";
|
|
2396
|
-
return { sql, params: [], description: "Excluded from publications" };
|
|
1306
|
+
* Subscriptions that include this relation. Mirrors the upstream
|
|
1307
|
+
* `\d+` section. Requires read access to `pg_subscription`, which is
|
|
1308
|
+
* only granted to superusers — the formatter must swallow
|
|
1309
|
+
* permission-denied errors silently.
|
|
1310
|
+
*
|
|
1311
|
+
* Pre-PG 10 servers return an empty set.
|
|
1312
|
+
*/
|
|
1313
|
+
const fetchTableSubscriptions = (opts) => {
|
|
1314
|
+
const { oid, serverVersion } = opts;
|
|
1315
|
+
if (serverLess(serverVersion, 1e5)) return {
|
|
1316
|
+
sql: "/* server < 10 does not support subscriptions */ SELECT 1 WHERE false;",
|
|
1317
|
+
params: [],
|
|
1318
|
+
description: "Table subscriptions"
|
|
1319
|
+
};
|
|
1320
|
+
return {
|
|
1321
|
+
sql: `SELECT sub.subname
|
|
1322
|
+
FROM pg_catalog.pg_subscription sub
|
|
1323
|
+
JOIN pg_catalog.pg_subscription_rel sr ON sr.srsubid = sub.oid
|
|
1324
|
+
WHERE sr.srrelid = '${oid}'\nORDER BY 1;`,
|
|
1325
|
+
params: [],
|
|
1326
|
+
description: "Table subscriptions"
|
|
1327
|
+
};
|
|
2397
1328
|
};
|
|
2398
1329
|
/**
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
1330
|
+
* Publications that exclude this relation via a FOR ALL TABLES ... EXCEPT
|
|
1331
|
+
* clause (PG 19+, `pg_publication_rel.prexcept`). Mirrors the upstream
|
|
1332
|
+
* "Excluded from publications:" footer in `describeOneTableDetails`.
|
|
1333
|
+
* Considers the partition root as well, since an EXCEPT can be declared on
|
|
1334
|
+
* the root of a partitioned table.
|
|
1335
|
+
*
|
|
1336
|
+
* Returns an empty set on servers older than PG 19 (the column and the
|
|
1337
|
+
* feature don't exist), so the caller suppresses the footer without a
|
|
1338
|
+
* separate version branch at the call site.
|
|
1339
|
+
*/
|
|
1340
|
+
const fetchExcludedFromPublications = (opts) => {
|
|
1341
|
+
const { oid, serverVersion } = opts;
|
|
1342
|
+
if (serverLess(serverVersion, 19e4)) return {
|
|
1343
|
+
sql: "/* server < 19 does not support publication EXCEPT lists */ SELECT 1 WHERE false;",
|
|
1344
|
+
params: [],
|
|
1345
|
+
description: "Excluded from publications"
|
|
1346
|
+
};
|
|
1347
|
+
return {
|
|
1348
|
+
sql: `SELECT pubname
|
|
1349
|
+
FROM pg_catalog.pg_publication p
|
|
1350
|
+
JOIN pg_catalog.pg_publication_rel pr ON p.oid = pr.prpubid
|
|
1351
|
+
WHERE (pr.prrelid = '${oid}' OR pr.prrelid = pg_catalog.pg_partition_root('${oid}'))\nAND pr.prexcept
|
|
1352
|
+
ORDER BY 1;`,
|
|
1353
|
+
params: [],
|
|
1354
|
+
description: "Excluded from publications"
|
|
1355
|
+
};
|
|
2421
1356
|
};
|
|
2422
1357
|
/**
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
1358
|
+
* Publications a sequence belongs to. PG 19 added sequence replication
|
|
1359
|
+
* (`pg_publication.puballsequences`); a sequence is included when a
|
|
1360
|
+
* publication is declared FOR ALL SEQUENCES and the sequence itself is
|
|
1361
|
+
* publishable. Mirrors the "Included in publications:" footer emitted for
|
|
1362
|
+
* sequences in upstream `describeOneTableDetails`.
|
|
1363
|
+
*
|
|
1364
|
+
* Returns an empty set on servers older than PG 19.
|
|
1365
|
+
*/
|
|
1366
|
+
const fetchSequencePublications = (opts) => {
|
|
1367
|
+
const { oid, serverVersion } = opts;
|
|
1368
|
+
if (serverLess(serverVersion, 19e4)) return {
|
|
1369
|
+
sql: "/* server < 19 does not support sequence publications */ SELECT 1 WHERE false;",
|
|
1370
|
+
params: [],
|
|
1371
|
+
description: "Sequence publications"
|
|
1372
|
+
};
|
|
1373
|
+
return {
|
|
1374
|
+
sql: `SELECT pubname FROM pg_catalog.pg_publication p
|
|
1375
|
+
WHERE p.puballsequences
|
|
1376
|
+
AND pg_catalog.pg_relation_is_publishable('${oid}')\nORDER BY 1;`,
|
|
1377
|
+
params: [],
|
|
1378
|
+
description: "Sequence publications"
|
|
1379
|
+
};
|
|
2440
1380
|
};
|
|
2441
1381
|
/**
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
1382
|
+
* Per-column FDW options for a foreign table. Returns one row per column
|
|
1383
|
+
* that has at least one `attfdwoptions` entry. Output columns:
|
|
1384
|
+
* attname, opts (pre-formatted "k 'v', k 'v'").
|
|
1385
|
+
*
|
|
1386
|
+
* Only meaningful for `relkind = 'f'`.
|
|
1387
|
+
*/
|
|
1388
|
+
const fetchPerColumnFdwOptions = (opts) => {
|
|
1389
|
+
const { oid } = opts;
|
|
1390
|
+
return {
|
|
1391
|
+
sql: `SELECT a.attname,
|
|
1392
|
+
pg_catalog.array_to_string(ARRAY(
|
|
1393
|
+
SELECT pg_catalog.quote_ident(option_name) || ' ' || pg_catalog.quote_literal(option_value)
|
|
1394
|
+
FROM pg_catalog.pg_options_to_table(a.attfdwoptions)), ', ') AS opts
|
|
1395
|
+
FROM pg_catalog.pg_attribute a
|
|
1396
|
+
WHERE a.attrelid = '${oid}' AND a.attnum > 0 AND NOT a.attisdropped\n AND a.attfdwoptions IS NOT NULL
|
|
1397
|
+
ORDER BY a.attnum;`,
|
|
1398
|
+
params: [],
|
|
1399
|
+
description: "Per-column FDW options"
|
|
1400
|
+
};
|
|
2452
1401
|
};
|
|
1402
|
+
/**
|
|
1403
|
+
* For a TOAST table (`relkind = 't'`), look up the owning user table.
|
|
1404
|
+
* Returns at most one row with the parent's regclass-formatted name.
|
|
1405
|
+
*/
|
|
1406
|
+
const fetchToastOwningTable = (opts) => {
|
|
1407
|
+
const { oid } = opts;
|
|
1408
|
+
return {
|
|
1409
|
+
sql: `SELECT oid::pg_catalog.regclass::pg_catalog.text AS relname
|
|
1410
|
+
FROM pg_catalog.pg_class
|
|
1411
|
+
WHERE reltoastrelid = '${oid}'\nLIMIT 1;`,
|
|
1412
|
+
params: [],
|
|
1413
|
+
description: "TOAST owning table"
|
|
1414
|
+
};
|
|
1415
|
+
};
|
|
1416
|
+
//#endregion
|
|
1417
|
+
export { describeAccessMethods, describeAggregates, describeConfigurationParameters, describeFunctions, describeOneTSParser, describeOperators, describePublications, describeRoleGrants, describeRoles, describeSubscriptions, describeTableDetails, describeTablespaces, describeTypes, fetchExcludedFromPublications, fetchForeignTableInfo, fetchInheritedBy, fetchInherits, fetchNotNullConstraints, fetchPartitionKey, fetchPartitionOf, fetchPerColumnFdwOptions, fetchPolicies, fetchReplicaIdentityIndex, fetchSequencePublications, fetchStatisticsObjects, fetchTableInfo, fetchTablePublications, fetchTableSubscriptions, fetchToastOwningTable, listAllDbs, listCasts, listCollations, listConversions, listDbRoleSettings, listDefaultACLs, listDomains, listEventTriggers, listExtendedStats, listExtensionContents, listExtensions, listForeignDataWrappers, listForeignServers, listForeignTables, listLanguages, listLargeObjects, listOneExtensionContents, listOpFamilyFunctions, listOpFamilyOperators, listOperatorClasses, listOperatorFamilies, listPartitionedTables, listPublications, listSchemas, listTSConfigs, listTSDictionaries, listTSParsers, listTSTemplates, listTables, listUserMappings, objectDescription, permissionsList, showFunction, showView };
|