vastdb 2.0.1__py3-none-any.whl → 2.0.3__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.
- vastdb/_adbc.py +194 -0
- vastdb/_internal.py +101 -12
- vastdb/_table_interface.py +20 -3
- vastdb/conftest.py +23 -1
- vastdb/errors.py +5 -0
- vastdb/schema.py +17 -2
- vastdb/session.py +12 -5
- vastdb/table.py +60 -24
- vastdb/table_metadata.py +58 -34
- vastdb/tests/test_adbc_integration.py +89 -0
- vastdb/tests/test_projections.py +49 -1
- vastdb/tests/test_tables.py +35 -1
- vastdb/tests/test_vector_index.py +162 -0
- vastdb/tests/test_vector_search.py +210 -0
- vastdb/tests/util.py +3 -2
- vastdb/transaction.py +30 -0
- vastdb/vast_flatbuf/tabular/GetTableStatsResponse.py +51 -59
- vastdb/vast_flatbuf/tabular/ObjectDetails.py +36 -59
- vastdb/vast_flatbuf/tabular/VectorIndexMetadata.py +67 -0
- vastdb/vast_flatbuf/tabular/VipRange.py +19 -12
- {vastdb-2.0.1.dist-info → vastdb-2.0.3.dist-info}/METADATA +2 -1
- {vastdb-2.0.1.dist-info → vastdb-2.0.3.dist-info}/RECORD +25 -20
- {vastdb-2.0.1.dist-info → vastdb-2.0.3.dist-info}/WHEEL +0 -0
- {vastdb-2.0.1.dist-info → vastdb-2.0.3.dist-info}/licenses/LICENSE +0 -0
- {vastdb-2.0.1.dist-info → vastdb-2.0.3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"""Tests for vector index functionality."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
import pyarrow as pa
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
from vastdb import errors
|
|
10
|
+
from vastdb._internal import VectorIndexSpec
|
|
11
|
+
from vastdb.session import Session
|
|
12
|
+
|
|
13
|
+
log = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@pytest.mark.parametrize("table_name,vector_index", [
|
|
17
|
+
# Test 1: Table without vector index
|
|
18
|
+
("table_without_index", None),
|
|
19
|
+
# Test 2: Table with L2 vector index
|
|
20
|
+
("table_with_l2_index", VectorIndexSpec("embedding", "l2sq")),
|
|
21
|
+
# Test 3: Table with inner product vector index
|
|
22
|
+
("table_with_ip_index", VectorIndexSpec("embedding", "ip")),
|
|
23
|
+
])
|
|
24
|
+
def test_create_table_with_vector_index_metadata(session: Session,
|
|
25
|
+
clean_bucket_name: str,
|
|
26
|
+
table_name: str,
|
|
27
|
+
vector_index: Optional[VectorIndexSpec]):
|
|
28
|
+
"""Test that table creation and stats retrieval work correctly with vector index metadata."""
|
|
29
|
+
schema_name = "schema1"
|
|
30
|
+
|
|
31
|
+
with session.transaction() as tx:
|
|
32
|
+
log.info(f"Testing table '{table_name}' with {vector_index}")
|
|
33
|
+
|
|
34
|
+
# Create schema
|
|
35
|
+
bucket = tx.bucket(clean_bucket_name)
|
|
36
|
+
schema = bucket.create_schema(schema_name)
|
|
37
|
+
|
|
38
|
+
# Create the appropriate schema based on whether vector index is needed
|
|
39
|
+
if vector_index is None:
|
|
40
|
+
# Simple table without vector index
|
|
41
|
+
arrow_schema = pa.schema([
|
|
42
|
+
('id', pa.int64()),
|
|
43
|
+
('data', pa.string())
|
|
44
|
+
])
|
|
45
|
+
else:
|
|
46
|
+
# Table with vector column
|
|
47
|
+
vector_dimension = 128 # Fixed-size vector dimension
|
|
48
|
+
vec_type = pa.list_(pa.field('', pa.float32(), False), vector_dimension)
|
|
49
|
+
arrow_schema = pa.schema([
|
|
50
|
+
('id', pa.int64()),
|
|
51
|
+
('embedding', vec_type) # Fixed-size vector column
|
|
52
|
+
])
|
|
53
|
+
|
|
54
|
+
# Create table with or without vector index
|
|
55
|
+
log.info(f"Creating table: {table_name}")
|
|
56
|
+
table = schema.create_table(
|
|
57
|
+
table_name=table_name,
|
|
58
|
+
columns=arrow_schema,
|
|
59
|
+
vector_index=vector_index
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
# Reload stats to ensure we get the vector index metadata
|
|
63
|
+
table.reload_stats()
|
|
64
|
+
|
|
65
|
+
# Get vector index metadata
|
|
66
|
+
result_vector_index = table._metadata._vector_index
|
|
67
|
+
|
|
68
|
+
log.info(f"Vector index metadata: {result_vector_index}")
|
|
69
|
+
|
|
70
|
+
# Assert expected values (should match input parameters)
|
|
71
|
+
result_vector_index_spec = (
|
|
72
|
+
None
|
|
73
|
+
if result_vector_index is None
|
|
74
|
+
else result_vector_index.to_vector_index_spec()
|
|
75
|
+
)
|
|
76
|
+
assert result_vector_index_spec == vector_index
|
|
77
|
+
|
|
78
|
+
log.info(f"✓ Test passed for table '{table_name}'")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@pytest.mark.parametrize("table_name,vector_index,expected_error", [
|
|
82
|
+
# Test 1: Invalid column name (column doesn't exist in schema)
|
|
83
|
+
("table_invalid_column", VectorIndexSpec("nonexistent_column", "l2sq"), "invalid vector indexed column name nonexistent_column"),
|
|
84
|
+
# Test 2: Invalid distance metric
|
|
85
|
+
("table_invalid_metric", VectorIndexSpec("embedding", "invalid_metric"), "invalid vector index distance metric invalid_metric, supported metrics: 'l2sq', 'ip'"),
|
|
86
|
+
])
|
|
87
|
+
def test_create_table_with_invalid_vector_index(session: Session,
|
|
88
|
+
clean_bucket_name: str,
|
|
89
|
+
table_name: str,
|
|
90
|
+
vector_index: VectorIndexSpec,
|
|
91
|
+
expected_error: str):
|
|
92
|
+
"""Test that table creation fails with appropriate error messages for invalid vector index parameters."""
|
|
93
|
+
schema_name = "schema1"
|
|
94
|
+
|
|
95
|
+
with session.transaction() as tx:
|
|
96
|
+
log.info(f"Testing invalid table '{table_name}' with vector_index={vector_index}, expected_error={expected_error}")
|
|
97
|
+
|
|
98
|
+
# Create schema
|
|
99
|
+
bucket = tx.bucket(clean_bucket_name)
|
|
100
|
+
schema = bucket.create_schema(schema_name)
|
|
101
|
+
|
|
102
|
+
# Table with vector column
|
|
103
|
+
vector_dimension = 128 # Fixed-size vector dimension
|
|
104
|
+
vec_type = pa.list_(pa.field('', pa.float32(), False), vector_dimension)
|
|
105
|
+
arrow_schema = pa.schema([
|
|
106
|
+
('id', pa.int64()),
|
|
107
|
+
('embedding', vec_type) # Fixed-size vector column
|
|
108
|
+
])
|
|
109
|
+
|
|
110
|
+
# Attempt to create table with invalid parameters - should raise an error
|
|
111
|
+
log.info(f"Attempting to create invalid table: {table_name}")
|
|
112
|
+
with pytest.raises((errors.BadRequest)) as exc_info:
|
|
113
|
+
schema.create_table(
|
|
114
|
+
table_name=table_name,
|
|
115
|
+
columns=arrow_schema,
|
|
116
|
+
vector_index=vector_index
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# Verify the error message contains the expected error text
|
|
120
|
+
assert expected_error in str(exc_info.value), \
|
|
121
|
+
f"Expected error message to contain '{expected_error}', got '{str(exc_info.value)}'"
|
|
122
|
+
|
|
123
|
+
log.info(f"✓ Test passed for invalid table '{table_name}'")
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def test_vector_index_metadata_from_stats(session: Session, clean_bucket_name: str):
|
|
127
|
+
"""Test that vector index metadata is correctly retrieved from table stats."""
|
|
128
|
+
schema_name = "schema1"
|
|
129
|
+
table_name = "vector_table"
|
|
130
|
+
|
|
131
|
+
with session.transaction() as tx:
|
|
132
|
+
# Create schema
|
|
133
|
+
bucket = tx.bucket(clean_bucket_name)
|
|
134
|
+
schema = bucket.create_schema(schema_name)
|
|
135
|
+
|
|
136
|
+
# Create table with vector index
|
|
137
|
+
vector_dimension = 128
|
|
138
|
+
vec_type = pa.list_(pa.field('', pa.float32(), False), vector_dimension)
|
|
139
|
+
arrow_schema = pa.schema([
|
|
140
|
+
('id', pa.int64()),
|
|
141
|
+
('embedding', vec_type)
|
|
142
|
+
])
|
|
143
|
+
|
|
144
|
+
table = schema.create_table(
|
|
145
|
+
table_name=table_name,
|
|
146
|
+
columns=arrow_schema,
|
|
147
|
+
vector_index=VectorIndexSpec("embedding", "l2sq")
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
# Check stats object directly
|
|
151
|
+
stats = table.stats
|
|
152
|
+
assert stats is not None
|
|
153
|
+
assert stats.vector_index is not None
|
|
154
|
+
assert stats.vector_index.column == "embedding"
|
|
155
|
+
assert stats.vector_index.distance_metric == "l2sq"
|
|
156
|
+
|
|
157
|
+
# Check via the table methods
|
|
158
|
+
assert table._metadata._vector_index is not None
|
|
159
|
+
assert table._metadata._vector_index.column == "embedding"
|
|
160
|
+
assert table._metadata._vector_index.distance_metric == "l2sq"
|
|
161
|
+
|
|
162
|
+
log.info("✓ Vector index metadata correctly retrieved from stats")
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
from collections import defaultdict
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import pyarrow as pa
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
from vastdb._adbc import _ibis_to_qe_predicates
|
|
8
|
+
from vastdb._internal import VectorIndex, VectorIndexSpec
|
|
9
|
+
from vastdb._table_interface import IbisPredicate
|
|
10
|
+
from vastdb.conftest import SessionFactory
|
|
11
|
+
from vastdb.table_metadata import TableMetadata, TableRef, TableType
|
|
12
|
+
|
|
13
|
+
DIM = 8
|
|
14
|
+
TEST_DISTANCE_FUNC = 'array_distance'
|
|
15
|
+
TEST_DISTANCE_METRIC = 'l2sq'
|
|
16
|
+
|
|
17
|
+
VectorColumnArrowType = pa.list_(
|
|
18
|
+
pa.field(name='item', type=pa.float32(), nullable=False), DIM)
|
|
19
|
+
|
|
20
|
+
query_vector: np.ndarray = np.ones(DIM)
|
|
21
|
+
first_closest_vector = (query_vector * 1.1).tolist()
|
|
22
|
+
second_closest_vector = (query_vector * 1.2).tolist()
|
|
23
|
+
third_closest_vector = (query_vector * 1.3).tolist()
|
|
24
|
+
fourth_closest_vector = (query_vector * 1.4).tolist()
|
|
25
|
+
fifth_closest_vector = (query_vector * 1.5).tolist()
|
|
26
|
+
furthest_vector = (np.ones(DIM) * 5).tolist()
|
|
27
|
+
|
|
28
|
+
vector_column_name = 'vector_col'
|
|
29
|
+
|
|
30
|
+
data = [
|
|
31
|
+
{
|
|
32
|
+
"id": 0,
|
|
33
|
+
"n1": 1,
|
|
34
|
+
"n2": 100,
|
|
35
|
+
vector_column_name: first_closest_vector,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"id": 1,
|
|
39
|
+
"n1": 2,
|
|
40
|
+
"n2": 100,
|
|
41
|
+
vector_column_name: second_closest_vector,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"id": 2,
|
|
45
|
+
"n1": 3,
|
|
46
|
+
"n2": 200,
|
|
47
|
+
vector_column_name: third_closest_vector,
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"id": 3,
|
|
51
|
+
"n1": 4,
|
|
52
|
+
"n2": 200,
|
|
53
|
+
vector_column_name: fourth_closest_vector,
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"id": 4,
|
|
57
|
+
"n1": 5,
|
|
58
|
+
"n2": 200,
|
|
59
|
+
vector_column_name: fifth_closest_vector,
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"id": 5,
|
|
63
|
+
"n1": 6,
|
|
64
|
+
"n2": 200,
|
|
65
|
+
vector_column_name: furthest_vector,
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def into_arrow_arrays(data: list[dict]) -> list[list]:
|
|
72
|
+
agg = defaultdict(list)
|
|
73
|
+
for d in data:
|
|
74
|
+
for k, v in d.items():
|
|
75
|
+
agg[k].append(v)
|
|
76
|
+
|
|
77
|
+
return [v for v in agg.values()]
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def test_sanity(session_factory: SessionFactory, clean_bucket_name: str):
|
|
81
|
+
session = session_factory(with_adbc=True)
|
|
82
|
+
|
|
83
|
+
arrow_schema = pa.schema([('id', pa.int32()), ('n1', pa.int32(
|
|
84
|
+
)), ('n2', pa.int32()), (vector_column_name, VectorColumnArrowType),])
|
|
85
|
+
|
|
86
|
+
limit = 3
|
|
87
|
+
|
|
88
|
+
ref = TableRef(clean_bucket_name, 's', 't')
|
|
89
|
+
table_md = TableMetadata(ref,
|
|
90
|
+
arrow_schema,
|
|
91
|
+
TableType.Regular,
|
|
92
|
+
vector_index=VectorIndex(vector_column_name,
|
|
93
|
+
TEST_DISTANCE_METRIC,
|
|
94
|
+
TEST_DISTANCE_FUNC))
|
|
95
|
+
data_table = pa.table(schema=arrow_schema, data=into_arrow_arrays(data))
|
|
96
|
+
|
|
97
|
+
with session.transaction() as tx:
|
|
98
|
+
table = tx.bucket(clean_bucket_name).create_schema(
|
|
99
|
+
's').create_table('t', arrow_schema)
|
|
100
|
+
table.insert(data_table)
|
|
101
|
+
|
|
102
|
+
# TODO merge in same tx
|
|
103
|
+
with session.transaction() as tx:
|
|
104
|
+
table = tx.table_from_metadata(table_md)
|
|
105
|
+
|
|
106
|
+
reader = table.vector_search(vec=query_vector.tolist(),
|
|
107
|
+
columns=['id', 'n1', 'n2'],
|
|
108
|
+
limit=limit)
|
|
109
|
+
|
|
110
|
+
result_table = reader.read_all()
|
|
111
|
+
|
|
112
|
+
assert set([v.as_py() for v in result_table['n1']]) == {1, 2, 3}
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def test_with_predicates(session_factory: SessionFactory, clean_bucket_name: str):
|
|
116
|
+
session = session_factory(with_adbc=True)
|
|
117
|
+
|
|
118
|
+
vector_column_name = 'vector_column'
|
|
119
|
+
arrow_schema = pa.schema([('id', pa.int32()), ('n1', pa.int32(
|
|
120
|
+
)), ('n2', pa.int32()), (vector_column_name, VectorColumnArrowType),])
|
|
121
|
+
limit = 3
|
|
122
|
+
|
|
123
|
+
ref = TableRef(clean_bucket_name, 's', 't')
|
|
124
|
+
table_md = TableMetadata(ref, arrow_schema, TableType.Regular,
|
|
125
|
+
vector_index=VectorIndex(vector_column_name,
|
|
126
|
+
TEST_DISTANCE_METRIC,
|
|
127
|
+
TEST_DISTANCE_FUNC))
|
|
128
|
+
data_table = pa.table(schema=arrow_schema, data=into_arrow_arrays(data))
|
|
129
|
+
|
|
130
|
+
with session.transaction() as tx:
|
|
131
|
+
table = tx.bucket(clean_bucket_name).create_schema(
|
|
132
|
+
's').create_table('t', arrow_schema)
|
|
133
|
+
table.insert(data_table)
|
|
134
|
+
|
|
135
|
+
with session.transaction() as tx:
|
|
136
|
+
table = tx.table_from_metadata(table_md)
|
|
137
|
+
|
|
138
|
+
pred = table_md.ibis_table['n2'] == 200
|
|
139
|
+
reader = table.vector_search(vec=query_vector.tolist(),
|
|
140
|
+
columns=['id', 'n1', 'n2'],
|
|
141
|
+
limit=limit,
|
|
142
|
+
predicate=pred)
|
|
143
|
+
|
|
144
|
+
result_table = reader.read_all()
|
|
145
|
+
|
|
146
|
+
assert set([v.as_py() for v in result_table['n1']]) == {3, 4, 5}
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
arrow_schema = pa.schema([('id', pa.int32()), ('n1', pa.int32(
|
|
150
|
+
)), ('n2', pa.int32()), (vector_column_name, VectorColumnArrowType),])
|
|
151
|
+
|
|
152
|
+
ref = TableRef('b', 's', 't')
|
|
153
|
+
table_md = TableMetadata(ref, arrow_schema, TableType.Regular)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
@pytest.mark.parametrize('ibis_predicate, expected', [
|
|
157
|
+
((table_md.ibis_table['n1'] == 1) & (table_md.ibis_table['n2'] == 2),
|
|
158
|
+
'("n1" = 1) AND ("n2" = 2)'),
|
|
159
|
+
((table_md.ibis_table['n1'] == 1),
|
|
160
|
+
'"n1" = 1')
|
|
161
|
+
])
|
|
162
|
+
def test_ibis_to_query_engine_predicates(ibis_predicate: IbisPredicate, expected: str):
|
|
163
|
+
assert _ibis_to_qe_predicates(ibis_predicate) == expected
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def test_with_predicates_get_vector_index_properties_from_server(
|
|
167
|
+
session_factory: SessionFactory,
|
|
168
|
+
clean_bucket_name: str
|
|
169
|
+
):
|
|
170
|
+
session = session_factory(with_adbc=True)
|
|
171
|
+
|
|
172
|
+
vector_column_name = 'vector_column'
|
|
173
|
+
vector_index_distance_metric = 'l2sq'
|
|
174
|
+
vector_index_sql_distance_function = "array_distance"
|
|
175
|
+
|
|
176
|
+
arrow_schema = pa.schema([('id', pa.int32()), ('n1', pa.int32(
|
|
177
|
+
)), ('n2', pa.int32()), (vector_column_name, VectorColumnArrowType),])
|
|
178
|
+
limit = 3
|
|
179
|
+
|
|
180
|
+
ref = TableRef(clean_bucket_name, 's', 't')
|
|
181
|
+
table_md = TableMetadata(ref, arrow_schema, TableType.Regular)
|
|
182
|
+
data_table = pa.table(schema=arrow_schema, data=into_arrow_arrays(data))
|
|
183
|
+
|
|
184
|
+
with session.transaction() as tx:
|
|
185
|
+
table = (tx.bucket(clean_bucket_name)
|
|
186
|
+
.create_schema('s')
|
|
187
|
+
.create_table('t',
|
|
188
|
+
arrow_schema,
|
|
189
|
+
vector_index=VectorIndexSpec(vector_column_name,
|
|
190
|
+
vector_index_distance_metric)))
|
|
191
|
+
table.insert(data_table)
|
|
192
|
+
|
|
193
|
+
with session.transaction() as tx:
|
|
194
|
+
table = tx.table_from_metadata(table_md)
|
|
195
|
+
|
|
196
|
+
table.reload_stats()
|
|
197
|
+
assert table.vector_index == VectorIndex(
|
|
198
|
+
column=vector_column_name,
|
|
199
|
+
distance_metric=vector_index_distance_metric,
|
|
200
|
+
sql_distance_function=vector_index_sql_distance_function)
|
|
201
|
+
|
|
202
|
+
pred = table_md.ibis_table['n2'] == 200
|
|
203
|
+
reader = table.vector_search(vec=query_vector.tolist(),
|
|
204
|
+
columns=['id', 'n1', 'n2'],
|
|
205
|
+
limit=limit,
|
|
206
|
+
predicate=pred)
|
|
207
|
+
|
|
208
|
+
result_table = reader.read_all()
|
|
209
|
+
|
|
210
|
+
assert set([v.as_py() for v in result_table['n1']]) == {3, 4, 5}
|
vastdb/tests/util.py
CHANGED
|
@@ -25,11 +25,12 @@ def assert_row_ids_ascending_on_first_insertion_to_table(row_ids, expected_num_r
|
|
|
25
25
|
@contextmanager
|
|
26
26
|
def prepare_data(session: Session,
|
|
27
27
|
clean_bucket_name: str, schema_name: str, table_name: str,
|
|
28
|
-
arrow_table: pa.Table, sorting_key: List[str] = []
|
|
28
|
+
arrow_table: pa.Table, sorting_key: List[str] = [],
|
|
29
|
+
insert_by_columns: bool = True) -> Iterator[Table]:
|
|
29
30
|
with session.transaction() as tx:
|
|
30
31
|
s = tx.bucket(clean_bucket_name).create_schema(schema_name)
|
|
31
32
|
t = s.create_table(table_name, arrow_table.schema, sorting_key=sorting_key)
|
|
32
|
-
row_ids_array = t.insert(arrow_table)
|
|
33
|
+
row_ids_array = t.insert(arrow_table, by_columns=insert_by_columns)
|
|
33
34
|
row_ids = row_ids_array.to_pylist()
|
|
34
35
|
assert_row_ids_ascending_on_first_insertion_to_table(row_ids, arrow_table.num_rows, t.sorted_table)
|
|
35
36
|
yield t
|
vastdb/transaction.py
CHANGED
|
@@ -11,6 +11,7 @@ from copy import deepcopy
|
|
|
11
11
|
from dataclasses import dataclass
|
|
12
12
|
from typing import TYPE_CHECKING, Iterable, Optional
|
|
13
13
|
|
|
14
|
+
from vastdb._adbc import AdbcConnection, AdbcDriver
|
|
14
15
|
from vastdb._table_interface import ITable
|
|
15
16
|
from vastdb.table import TableInTransaction
|
|
16
17
|
from vastdb.table_metadata import TableMetadata
|
|
@@ -39,17 +40,35 @@ class TransactionNotActiveError(Exception):
|
|
|
39
40
|
pass
|
|
40
41
|
|
|
41
42
|
|
|
43
|
+
class NoAdbcConnectionError(Exception):
|
|
44
|
+
"""No Adbc Connection Error."""
|
|
45
|
+
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
|
|
42
49
|
@dataclass
|
|
43
50
|
class Transaction:
|
|
44
51
|
"""A holder of a single VAST transaction."""
|
|
45
52
|
|
|
46
53
|
_rpc: "session.Session"
|
|
47
54
|
txid: Optional[int] = None
|
|
55
|
+
_adbc_driver: Optional[AdbcDriver] = None
|
|
56
|
+
_adbc_conn: Optional[AdbcConnection] = None
|
|
48
57
|
|
|
49
58
|
def __enter__(self):
|
|
50
59
|
"""Create a transaction and store its ID."""
|
|
51
60
|
response = self._rpc.api.begin_transaction()
|
|
52
61
|
self.txid = int(response.headers['tabular-txid'])
|
|
62
|
+
|
|
63
|
+
if self._adbc_driver is not None:
|
|
64
|
+
self._adbc_conn = AdbcConnection(
|
|
65
|
+
self._adbc_driver,
|
|
66
|
+
self._rpc.endpoint,
|
|
67
|
+
self._rpc.access,
|
|
68
|
+
self._rpc.secret,
|
|
69
|
+
self.txid,
|
|
70
|
+
)
|
|
71
|
+
|
|
53
72
|
log.debug("opened txid=%016x", self.txid)
|
|
54
73
|
return self
|
|
55
74
|
|
|
@@ -57,6 +76,10 @@ class Transaction:
|
|
|
57
76
|
"""On success, the transaction is committed. Otherwise, it is rolled back."""
|
|
58
77
|
txid = self.txid
|
|
59
78
|
self.txid = None
|
|
79
|
+
if self._adbc_conn is not None:
|
|
80
|
+
self.adbc_conn.close()
|
|
81
|
+
self._adbc_conn = None
|
|
82
|
+
|
|
60
83
|
if (exc_type, exc_value, exc_traceback) == (None, None, None):
|
|
61
84
|
log.debug("committing txid=%016x", txid)
|
|
62
85
|
self._rpc.api.commit_transaction(txid)
|
|
@@ -110,3 +133,10 @@ class Transaction:
|
|
|
110
133
|
def table_from_metadata(self, metadata: TableMetadata) -> ITable:
|
|
111
134
|
"""Create Table from TableMetadata."""
|
|
112
135
|
return TableInTransaction(deepcopy(metadata), tx=self)
|
|
136
|
+
|
|
137
|
+
@property
|
|
138
|
+
def adbc_conn(self) -> AdbcConnection:
|
|
139
|
+
"""ADBC connection in transaction."""
|
|
140
|
+
if self._adbc_conn is None:
|
|
141
|
+
raise NoAdbcConnectionError("Adbc Driver may not have been supplied")
|
|
142
|
+
return self._adbc_conn
|
|
@@ -105,74 +105,66 @@ class GetTableStatsResponse(object):
|
|
|
105
105
|
return self._tab.Get(flatbuffers.number_types.Int64Flags, o + self._tab.Pos)
|
|
106
106
|
return 0
|
|
107
107
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
108
|
+
# GetTableStatsResponse
|
|
109
|
+
def VectorIndexMetadata(self):
|
|
110
|
+
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(22))
|
|
111
|
+
if o != 0:
|
|
112
|
+
x = self._tab.Indirect(o + self._tab.Pos)
|
|
113
|
+
from vastdb.vast_flatbuf.tabular.VectorIndexMetadata import VectorIndexMetadata
|
|
114
|
+
obj = VectorIndexMetadata()
|
|
115
|
+
obj.Init(self._tab.Bytes, x)
|
|
116
|
+
return obj
|
|
117
|
+
return None
|
|
113
118
|
|
|
119
|
+
def Start(builder): builder.StartObject(10)
|
|
120
|
+
def GetTableStatsResponseStart(builder):
|
|
121
|
+
"""This method is deprecated. Please switch to Start."""
|
|
122
|
+
return Start(builder)
|
|
123
|
+
def AddNumRows(builder, numRows): builder.PrependInt64Slot(0, numRows, 0)
|
|
114
124
|
def GetTableStatsResponseAddNumRows(builder, numRows):
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
def
|
|
118
|
-
GetTableStatsResponseAddNumRows(builder, numRows)
|
|
119
|
-
|
|
125
|
+
"""This method is deprecated. Please switch to AddNumRows."""
|
|
126
|
+
return AddNumRows(builder, numRows)
|
|
127
|
+
def AddSizeInBytes(builder, sizeInBytes): builder.PrependInt64Slot(1, sizeInBytes, 0)
|
|
120
128
|
def GetTableStatsResponseAddSizeInBytes(builder, sizeInBytes):
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
def
|
|
124
|
-
GetTableStatsResponseAddSizeInBytes(builder, sizeInBytes)
|
|
125
|
-
|
|
129
|
+
"""This method is deprecated. Please switch to AddSizeInBytes."""
|
|
130
|
+
return AddSizeInBytes(builder, sizeInBytes)
|
|
131
|
+
def AddIsExternalRowidAlloc(builder, isExternalRowidAlloc): builder.PrependBoolSlot(2, isExternalRowidAlloc, 0)
|
|
126
132
|
def GetTableStatsResponseAddIsExternalRowidAlloc(builder, isExternalRowidAlloc):
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
def
|
|
130
|
-
GetTableStatsResponseAddIsExternalRowidAlloc(builder, isExternalRowidAlloc)
|
|
131
|
-
|
|
133
|
+
"""This method is deprecated. Please switch to AddIsExternalRowidAlloc."""
|
|
134
|
+
return AddIsExternalRowidAlloc(builder, isExternalRowidAlloc)
|
|
135
|
+
def AddAddressType(builder, addressType): builder.PrependUOffsetTRelativeSlot(3, flatbuffers.number_types.UOffsetTFlags.py_type(addressType), 0)
|
|
132
136
|
def GetTableStatsResponseAddAddressType(builder, addressType):
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
def
|
|
136
|
-
GetTableStatsResponseAddAddressType(builder, addressType)
|
|
137
|
-
|
|
137
|
+
"""This method is deprecated. Please switch to AddAddressType."""
|
|
138
|
+
return AddAddressType(builder, addressType)
|
|
139
|
+
def AddVips(builder, vips): builder.PrependUOffsetTRelativeSlot(4, flatbuffers.number_types.UOffsetTFlags.py_type(vips), 0)
|
|
138
140
|
def GetTableStatsResponseAddVips(builder, vips):
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
def
|
|
142
|
-
GetTableStatsResponseAddVips(builder, vips)
|
|
143
|
-
|
|
141
|
+
"""This method is deprecated. Please switch to AddVips."""
|
|
142
|
+
return AddVips(builder, vips)
|
|
143
|
+
def StartVipsVector(builder, numElems): return builder.StartVector(4, numElems, 4)
|
|
144
144
|
def GetTableStatsResponseStartVipsVector(builder, numElems):
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
def
|
|
148
|
-
return GetTableStatsResponseStartVipsVector(builder, numElems)
|
|
149
|
-
|
|
145
|
+
"""This method is deprecated. Please switch to Start."""
|
|
146
|
+
return StartVipsVector(builder, numElems)
|
|
147
|
+
def AddSortingKeyEnabled(builder, sortingKeyEnabled): builder.PrependBoolSlot(5, sortingKeyEnabled, 0)
|
|
150
148
|
def GetTableStatsResponseAddSortingKeyEnabled(builder, sortingKeyEnabled):
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
def
|
|
154
|
-
GetTableStatsResponseAddSortingKeyEnabled(builder, sortingKeyEnabled)
|
|
155
|
-
|
|
149
|
+
"""This method is deprecated. Please switch to AddSortingKeyEnabled."""
|
|
150
|
+
return AddSortingKeyEnabled(builder, sortingKeyEnabled)
|
|
151
|
+
def AddSortingScore(builder, sortingScore): builder.PrependInt64Slot(6, sortingScore, 0)
|
|
156
152
|
def GetTableStatsResponseAddSortingScore(builder, sortingScore):
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
def
|
|
160
|
-
GetTableStatsResponseAddSortingScore(builder, sortingScore)
|
|
161
|
-
|
|
153
|
+
"""This method is deprecated. Please switch to AddSortingScore."""
|
|
154
|
+
return AddSortingScore(builder, sortingScore)
|
|
155
|
+
def AddWriteAmplification(builder, writeAmplification): builder.PrependInt64Slot(7, writeAmplification, 0)
|
|
162
156
|
def GetTableStatsResponseAddWriteAmplification(builder, writeAmplification):
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
def
|
|
166
|
-
GetTableStatsResponseAddWriteAmplification(builder, writeAmplification)
|
|
167
|
-
|
|
157
|
+
"""This method is deprecated. Please switch to AddWriteAmplification."""
|
|
158
|
+
return AddWriteAmplification(builder, writeAmplification)
|
|
159
|
+
def AddAcummulativeRowInseritionCount(builder, acummulativeRowInseritionCount): builder.PrependInt64Slot(8, acummulativeRowInseritionCount, 0)
|
|
168
160
|
def GetTableStatsResponseAddAcummulativeRowInseritionCount(builder, acummulativeRowInseritionCount):
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
def
|
|
172
|
-
|
|
173
|
-
|
|
161
|
+
"""This method is deprecated. Please switch to AddAcummulativeRowInseritionCount."""
|
|
162
|
+
return AddAcummulativeRowInseritionCount(builder, acummulativeRowInseritionCount)
|
|
163
|
+
def AddVectorIndexMetadata(builder, vectorIndexMetadata): builder.PrependUOffsetTRelativeSlot(9, flatbuffers.number_types.UOffsetTFlags.py_type(vectorIndexMetadata), 0)
|
|
164
|
+
def GetTableStatsResponseAddVectorIndexMetadata(builder, vectorIndexMetadata):
|
|
165
|
+
"""This method is deprecated. Please switch to AddVectorIndexMetadata."""
|
|
166
|
+
return AddVectorIndexMetadata(builder, vectorIndexMetadata)
|
|
167
|
+
def End(builder): return builder.EndObject()
|
|
174
168
|
def GetTableStatsResponseEnd(builder):
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
def End(builder):
|
|
178
|
-
return GetTableStatsResponseEnd(builder)
|
|
169
|
+
"""This method is deprecated. Please switch to End."""
|
|
170
|
+
return End(builder)
|