vgi-python 0.8.0__py3-none-any.whl
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.
- vgi/__init__.py +152 -0
- vgi/_duckdb.py +62 -0
- vgi/_storage_profile.py +132 -0
- vgi/_test_fixtures/__init__.py +20 -0
- vgi/_test_fixtures/accumulate/__init__.py +19 -0
- vgi/_test_fixtures/accumulate/worker.py +762 -0
- vgi/_test_fixtures/aggregate/__init__.py +62 -0
- vgi/_test_fixtures/aggregate/_common.py +21 -0
- vgi/_test_fixtures/aggregate/basic.py +232 -0
- vgi/_test_fixtures/aggregate/dynamic.py +409 -0
- vgi/_test_fixtures/aggregate/generic.py +86 -0
- vgi/_test_fixtures/aggregate/listagg.py +71 -0
- vgi/_test_fixtures/aggregate/percentile.py +107 -0
- vgi/_test_fixtures/aggregate/streaming.py +192 -0
- vgi/_test_fixtures/aggregate/varargs.py +75 -0
- vgi/_test_fixtures/aggregate/window.py +380 -0
- vgi/_test_fixtures/attach_options.py +308 -0
- vgi/_test_fixtures/bad_protocol.py +62 -0
- vgi/_test_fixtures/cancellable.py +336 -0
- vgi/_test_fixtures/catalog.py +813 -0
- vgi/_test_fixtures/http_server.py +394 -0
- vgi/_test_fixtures/nest_tensor.py +614 -0
- vgi/_test_fixtures/orchard_catalog.py +47 -0
- vgi/_test_fixtures/projection_repro/__init__.py +6 -0
- vgi/_test_fixtures/projection_repro/worker.py +454 -0
- vgi/_test_fixtures/scalar/__init__.py +116 -0
- vgi/_test_fixtures/scalar/_common.py +69 -0
- vgi/_test_fixtures/scalar/arithmetic.py +321 -0
- vgi/_test_fixtures/scalar/binary.py +120 -0
- vgi/_test_fixtures/scalar/formatting.py +176 -0
- vgi/_test_fixtures/scalar/geo.py +300 -0
- vgi/_test_fixtures/scalar/null_handling.py +107 -0
- vgi/_test_fixtures/scalar/random_demo.py +171 -0
- vgi/_test_fixtures/scalar/settings_secrets.py +102 -0
- vgi/_test_fixtures/scalar/type_info.py +219 -0
- vgi/_test_fixtures/schema_reconcile/__init__.py +29 -0
- vgi/_test_fixtures/schema_reconcile/worker.py +653 -0
- vgi/_test_fixtures/simple_writable.py +793 -0
- vgi/_test_fixtures/table/__init__.py +221 -0
- vgi/_test_fixtures/table/_common.py +162 -0
- vgi/_test_fixtures/table/batch_index.py +283 -0
- vgi/_test_fixtures/table/batch_index_broken.py +200 -0
- vgi/_test_fixtures/table/catalog_scans.py +162 -0
- vgi/_test_fixtures/table/filters.py +1005 -0
- vgi/_test_fixtures/table/late_materialization.py +249 -0
- vgi/_test_fixtures/table/make_series.py +273 -0
- vgi/_test_fixtures/table/misc.py +499 -0
- vgi/_test_fixtures/table/order_modes.py +164 -0
- vgi/_test_fixtures/table/pairs.py +437 -0
- vgi/_test_fixtures/table/partition_columns.py +472 -0
- vgi/_test_fixtures/table/partition_columns_broken.py +304 -0
- vgi/_test_fixtures/table/profiling_example.py +195 -0
- vgi/_test_fixtures/table/required_filters.py +234 -0
- vgi/_test_fixtures/table/sequence.py +710 -0
- vgi/_test_fixtures/table/settings.py +426 -0
- vgi/_test_fixtures/table/transaction_storage.py +162 -0
- vgi/_test_fixtures/table/tt_pushdown.py +191 -0
- vgi/_test_fixtures/table/versioned.py +230 -0
- vgi/_test_fixtures/table_in_out.py +1392 -0
- vgi/_test_fixtures/versioned.py +155 -0
- vgi/_test_fixtures/versioned_tables.py +595 -0
- vgi/_test_fixtures/worker.py +1631 -0
- vgi/_test_fixtures/writable/__init__.py +8 -0
- vgi/_test_fixtures/writable/generic.py +236 -0
- vgi/_test_fixtures/writable/table.py +149 -0
- vgi/_test_fixtures/writable/worker.py +1148 -0
- vgi/aggregate_function.py +607 -0
- vgi/argument_spec.py +472 -0
- vgi/arguments.py +1747 -0
- vgi/auth.py +55 -0
- vgi/catalog/__init__.py +88 -0
- vgi/catalog/attach_option.py +206 -0
- vgi/catalog/catalog_interface.py +2767 -0
- vgi/catalog/descriptors.py +870 -0
- vgi/catalog/duckdb_statistics.py +377 -0
- vgi/catalog/secret_type.py +96 -0
- vgi/catalog/setting.py +253 -0
- vgi/catalog/storage.py +372 -0
- vgi/client/__init__.py +67 -0
- vgi/client/catalog_mixin.py +1251 -0
- vgi/client/cli.py +582 -0
- vgi/client/cli_catalog.py +182 -0
- vgi/client/cli_schema.py +270 -0
- vgi/client/cli_table.py +907 -0
- vgi/client/cli_transaction.py +97 -0
- vgi/client/cli_utils.py +441 -0
- vgi/client/cli_view.py +303 -0
- vgi/client/client.py +2183 -0
- vgi/exceptions.py +205 -0
- vgi/function.py +245 -0
- vgi/function_storage.py +1636 -0
- vgi/function_storage_azure_sql.py +922 -0
- vgi/function_storage_cf_do.py +740 -0
- vgi/http/__init__.py +25 -0
- vgi/http/demo_storage.py +212 -0
- vgi/http/worker_page.py +1252 -0
- vgi/invocation.py +154 -0
- vgi/logging_config.py +93 -0
- vgi/meta_worker.py +661 -0
- vgi/metadata.py +1403 -0
- vgi/otel.py +406 -0
- vgi/protocol.py +2418 -0
- vgi/protocol_version.txt +1 -0
- vgi/py.typed +0 -0
- vgi/scalar_function.py +1211 -0
- vgi/schema_utils.py +234 -0
- vgi/secret_protocol.py +124 -0
- vgi/secret_service.py +238 -0
- vgi/serve.py +769 -0
- vgi/table_buffering_function.py +443 -0
- vgi/table_filter_pushdown.py +1528 -0
- vgi/table_function.py +1130 -0
- vgi/table_in_out_function.py +383 -0
- vgi/transactor/__init__.py +24 -0
- vgi/transactor/_duckdb_compat.py +27 -0
- vgi/transactor/client.py +137 -0
- vgi/transactor/protocol.py +149 -0
- vgi/transactor/server.py +740 -0
- vgi/worker.py +4761 -0
- vgi_python-0.8.0.dist-info/METADATA +735 -0
- vgi_python-0.8.0.dist-info/RECORD +124 -0
- vgi_python-0.8.0.dist-info/WHEEL +4 -0
- vgi_python-0.8.0.dist-info/entry_points.txt +5 -0
- vgi_python-0.8.0.dist-info/licenses/LICENSE +134 -0
vgi/client/cli_table.py
ADDED
|
@@ -0,0 +1,907 @@
|
|
|
1
|
+
# Copyright 2025, 2026 Query Farm LLC - https://query.farm
|
|
2
|
+
|
|
3
|
+
"""Table CLI commands for VGI.
|
|
4
|
+
|
|
5
|
+
This module provides CLI commands for table operations:
|
|
6
|
+
- get: Get table info
|
|
7
|
+
- create: Create a new table
|
|
8
|
+
- drop: Drop a table
|
|
9
|
+
- rename: Rename a table
|
|
10
|
+
- comment: Set or clear table comment
|
|
11
|
+
- scan-function: Get scan function for a table
|
|
12
|
+
- column: Column subcommands (add, drop, rename, etc.)
|
|
13
|
+
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import click
|
|
19
|
+
|
|
20
|
+
from vgi.catalog import OnConflict, SerializedSchema, SqlExpression
|
|
21
|
+
from vgi.client.cli_utils import (
|
|
22
|
+
get_attach_opaque_data_from_options,
|
|
23
|
+
hex_to_transaction_opaque_data,
|
|
24
|
+
json_to_arrow_schema,
|
|
25
|
+
output_json,
|
|
26
|
+
parse_json_option,
|
|
27
|
+
scan_function_result_to_dict,
|
|
28
|
+
table_info_to_dict,
|
|
29
|
+
)
|
|
30
|
+
from vgi.client.client import Client
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@click.group()
|
|
34
|
+
def table() -> None:
|
|
35
|
+
"""Manage tables in a schema."""
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@table.command("get")
|
|
39
|
+
@click.argument("schema_name")
|
|
40
|
+
@click.argument("name")
|
|
41
|
+
@click.option("--attach-opaque-data", help="Hex-encoded attach ID")
|
|
42
|
+
@click.option("--catalog", "catalog_name", help="Catalog name for auto-attach")
|
|
43
|
+
@click.option("--attach-options", default="{}", help="Attach options as JSON")
|
|
44
|
+
@click.option("--worker", "-w", required=True, help="VGI worker command")
|
|
45
|
+
@click.option("--transaction-opaque-data", help="Transaction ID (hex) for transactional read")
|
|
46
|
+
def table_get(
|
|
47
|
+
schema_name: str,
|
|
48
|
+
name: str,
|
|
49
|
+
attach_opaque_data: str | None,
|
|
50
|
+
catalog_name: str | None,
|
|
51
|
+
attach_options: str,
|
|
52
|
+
worker: str,
|
|
53
|
+
transaction_opaque_data: str | None,
|
|
54
|
+
) -> None:
|
|
55
|
+
"""Get information about a table.
|
|
56
|
+
|
|
57
|
+
SCHEMA_NAME is the schema containing the table.
|
|
58
|
+
NAME is the table name.
|
|
59
|
+
|
|
60
|
+
"""
|
|
61
|
+
client = Client(worker)
|
|
62
|
+
opts = parse_json_option(attach_options, "--attach-options")
|
|
63
|
+
resolved_attach_opaque_data, is_stateful = get_attach_opaque_data_from_options(
|
|
64
|
+
client, attach_opaque_data, catalog_name, opts
|
|
65
|
+
)
|
|
66
|
+
if is_stateful and catalog_name:
|
|
67
|
+
click.echo(
|
|
68
|
+
"Warning: Using --catalog with a stateful catalog. "
|
|
69
|
+
"Consider using --attach-opaque-data for session persistence.",
|
|
70
|
+
err=True,
|
|
71
|
+
)
|
|
72
|
+
table_info = client.table_get(
|
|
73
|
+
attach_opaque_data=resolved_attach_opaque_data,
|
|
74
|
+
transaction_opaque_data=(
|
|
75
|
+
hex_to_transaction_opaque_data(transaction_opaque_data) if transaction_opaque_data else None
|
|
76
|
+
),
|
|
77
|
+
schema_name=schema_name,
|
|
78
|
+
name=name,
|
|
79
|
+
)
|
|
80
|
+
if table_info:
|
|
81
|
+
output_json(table_info_to_dict(table_info))
|
|
82
|
+
else:
|
|
83
|
+
output_json({"error": "not_found", "schema": schema_name, "name": name})
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@table.command("create")
|
|
87
|
+
@click.argument("schema_name")
|
|
88
|
+
@click.argument("name")
|
|
89
|
+
@click.option("--attach-opaque-data", help="Hex-encoded attach ID")
|
|
90
|
+
@click.option("--catalog", "catalog_name", help="Catalog name for auto-attach")
|
|
91
|
+
@click.option("--attach-options", default="{}", help="Attach options as JSON")
|
|
92
|
+
@click.option("--worker", "-w", required=True, help="VGI worker command")
|
|
93
|
+
@click.option("--transaction-opaque-data", help="Transaction ID (hex)")
|
|
94
|
+
@click.option(
|
|
95
|
+
"--columns",
|
|
96
|
+
required=True,
|
|
97
|
+
help='Column definitions as JSON array: [{"name":"id","type":"int64"}]',
|
|
98
|
+
)
|
|
99
|
+
@click.option(
|
|
100
|
+
"--on-conflict",
|
|
101
|
+
type=click.Choice(["error", "ignore", "replace"]),
|
|
102
|
+
default="error",
|
|
103
|
+
help="Behavior if table already exists",
|
|
104
|
+
)
|
|
105
|
+
@click.option(
|
|
106
|
+
"--not-null",
|
|
107
|
+
multiple=True,
|
|
108
|
+
type=int,
|
|
109
|
+
help="Column index with NOT NULL constraint (can repeat)",
|
|
110
|
+
)
|
|
111
|
+
@click.option(
|
|
112
|
+
"--unique",
|
|
113
|
+
multiple=True,
|
|
114
|
+
help="Column indices for unique constraint as comma-separated list (can repeat)",
|
|
115
|
+
)
|
|
116
|
+
@click.option("--check", multiple=True, help="SQL check constraint (can repeat)")
|
|
117
|
+
def table_create(
|
|
118
|
+
schema_name: str,
|
|
119
|
+
name: str,
|
|
120
|
+
attach_opaque_data: str | None,
|
|
121
|
+
catalog_name: str | None,
|
|
122
|
+
attach_options: str,
|
|
123
|
+
worker: str,
|
|
124
|
+
transaction_opaque_data: str | None,
|
|
125
|
+
columns: str,
|
|
126
|
+
on_conflict: str,
|
|
127
|
+
not_null: tuple[int, ...],
|
|
128
|
+
unique: tuple[str, ...],
|
|
129
|
+
check: tuple[str, ...],
|
|
130
|
+
) -> None:
|
|
131
|
+
"""Create a new table.
|
|
132
|
+
|
|
133
|
+
SCHEMA_NAME is the schema to create the table in.
|
|
134
|
+
NAME is the name for the new table.
|
|
135
|
+
|
|
136
|
+
"""
|
|
137
|
+
client = Client(worker)
|
|
138
|
+
opts = parse_json_option(attach_options, "--attach-options")
|
|
139
|
+
resolved_attach_opaque_data, is_stateful = get_attach_opaque_data_from_options(
|
|
140
|
+
client, attach_opaque_data, catalog_name, opts
|
|
141
|
+
)
|
|
142
|
+
if is_stateful and catalog_name:
|
|
143
|
+
click.echo(
|
|
144
|
+
"Warning: Using --catalog with a stateful catalog. "
|
|
145
|
+
"Consider using --attach-opaque-data for session persistence.",
|
|
146
|
+
err=True,
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
columns_json = parse_json_option(columns, "--columns")
|
|
150
|
+
arrow_schema = json_to_arrow_schema(columns_json)
|
|
151
|
+
|
|
152
|
+
# Parse unique constraints: each is a comma-separated list of column indices
|
|
153
|
+
unique_constraints = []
|
|
154
|
+
for u in unique:
|
|
155
|
+
indices = [int(i.strip()) for i in u.split(",")]
|
|
156
|
+
unique_constraints.append(indices)
|
|
157
|
+
|
|
158
|
+
client.table_create(
|
|
159
|
+
attach_opaque_data=resolved_attach_opaque_data,
|
|
160
|
+
transaction_opaque_data=(
|
|
161
|
+
hex_to_transaction_opaque_data(transaction_opaque_data) if transaction_opaque_data else None
|
|
162
|
+
),
|
|
163
|
+
schema_name=schema_name,
|
|
164
|
+
name=name,
|
|
165
|
+
columns=SerializedSchema(arrow_schema.serialize().to_pybytes()),
|
|
166
|
+
on_conflict=OnConflict(on_conflict),
|
|
167
|
+
not_null_constraints=list(not_null),
|
|
168
|
+
unique_constraints=unique_constraints,
|
|
169
|
+
check_constraints=list(check),
|
|
170
|
+
)
|
|
171
|
+
output_json({"status": "created", "schema": schema_name, "name": name})
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
@table.command("drop")
|
|
175
|
+
@click.argument("schema_name")
|
|
176
|
+
@click.argument("name")
|
|
177
|
+
@click.option("--attach-opaque-data", help="Hex-encoded attach ID")
|
|
178
|
+
@click.option("--catalog", "catalog_name", help="Catalog name for auto-attach")
|
|
179
|
+
@click.option("--attach-options", default="{}", help="Attach options as JSON")
|
|
180
|
+
@click.option("--worker", "-w", required=True, help="VGI worker command")
|
|
181
|
+
@click.option("--transaction-opaque-data", help="Transaction ID (hex)")
|
|
182
|
+
@click.option("--ignore-not-found", is_flag=True, help="Don't error if not found")
|
|
183
|
+
def table_drop(
|
|
184
|
+
schema_name: str,
|
|
185
|
+
name: str,
|
|
186
|
+
attach_opaque_data: str | None,
|
|
187
|
+
catalog_name: str | None,
|
|
188
|
+
attach_options: str,
|
|
189
|
+
worker: str,
|
|
190
|
+
transaction_opaque_data: str | None,
|
|
191
|
+
ignore_not_found: bool,
|
|
192
|
+
) -> None:
|
|
193
|
+
"""Drop a table.
|
|
194
|
+
|
|
195
|
+
SCHEMA_NAME is the schema containing the table.
|
|
196
|
+
NAME is the table name to drop.
|
|
197
|
+
|
|
198
|
+
"""
|
|
199
|
+
client = Client(worker)
|
|
200
|
+
opts = parse_json_option(attach_options, "--attach-options")
|
|
201
|
+
resolved_attach_opaque_data, is_stateful = get_attach_opaque_data_from_options(
|
|
202
|
+
client, attach_opaque_data, catalog_name, opts
|
|
203
|
+
)
|
|
204
|
+
if is_stateful and catalog_name:
|
|
205
|
+
click.echo(
|
|
206
|
+
"Warning: Using --catalog with a stateful catalog. "
|
|
207
|
+
"Consider using --attach-opaque-data for session persistence.",
|
|
208
|
+
err=True,
|
|
209
|
+
)
|
|
210
|
+
client.table_drop(
|
|
211
|
+
attach_opaque_data=resolved_attach_opaque_data,
|
|
212
|
+
transaction_opaque_data=(
|
|
213
|
+
hex_to_transaction_opaque_data(transaction_opaque_data) if transaction_opaque_data else None
|
|
214
|
+
),
|
|
215
|
+
schema_name=schema_name,
|
|
216
|
+
name=name,
|
|
217
|
+
ignore_not_found=ignore_not_found,
|
|
218
|
+
)
|
|
219
|
+
output_json({"status": "dropped", "schema": schema_name, "name": name})
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
@table.command("rename")
|
|
223
|
+
@click.argument("schema_name")
|
|
224
|
+
@click.argument("name")
|
|
225
|
+
@click.argument("new_name")
|
|
226
|
+
@click.option("--attach-opaque-data", help="Hex-encoded attach ID")
|
|
227
|
+
@click.option("--catalog", "catalog_name", help="Catalog name for auto-attach")
|
|
228
|
+
@click.option("--attach-options", default="{}", help="Attach options as JSON")
|
|
229
|
+
@click.option("--worker", "-w", required=True, help="VGI worker command")
|
|
230
|
+
@click.option("--transaction-opaque-data", help="Transaction ID (hex)")
|
|
231
|
+
@click.option("--ignore-not-found", is_flag=True, help="Don't error if not found")
|
|
232
|
+
def table_rename(
|
|
233
|
+
schema_name: str,
|
|
234
|
+
name: str,
|
|
235
|
+
new_name: str,
|
|
236
|
+
attach_opaque_data: str | None,
|
|
237
|
+
catalog_name: str | None,
|
|
238
|
+
attach_options: str,
|
|
239
|
+
worker: str,
|
|
240
|
+
transaction_opaque_data: str | None,
|
|
241
|
+
ignore_not_found: bool,
|
|
242
|
+
) -> None:
|
|
243
|
+
"""Rename a table.
|
|
244
|
+
|
|
245
|
+
SCHEMA_NAME is the schema containing the table.
|
|
246
|
+
NAME is the current table name.
|
|
247
|
+
NEW_NAME is the new name for the table.
|
|
248
|
+
|
|
249
|
+
"""
|
|
250
|
+
client = Client(worker)
|
|
251
|
+
opts = parse_json_option(attach_options, "--attach-options")
|
|
252
|
+
resolved_attach_opaque_data, is_stateful = get_attach_opaque_data_from_options(
|
|
253
|
+
client, attach_opaque_data, catalog_name, opts
|
|
254
|
+
)
|
|
255
|
+
if is_stateful and catalog_name:
|
|
256
|
+
click.echo(
|
|
257
|
+
"Warning: Using --catalog with a stateful catalog. "
|
|
258
|
+
"Consider using --attach-opaque-data for session persistence.",
|
|
259
|
+
err=True,
|
|
260
|
+
)
|
|
261
|
+
client.table_rename(
|
|
262
|
+
attach_opaque_data=resolved_attach_opaque_data,
|
|
263
|
+
transaction_opaque_data=(
|
|
264
|
+
hex_to_transaction_opaque_data(transaction_opaque_data) if transaction_opaque_data else None
|
|
265
|
+
),
|
|
266
|
+
schema_name=schema_name,
|
|
267
|
+
name=name,
|
|
268
|
+
new_name=new_name,
|
|
269
|
+
ignore_not_found=ignore_not_found,
|
|
270
|
+
)
|
|
271
|
+
output_json(
|
|
272
|
+
{
|
|
273
|
+
"status": "renamed",
|
|
274
|
+
"schema": schema_name,
|
|
275
|
+
"old": name,
|
|
276
|
+
"new": new_name,
|
|
277
|
+
}
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
@table.command("comment")
|
|
282
|
+
@click.argument("schema_name")
|
|
283
|
+
@click.argument("name")
|
|
284
|
+
@click.option("--attach-opaque-data", help="Hex-encoded attach ID")
|
|
285
|
+
@click.option("--catalog", "catalog_name", help="Catalog name for auto-attach")
|
|
286
|
+
@click.option("--attach-options", default="{}", help="Attach options as JSON")
|
|
287
|
+
@click.option("--worker", "-w", required=True, help="VGI worker command")
|
|
288
|
+
@click.option("--transaction-opaque-data", help="Transaction ID (hex)")
|
|
289
|
+
@click.option("--set", "comment_text", help="Set comment to this text")
|
|
290
|
+
@click.option("--clear", is_flag=True, help="Clear the comment")
|
|
291
|
+
@click.option("--ignore-not-found", is_flag=True, help="Don't error if not found")
|
|
292
|
+
def table_comment(
|
|
293
|
+
schema_name: str,
|
|
294
|
+
name: str,
|
|
295
|
+
attach_opaque_data: str | None,
|
|
296
|
+
catalog_name: str | None,
|
|
297
|
+
attach_options: str,
|
|
298
|
+
worker: str,
|
|
299
|
+
transaction_opaque_data: str | None,
|
|
300
|
+
comment_text: str | None,
|
|
301
|
+
clear: bool,
|
|
302
|
+
ignore_not_found: bool,
|
|
303
|
+
) -> None:
|
|
304
|
+
"""Set or clear a table's comment.
|
|
305
|
+
|
|
306
|
+
SCHEMA_NAME is the schema containing the table.
|
|
307
|
+
NAME is the table name.
|
|
308
|
+
|
|
309
|
+
Use --set to set the comment, or --clear to remove it.
|
|
310
|
+
|
|
311
|
+
"""
|
|
312
|
+
if not comment_text and not clear:
|
|
313
|
+
raise click.ClickException("Must specify --set or --clear")
|
|
314
|
+
if comment_text and clear:
|
|
315
|
+
raise click.ClickException("Cannot specify both --set and --clear")
|
|
316
|
+
|
|
317
|
+
client = Client(worker)
|
|
318
|
+
opts = parse_json_option(attach_options, "--attach-options")
|
|
319
|
+
resolved_attach_opaque_data, is_stateful = get_attach_opaque_data_from_options(
|
|
320
|
+
client, attach_opaque_data, catalog_name, opts
|
|
321
|
+
)
|
|
322
|
+
if is_stateful and catalog_name:
|
|
323
|
+
click.echo(
|
|
324
|
+
"Warning: Using --catalog with a stateful catalog. "
|
|
325
|
+
"Consider using --attach-opaque-data for session persistence.",
|
|
326
|
+
err=True,
|
|
327
|
+
)
|
|
328
|
+
client.table_comment_set(
|
|
329
|
+
attach_opaque_data=resolved_attach_opaque_data,
|
|
330
|
+
transaction_opaque_data=(
|
|
331
|
+
hex_to_transaction_opaque_data(transaction_opaque_data) if transaction_opaque_data else None
|
|
332
|
+
),
|
|
333
|
+
schema_name=schema_name,
|
|
334
|
+
name=name,
|
|
335
|
+
comment=None if clear else comment_text,
|
|
336
|
+
ignore_not_found=ignore_not_found,
|
|
337
|
+
)
|
|
338
|
+
action = "cleared" if clear else "set"
|
|
339
|
+
output_json({"status": f"comment_{action}", "schema": schema_name, "name": name})
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
@table.command("scan-function")
|
|
343
|
+
@click.argument("schema_name")
|
|
344
|
+
@click.argument("name")
|
|
345
|
+
@click.option("--attach-opaque-data", help="Hex-encoded attach ID")
|
|
346
|
+
@click.option("--catalog", "catalog_name", help="Catalog name for auto-attach")
|
|
347
|
+
@click.option("--attach-options", default="{}", help="Attach options as JSON")
|
|
348
|
+
@click.option("--worker", "-w", required=True, help="VGI worker command")
|
|
349
|
+
@click.option("--transaction-opaque-data", help="Transaction ID (hex) for transactional read")
|
|
350
|
+
@click.option("--at-unit", help="Time travel unit (e.g., 'timestamp', 'version')")
|
|
351
|
+
@click.option("--at-value", help="Time travel value")
|
|
352
|
+
def table_scan_function(
|
|
353
|
+
schema_name: str,
|
|
354
|
+
name: str,
|
|
355
|
+
attach_opaque_data: str | None,
|
|
356
|
+
catalog_name: str | None,
|
|
357
|
+
attach_options: str,
|
|
358
|
+
worker: str,
|
|
359
|
+
transaction_opaque_data: str | None,
|
|
360
|
+
at_unit: str | None,
|
|
361
|
+
at_value: str | None,
|
|
362
|
+
) -> None:
|
|
363
|
+
"""Get the scan function for a table.
|
|
364
|
+
|
|
365
|
+
SCHEMA_NAME is the schema containing the table.
|
|
366
|
+
NAME is the table name.
|
|
367
|
+
|
|
368
|
+
"""
|
|
369
|
+
client = Client(worker)
|
|
370
|
+
opts = parse_json_option(attach_options, "--attach-options")
|
|
371
|
+
resolved_attach_opaque_data, is_stateful = get_attach_opaque_data_from_options(
|
|
372
|
+
client, attach_opaque_data, catalog_name, opts
|
|
373
|
+
)
|
|
374
|
+
if is_stateful and catalog_name:
|
|
375
|
+
click.echo(
|
|
376
|
+
"Warning: Using --catalog with a stateful catalog. "
|
|
377
|
+
"Consider using --attach-opaque-data for session persistence.",
|
|
378
|
+
err=True,
|
|
379
|
+
)
|
|
380
|
+
result = client.table_scan_function_get(
|
|
381
|
+
attach_opaque_data=resolved_attach_opaque_data,
|
|
382
|
+
transaction_opaque_data=(
|
|
383
|
+
hex_to_transaction_opaque_data(transaction_opaque_data) if transaction_opaque_data else None
|
|
384
|
+
),
|
|
385
|
+
schema_name=schema_name,
|
|
386
|
+
name=name,
|
|
387
|
+
at_unit=at_unit,
|
|
388
|
+
at_value=at_value,
|
|
389
|
+
)
|
|
390
|
+
output_json(scan_function_result_to_dict(result))
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
# Column subcommands
|
|
394
|
+
@table.group("column")
|
|
395
|
+
def column() -> None:
|
|
396
|
+
"""Manage table columns."""
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
@column.command("add")
|
|
400
|
+
@click.argument("schema_name")
|
|
401
|
+
@click.argument("table_name")
|
|
402
|
+
@click.option("--attach-opaque-data", help="Hex-encoded attach ID")
|
|
403
|
+
@click.option("--catalog", "catalog_name", help="Catalog name for auto-attach")
|
|
404
|
+
@click.option("--attach-options", default="{}", help="Attach options as JSON")
|
|
405
|
+
@click.option("--worker", "-w", required=True, help="VGI worker command")
|
|
406
|
+
@click.option("--transaction-opaque-data", help="Transaction ID (hex)")
|
|
407
|
+
@click.option(
|
|
408
|
+
"--column",
|
|
409
|
+
"column_def",
|
|
410
|
+
required=True,
|
|
411
|
+
help='Column definition as JSON: {"name":"col","type":"int64"}',
|
|
412
|
+
)
|
|
413
|
+
@click.option("--ignore-not-found", is_flag=True, help="Don't error if table not found")
|
|
414
|
+
@click.option("--if-not-exists", is_flag=True, help="Don't error if column already exists")
|
|
415
|
+
def column_add(
|
|
416
|
+
schema_name: str,
|
|
417
|
+
table_name: str,
|
|
418
|
+
attach_opaque_data: str | None,
|
|
419
|
+
catalog_name: str | None,
|
|
420
|
+
attach_options: str,
|
|
421
|
+
worker: str,
|
|
422
|
+
transaction_opaque_data: str | None,
|
|
423
|
+
column_def: str,
|
|
424
|
+
ignore_not_found: bool,
|
|
425
|
+
if_not_exists: bool,
|
|
426
|
+
) -> None:
|
|
427
|
+
"""Add a column to a table.
|
|
428
|
+
|
|
429
|
+
SCHEMA_NAME is the schema containing the table.
|
|
430
|
+
TABLE_NAME is the table to add the column to.
|
|
431
|
+
|
|
432
|
+
"""
|
|
433
|
+
client = Client(worker)
|
|
434
|
+
opts = parse_json_option(attach_options, "--attach-options")
|
|
435
|
+
resolved_attach_opaque_data, is_stateful = get_attach_opaque_data_from_options(
|
|
436
|
+
client, attach_opaque_data, catalog_name, opts
|
|
437
|
+
)
|
|
438
|
+
if is_stateful and catalog_name:
|
|
439
|
+
click.echo(
|
|
440
|
+
"Warning: Using --catalog with a stateful catalog. "
|
|
441
|
+
"Consider using --attach-opaque-data for session persistence.",
|
|
442
|
+
err=True,
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
col_json = parse_json_option(column_def, "--column")
|
|
446
|
+
arrow_schema = json_to_arrow_schema([col_json])
|
|
447
|
+
|
|
448
|
+
client.table_column_add(
|
|
449
|
+
attach_opaque_data=resolved_attach_opaque_data,
|
|
450
|
+
transaction_opaque_data=(
|
|
451
|
+
hex_to_transaction_opaque_data(transaction_opaque_data) if transaction_opaque_data else None
|
|
452
|
+
),
|
|
453
|
+
schema_name=schema_name,
|
|
454
|
+
name=table_name,
|
|
455
|
+
column_definition=SerializedSchema(arrow_schema.serialize().to_pybytes()),
|
|
456
|
+
ignore_not_found=ignore_not_found,
|
|
457
|
+
if_column_not_exists=if_not_exists,
|
|
458
|
+
)
|
|
459
|
+
output_json(
|
|
460
|
+
{
|
|
461
|
+
"status": "column_added",
|
|
462
|
+
"schema": schema_name,
|
|
463
|
+
"table": table_name,
|
|
464
|
+
"column": col_json["name"],
|
|
465
|
+
}
|
|
466
|
+
)
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
@column.command("drop")
|
|
470
|
+
@click.argument("schema_name")
|
|
471
|
+
@click.argument("table_name")
|
|
472
|
+
@click.argument("column_name")
|
|
473
|
+
@click.option("--attach-opaque-data", help="Hex-encoded attach ID")
|
|
474
|
+
@click.option("--catalog", "catalog_name", help="Catalog name for auto-attach")
|
|
475
|
+
@click.option("--attach-options", default="{}", help="Attach options as JSON")
|
|
476
|
+
@click.option("--worker", "-w", required=True, help="VGI worker command")
|
|
477
|
+
@click.option("--transaction-opaque-data", help="Transaction ID (hex)")
|
|
478
|
+
@click.option("--ignore-not-found", is_flag=True, help="Don't error if table not found")
|
|
479
|
+
@click.option("--if-exists", is_flag=True, help="Don't error if column doesn't exist")
|
|
480
|
+
@click.option("--cascade", is_flag=True, help="Drop dependent constraints")
|
|
481
|
+
def column_drop(
|
|
482
|
+
schema_name: str,
|
|
483
|
+
table_name: str,
|
|
484
|
+
column_name: str,
|
|
485
|
+
attach_opaque_data: str | None,
|
|
486
|
+
catalog_name: str | None,
|
|
487
|
+
attach_options: str,
|
|
488
|
+
worker: str,
|
|
489
|
+
transaction_opaque_data: str | None,
|
|
490
|
+
ignore_not_found: bool,
|
|
491
|
+
if_exists: bool,
|
|
492
|
+
cascade: bool,
|
|
493
|
+
) -> None:
|
|
494
|
+
"""Drop a column from a table.
|
|
495
|
+
|
|
496
|
+
SCHEMA_NAME is the schema containing the table.
|
|
497
|
+
TABLE_NAME is the table to drop the column from.
|
|
498
|
+
COLUMN_NAME is the column to drop.
|
|
499
|
+
|
|
500
|
+
"""
|
|
501
|
+
client = Client(worker)
|
|
502
|
+
opts = parse_json_option(attach_options, "--attach-options")
|
|
503
|
+
resolved_attach_opaque_data, is_stateful = get_attach_opaque_data_from_options(
|
|
504
|
+
client, attach_opaque_data, catalog_name, opts
|
|
505
|
+
)
|
|
506
|
+
if is_stateful and catalog_name:
|
|
507
|
+
click.echo(
|
|
508
|
+
"Warning: Using --catalog with a stateful catalog. "
|
|
509
|
+
"Consider using --attach-opaque-data for session persistence.",
|
|
510
|
+
err=True,
|
|
511
|
+
)
|
|
512
|
+
client.table_column_drop(
|
|
513
|
+
attach_opaque_data=resolved_attach_opaque_data,
|
|
514
|
+
transaction_opaque_data=(
|
|
515
|
+
hex_to_transaction_opaque_data(transaction_opaque_data) if transaction_opaque_data else None
|
|
516
|
+
),
|
|
517
|
+
schema_name=schema_name,
|
|
518
|
+
name=table_name,
|
|
519
|
+
column_name=column_name,
|
|
520
|
+
ignore_not_found=ignore_not_found,
|
|
521
|
+
if_column_exists=if_exists,
|
|
522
|
+
cascade=cascade,
|
|
523
|
+
)
|
|
524
|
+
output_json(
|
|
525
|
+
{
|
|
526
|
+
"status": "column_dropped",
|
|
527
|
+
"schema": schema_name,
|
|
528
|
+
"table": table_name,
|
|
529
|
+
"column": column_name,
|
|
530
|
+
}
|
|
531
|
+
)
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
@column.command("rename")
|
|
535
|
+
@click.argument("schema_name")
|
|
536
|
+
@click.argument("table_name")
|
|
537
|
+
@click.argument("column_name")
|
|
538
|
+
@click.argument("new_column_name")
|
|
539
|
+
@click.option("--attach-opaque-data", help="Hex-encoded attach ID")
|
|
540
|
+
@click.option("--catalog", "catalog_name", help="Catalog name for auto-attach")
|
|
541
|
+
@click.option("--attach-options", default="{}", help="Attach options as JSON")
|
|
542
|
+
@click.option("--worker", "-w", required=True, help="VGI worker command")
|
|
543
|
+
@click.option("--transaction-opaque-data", help="Transaction ID (hex)")
|
|
544
|
+
@click.option("--ignore-not-found", is_flag=True, help="Don't error if table not found")
|
|
545
|
+
def column_rename(
|
|
546
|
+
schema_name: str,
|
|
547
|
+
table_name: str,
|
|
548
|
+
column_name: str,
|
|
549
|
+
new_column_name: str,
|
|
550
|
+
attach_opaque_data: str | None,
|
|
551
|
+
catalog_name: str | None,
|
|
552
|
+
attach_options: str,
|
|
553
|
+
worker: str,
|
|
554
|
+
transaction_opaque_data: str | None,
|
|
555
|
+
ignore_not_found: bool,
|
|
556
|
+
) -> None:
|
|
557
|
+
"""Rename a column.
|
|
558
|
+
|
|
559
|
+
SCHEMA_NAME is the schema containing the table.
|
|
560
|
+
TABLE_NAME is the table containing the column.
|
|
561
|
+
COLUMN_NAME is the current column name.
|
|
562
|
+
NEW_COLUMN_NAME is the new name for the column.
|
|
563
|
+
|
|
564
|
+
"""
|
|
565
|
+
client = Client(worker)
|
|
566
|
+
opts = parse_json_option(attach_options, "--attach-options")
|
|
567
|
+
resolved_attach_opaque_data, is_stateful = get_attach_opaque_data_from_options(
|
|
568
|
+
client, attach_opaque_data, catalog_name, opts
|
|
569
|
+
)
|
|
570
|
+
if is_stateful and catalog_name:
|
|
571
|
+
click.echo(
|
|
572
|
+
"Warning: Using --catalog with a stateful catalog. "
|
|
573
|
+
"Consider using --attach-opaque-data for session persistence.",
|
|
574
|
+
err=True,
|
|
575
|
+
)
|
|
576
|
+
client.table_column_rename(
|
|
577
|
+
attach_opaque_data=resolved_attach_opaque_data,
|
|
578
|
+
transaction_opaque_data=(
|
|
579
|
+
hex_to_transaction_opaque_data(transaction_opaque_data) if transaction_opaque_data else None
|
|
580
|
+
),
|
|
581
|
+
schema_name=schema_name,
|
|
582
|
+
name=table_name,
|
|
583
|
+
column_name=column_name,
|
|
584
|
+
new_column_name=new_column_name,
|
|
585
|
+
ignore_not_found=ignore_not_found,
|
|
586
|
+
)
|
|
587
|
+
output_json(
|
|
588
|
+
{
|
|
589
|
+
"status": "column_renamed",
|
|
590
|
+
"schema": schema_name,
|
|
591
|
+
"table": table_name,
|
|
592
|
+
"old_column": column_name,
|
|
593
|
+
"new_column": new_column_name,
|
|
594
|
+
}
|
|
595
|
+
)
|
|
596
|
+
|
|
597
|
+
|
|
598
|
+
@column.command("set-default")
|
|
599
|
+
@click.argument("schema_name")
|
|
600
|
+
@click.argument("table_name")
|
|
601
|
+
@click.argument("column_name")
|
|
602
|
+
@click.argument("expression")
|
|
603
|
+
@click.option("--attach-opaque-data", help="Hex-encoded attach ID")
|
|
604
|
+
@click.option("--catalog", "catalog_name", help="Catalog name for auto-attach")
|
|
605
|
+
@click.option("--attach-options", default="{}", help="Attach options as JSON")
|
|
606
|
+
@click.option("--worker", "-w", required=True, help="VGI worker command")
|
|
607
|
+
@click.option("--transaction-opaque-data", help="Transaction ID (hex)")
|
|
608
|
+
@click.option("--ignore-not-found", is_flag=True, help="Don't error if table not found")
|
|
609
|
+
def column_set_default(
|
|
610
|
+
schema_name: str,
|
|
611
|
+
table_name: str,
|
|
612
|
+
column_name: str,
|
|
613
|
+
expression: str,
|
|
614
|
+
attach_opaque_data: str | None,
|
|
615
|
+
catalog_name: str | None,
|
|
616
|
+
attach_options: str,
|
|
617
|
+
worker: str,
|
|
618
|
+
transaction_opaque_data: str | None,
|
|
619
|
+
ignore_not_found: bool,
|
|
620
|
+
) -> None:
|
|
621
|
+
"""Set the default value for a column.
|
|
622
|
+
|
|
623
|
+
SCHEMA_NAME is the schema containing the table.
|
|
624
|
+
TABLE_NAME is the table containing the column.
|
|
625
|
+
COLUMN_NAME is the column to set the default for.
|
|
626
|
+
EXPRESSION is the SQL expression for the default value.
|
|
627
|
+
|
|
628
|
+
"""
|
|
629
|
+
client = Client(worker)
|
|
630
|
+
opts = parse_json_option(attach_options, "--attach-options")
|
|
631
|
+
resolved_attach_opaque_data, is_stateful = get_attach_opaque_data_from_options(
|
|
632
|
+
client, attach_opaque_data, catalog_name, opts
|
|
633
|
+
)
|
|
634
|
+
if is_stateful and catalog_name:
|
|
635
|
+
click.echo(
|
|
636
|
+
"Warning: Using --catalog with a stateful catalog. "
|
|
637
|
+
"Consider using --attach-opaque-data for session persistence.",
|
|
638
|
+
err=True,
|
|
639
|
+
)
|
|
640
|
+
client.table_column_default_set(
|
|
641
|
+
attach_opaque_data=resolved_attach_opaque_data,
|
|
642
|
+
transaction_opaque_data=(
|
|
643
|
+
hex_to_transaction_opaque_data(transaction_opaque_data) if transaction_opaque_data else None
|
|
644
|
+
),
|
|
645
|
+
schema_name=schema_name,
|
|
646
|
+
name=table_name,
|
|
647
|
+
column_name=column_name,
|
|
648
|
+
expression=SqlExpression(expression),
|
|
649
|
+
ignore_not_found=ignore_not_found,
|
|
650
|
+
)
|
|
651
|
+
output_json(
|
|
652
|
+
{
|
|
653
|
+
"status": "default_set",
|
|
654
|
+
"schema": schema_name,
|
|
655
|
+
"table": table_name,
|
|
656
|
+
"column": column_name,
|
|
657
|
+
}
|
|
658
|
+
)
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
@column.command("drop-default")
|
|
662
|
+
@click.argument("schema_name")
|
|
663
|
+
@click.argument("table_name")
|
|
664
|
+
@click.argument("column_name")
|
|
665
|
+
@click.option("--attach-opaque-data", help="Hex-encoded attach ID")
|
|
666
|
+
@click.option("--catalog", "catalog_name", help="Catalog name for auto-attach")
|
|
667
|
+
@click.option("--attach-options", default="{}", help="Attach options as JSON")
|
|
668
|
+
@click.option("--worker", "-w", required=True, help="VGI worker command")
|
|
669
|
+
@click.option("--transaction-opaque-data", help="Transaction ID (hex)")
|
|
670
|
+
@click.option("--ignore-not-found", is_flag=True, help="Don't error if table not found")
|
|
671
|
+
def column_drop_default(
|
|
672
|
+
schema_name: str,
|
|
673
|
+
table_name: str,
|
|
674
|
+
column_name: str,
|
|
675
|
+
attach_opaque_data: str | None,
|
|
676
|
+
catalog_name: str | None,
|
|
677
|
+
attach_options: str,
|
|
678
|
+
worker: str,
|
|
679
|
+
transaction_opaque_data: str | None,
|
|
680
|
+
ignore_not_found: bool,
|
|
681
|
+
) -> None:
|
|
682
|
+
"""Remove the default value from a column.
|
|
683
|
+
|
|
684
|
+
SCHEMA_NAME is the schema containing the table.
|
|
685
|
+
TABLE_NAME is the table containing the column.
|
|
686
|
+
COLUMN_NAME is the column to remove the default from.
|
|
687
|
+
|
|
688
|
+
"""
|
|
689
|
+
client = Client(worker)
|
|
690
|
+
opts = parse_json_option(attach_options, "--attach-options")
|
|
691
|
+
resolved_attach_opaque_data, is_stateful = get_attach_opaque_data_from_options(
|
|
692
|
+
client, attach_opaque_data, catalog_name, opts
|
|
693
|
+
)
|
|
694
|
+
if is_stateful and catalog_name:
|
|
695
|
+
click.echo(
|
|
696
|
+
"Warning: Using --catalog with a stateful catalog. "
|
|
697
|
+
"Consider using --attach-opaque-data for session persistence.",
|
|
698
|
+
err=True,
|
|
699
|
+
)
|
|
700
|
+
client.table_column_default_drop(
|
|
701
|
+
attach_opaque_data=resolved_attach_opaque_data,
|
|
702
|
+
transaction_opaque_data=(
|
|
703
|
+
hex_to_transaction_opaque_data(transaction_opaque_data) if transaction_opaque_data else None
|
|
704
|
+
),
|
|
705
|
+
schema_name=schema_name,
|
|
706
|
+
name=table_name,
|
|
707
|
+
column_name=column_name,
|
|
708
|
+
ignore_not_found=ignore_not_found,
|
|
709
|
+
)
|
|
710
|
+
output_json(
|
|
711
|
+
{
|
|
712
|
+
"status": "default_dropped",
|
|
713
|
+
"schema": schema_name,
|
|
714
|
+
"table": table_name,
|
|
715
|
+
"column": column_name,
|
|
716
|
+
}
|
|
717
|
+
)
|
|
718
|
+
|
|
719
|
+
|
|
720
|
+
@column.command("set-type")
|
|
721
|
+
@click.argument("schema_name")
|
|
722
|
+
@click.argument("table_name")
|
|
723
|
+
@click.option("--attach-opaque-data", help="Hex-encoded attach ID")
|
|
724
|
+
@click.option("--catalog", "catalog_name", help="Catalog name for auto-attach")
|
|
725
|
+
@click.option("--attach-options", default="{}", help="Attach options as JSON")
|
|
726
|
+
@click.option("--worker", "-w", required=True, help="VGI worker command")
|
|
727
|
+
@click.option("--transaction-opaque-data", help="Transaction ID (hex)")
|
|
728
|
+
@click.option(
|
|
729
|
+
"--column",
|
|
730
|
+
"column_def",
|
|
731
|
+
required=True,
|
|
732
|
+
help='Column definition as JSON: {"name":"col","type":"string"}',
|
|
733
|
+
)
|
|
734
|
+
@click.option("--using", "expression", help="SQL expression to convert values")
|
|
735
|
+
@click.option("--ignore-not-found", is_flag=True, help="Don't error if table not found")
|
|
736
|
+
def column_set_type(
|
|
737
|
+
schema_name: str,
|
|
738
|
+
table_name: str,
|
|
739
|
+
attach_opaque_data: str | None,
|
|
740
|
+
catalog_name: str | None,
|
|
741
|
+
attach_options: str,
|
|
742
|
+
worker: str,
|
|
743
|
+
transaction_opaque_data: str | None,
|
|
744
|
+
column_def: str,
|
|
745
|
+
expression: str | None,
|
|
746
|
+
ignore_not_found: bool,
|
|
747
|
+
) -> None:
|
|
748
|
+
"""Change the type of a column.
|
|
749
|
+
|
|
750
|
+
SCHEMA_NAME is the schema containing the table.
|
|
751
|
+
TABLE_NAME is the table containing the column.
|
|
752
|
+
|
|
753
|
+
The --column option specifies the column name and new type.
|
|
754
|
+
|
|
755
|
+
"""
|
|
756
|
+
client = Client(worker)
|
|
757
|
+
opts = parse_json_option(attach_options, "--attach-options")
|
|
758
|
+
resolved_attach_opaque_data, is_stateful = get_attach_opaque_data_from_options(
|
|
759
|
+
client, attach_opaque_data, catalog_name, opts
|
|
760
|
+
)
|
|
761
|
+
if is_stateful and catalog_name:
|
|
762
|
+
click.echo(
|
|
763
|
+
"Warning: Using --catalog with a stateful catalog. "
|
|
764
|
+
"Consider using --attach-opaque-data for session persistence.",
|
|
765
|
+
err=True,
|
|
766
|
+
)
|
|
767
|
+
|
|
768
|
+
col_json = parse_json_option(column_def, "--column")
|
|
769
|
+
arrow_schema = json_to_arrow_schema([col_json])
|
|
770
|
+
|
|
771
|
+
client.table_column_type_change(
|
|
772
|
+
attach_opaque_data=resolved_attach_opaque_data,
|
|
773
|
+
transaction_opaque_data=(
|
|
774
|
+
hex_to_transaction_opaque_data(transaction_opaque_data) if transaction_opaque_data else None
|
|
775
|
+
),
|
|
776
|
+
schema_name=schema_name,
|
|
777
|
+
name=table_name,
|
|
778
|
+
column_definition=SerializedSchema(arrow_schema.serialize().to_pybytes()),
|
|
779
|
+
expression=SqlExpression(expression) if expression else None,
|
|
780
|
+
ignore_not_found=ignore_not_found,
|
|
781
|
+
)
|
|
782
|
+
output_json(
|
|
783
|
+
{
|
|
784
|
+
"status": "type_changed",
|
|
785
|
+
"schema": schema_name,
|
|
786
|
+
"table": table_name,
|
|
787
|
+
"column": col_json["name"],
|
|
788
|
+
}
|
|
789
|
+
)
|
|
790
|
+
|
|
791
|
+
|
|
792
|
+
@column.command("set-not-null")
|
|
793
|
+
@click.argument("schema_name")
|
|
794
|
+
@click.argument("table_name")
|
|
795
|
+
@click.argument("column_name")
|
|
796
|
+
@click.option("--attach-opaque-data", help="Hex-encoded attach ID")
|
|
797
|
+
@click.option("--catalog", "catalog_name", help="Catalog name for auto-attach")
|
|
798
|
+
@click.option("--attach-options", default="{}", help="Attach options as JSON")
|
|
799
|
+
@click.option("--worker", "-w", required=True, help="VGI worker command")
|
|
800
|
+
@click.option("--transaction-opaque-data", help="Transaction ID (hex)")
|
|
801
|
+
@click.option("--ignore-not-found", is_flag=True, help="Don't error if table not found")
|
|
802
|
+
def column_set_not_null(
|
|
803
|
+
schema_name: str,
|
|
804
|
+
table_name: str,
|
|
805
|
+
column_name: str,
|
|
806
|
+
attach_opaque_data: str | None,
|
|
807
|
+
catalog_name: str | None,
|
|
808
|
+
attach_options: str,
|
|
809
|
+
worker: str,
|
|
810
|
+
transaction_opaque_data: str | None,
|
|
811
|
+
ignore_not_found: bool,
|
|
812
|
+
) -> None:
|
|
813
|
+
"""Add NOT NULL constraint to a column.
|
|
814
|
+
|
|
815
|
+
SCHEMA_NAME is the schema containing the table.
|
|
816
|
+
TABLE_NAME is the table containing the column.
|
|
817
|
+
COLUMN_NAME is the column to add NOT NULL to.
|
|
818
|
+
|
|
819
|
+
"""
|
|
820
|
+
client = Client(worker)
|
|
821
|
+
opts = parse_json_option(attach_options, "--attach-options")
|
|
822
|
+
resolved_attach_opaque_data, is_stateful = get_attach_opaque_data_from_options(
|
|
823
|
+
client, attach_opaque_data, catalog_name, opts
|
|
824
|
+
)
|
|
825
|
+
if is_stateful and catalog_name:
|
|
826
|
+
click.echo(
|
|
827
|
+
"Warning: Using --catalog with a stateful catalog. "
|
|
828
|
+
"Consider using --attach-opaque-data for session persistence.",
|
|
829
|
+
err=True,
|
|
830
|
+
)
|
|
831
|
+
client.table_not_null_set(
|
|
832
|
+
attach_opaque_data=resolved_attach_opaque_data,
|
|
833
|
+
transaction_opaque_data=(
|
|
834
|
+
hex_to_transaction_opaque_data(transaction_opaque_data) if transaction_opaque_data else None
|
|
835
|
+
),
|
|
836
|
+
schema_name=schema_name,
|
|
837
|
+
name=table_name,
|
|
838
|
+
column_name=column_name,
|
|
839
|
+
ignore_not_found=ignore_not_found,
|
|
840
|
+
)
|
|
841
|
+
output_json(
|
|
842
|
+
{
|
|
843
|
+
"status": "not_null_set",
|
|
844
|
+
"schema": schema_name,
|
|
845
|
+
"table": table_name,
|
|
846
|
+
"column": column_name,
|
|
847
|
+
}
|
|
848
|
+
)
|
|
849
|
+
|
|
850
|
+
|
|
851
|
+
@column.command("drop-not-null")
|
|
852
|
+
@click.argument("schema_name")
|
|
853
|
+
@click.argument("table_name")
|
|
854
|
+
@click.argument("column_name")
|
|
855
|
+
@click.option("--attach-opaque-data", help="Hex-encoded attach ID")
|
|
856
|
+
@click.option("--catalog", "catalog_name", help="Catalog name for auto-attach")
|
|
857
|
+
@click.option("--attach-options", default="{}", help="Attach options as JSON")
|
|
858
|
+
@click.option("--worker", "-w", required=True, help="VGI worker command")
|
|
859
|
+
@click.option("--transaction-opaque-data", help="Transaction ID (hex)")
|
|
860
|
+
@click.option("--ignore-not-found", is_flag=True, help="Don't error if table not found")
|
|
861
|
+
def column_drop_not_null(
|
|
862
|
+
schema_name: str,
|
|
863
|
+
table_name: str,
|
|
864
|
+
column_name: str,
|
|
865
|
+
attach_opaque_data: str | None,
|
|
866
|
+
catalog_name: str | None,
|
|
867
|
+
attach_options: str,
|
|
868
|
+
worker: str,
|
|
869
|
+
transaction_opaque_data: str | None,
|
|
870
|
+
ignore_not_found: bool,
|
|
871
|
+
) -> None:
|
|
872
|
+
"""Remove NOT NULL constraint from a column.
|
|
873
|
+
|
|
874
|
+
SCHEMA_NAME is the schema containing the table.
|
|
875
|
+
TABLE_NAME is the table containing the column.
|
|
876
|
+
COLUMN_NAME is the column to remove NOT NULL from.
|
|
877
|
+
|
|
878
|
+
"""
|
|
879
|
+
client = Client(worker)
|
|
880
|
+
opts = parse_json_option(attach_options, "--attach-options")
|
|
881
|
+
resolved_attach_opaque_data, is_stateful = get_attach_opaque_data_from_options(
|
|
882
|
+
client, attach_opaque_data, catalog_name, opts
|
|
883
|
+
)
|
|
884
|
+
if is_stateful and catalog_name:
|
|
885
|
+
click.echo(
|
|
886
|
+
"Warning: Using --catalog with a stateful catalog. "
|
|
887
|
+
"Consider using --attach-opaque-data for session persistence.",
|
|
888
|
+
err=True,
|
|
889
|
+
)
|
|
890
|
+
client.table_not_null_drop(
|
|
891
|
+
attach_opaque_data=resolved_attach_opaque_data,
|
|
892
|
+
transaction_opaque_data=(
|
|
893
|
+
hex_to_transaction_opaque_data(transaction_opaque_data) if transaction_opaque_data else None
|
|
894
|
+
),
|
|
895
|
+
schema_name=schema_name,
|
|
896
|
+
name=table_name,
|
|
897
|
+
column_name=column_name,
|
|
898
|
+
ignore_not_found=ignore_not_found,
|
|
899
|
+
)
|
|
900
|
+
output_json(
|
|
901
|
+
{
|
|
902
|
+
"status": "not_null_dropped",
|
|
903
|
+
"schema": schema_name,
|
|
904
|
+
"table": table_name,
|
|
905
|
+
"column": column_name,
|
|
906
|
+
}
|
|
907
|
+
)
|