sqlspec 0.16.1__cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.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.
Potentially problematic release.
This version of sqlspec might be problematic. Click here for more details.
- 51ff5a9eadfdefd49f98__mypyc.cpython-312-aarch64-linux-gnu.so +0 -0
- sqlspec/__init__.py +92 -0
- sqlspec/__main__.py +12 -0
- sqlspec/__metadata__.py +14 -0
- sqlspec/_serialization.py +77 -0
- sqlspec/_sql.py +1780 -0
- sqlspec/_typing.py +680 -0
- sqlspec/adapters/__init__.py +0 -0
- sqlspec/adapters/adbc/__init__.py +5 -0
- sqlspec/adapters/adbc/_types.py +12 -0
- sqlspec/adapters/adbc/config.py +361 -0
- sqlspec/adapters/adbc/driver.py +512 -0
- sqlspec/adapters/aiosqlite/__init__.py +19 -0
- sqlspec/adapters/aiosqlite/_types.py +13 -0
- sqlspec/adapters/aiosqlite/config.py +253 -0
- sqlspec/adapters/aiosqlite/driver.py +248 -0
- sqlspec/adapters/asyncmy/__init__.py +19 -0
- sqlspec/adapters/asyncmy/_types.py +12 -0
- sqlspec/adapters/asyncmy/config.py +180 -0
- sqlspec/adapters/asyncmy/driver.py +274 -0
- sqlspec/adapters/asyncpg/__init__.py +21 -0
- sqlspec/adapters/asyncpg/_types.py +17 -0
- sqlspec/adapters/asyncpg/config.py +229 -0
- sqlspec/adapters/asyncpg/driver.py +344 -0
- sqlspec/adapters/bigquery/__init__.py +18 -0
- sqlspec/adapters/bigquery/_types.py +12 -0
- sqlspec/adapters/bigquery/config.py +298 -0
- sqlspec/adapters/bigquery/driver.py +558 -0
- sqlspec/adapters/duckdb/__init__.py +22 -0
- sqlspec/adapters/duckdb/_types.py +12 -0
- sqlspec/adapters/duckdb/config.py +504 -0
- sqlspec/adapters/duckdb/driver.py +368 -0
- sqlspec/adapters/oracledb/__init__.py +32 -0
- sqlspec/adapters/oracledb/_types.py +14 -0
- sqlspec/adapters/oracledb/config.py +317 -0
- sqlspec/adapters/oracledb/driver.py +538 -0
- sqlspec/adapters/psqlpy/__init__.py +16 -0
- sqlspec/adapters/psqlpy/_types.py +11 -0
- sqlspec/adapters/psqlpy/config.py +214 -0
- sqlspec/adapters/psqlpy/driver.py +530 -0
- sqlspec/adapters/psycopg/__init__.py +32 -0
- sqlspec/adapters/psycopg/_types.py +17 -0
- sqlspec/adapters/psycopg/config.py +426 -0
- sqlspec/adapters/psycopg/driver.py +796 -0
- sqlspec/adapters/sqlite/__init__.py +15 -0
- sqlspec/adapters/sqlite/_types.py +11 -0
- sqlspec/adapters/sqlite/config.py +240 -0
- sqlspec/adapters/sqlite/driver.py +294 -0
- sqlspec/base.py +571 -0
- sqlspec/builder/__init__.py +62 -0
- sqlspec/builder/_base.py +473 -0
- sqlspec/builder/_column.py +320 -0
- sqlspec/builder/_ddl.py +1346 -0
- sqlspec/builder/_ddl_utils.py +103 -0
- sqlspec/builder/_delete.py +76 -0
- sqlspec/builder/_insert.py +256 -0
- sqlspec/builder/_merge.py +71 -0
- sqlspec/builder/_parsing_utils.py +140 -0
- sqlspec/builder/_select.py +170 -0
- sqlspec/builder/_update.py +188 -0
- sqlspec/builder/mixins/__init__.py +55 -0
- sqlspec/builder/mixins/_cte_and_set_ops.py +222 -0
- sqlspec/builder/mixins/_delete_operations.py +41 -0
- sqlspec/builder/mixins/_insert_operations.py +244 -0
- sqlspec/builder/mixins/_join_operations.py +122 -0
- sqlspec/builder/mixins/_merge_operations.py +476 -0
- sqlspec/builder/mixins/_order_limit_operations.py +135 -0
- sqlspec/builder/mixins/_pivot_operations.py +153 -0
- sqlspec/builder/mixins/_select_operations.py +603 -0
- sqlspec/builder/mixins/_update_operations.py +187 -0
- sqlspec/builder/mixins/_where_clause.py +621 -0
- sqlspec/cli.py +247 -0
- sqlspec/config.py +395 -0
- sqlspec/core/__init__.py +63 -0
- sqlspec/core/cache.cpython-312-aarch64-linux-gnu.so +0 -0
- sqlspec/core/cache.py +871 -0
- sqlspec/core/compiler.cpython-312-aarch64-linux-gnu.so +0 -0
- sqlspec/core/compiler.py +417 -0
- sqlspec/core/filters.cpython-312-aarch64-linux-gnu.so +0 -0
- sqlspec/core/filters.py +830 -0
- sqlspec/core/hashing.cpython-312-aarch64-linux-gnu.so +0 -0
- sqlspec/core/hashing.py +310 -0
- sqlspec/core/parameters.cpython-312-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters.py +1237 -0
- sqlspec/core/result.cpython-312-aarch64-linux-gnu.so +0 -0
- sqlspec/core/result.py +677 -0
- sqlspec/core/splitter.cpython-312-aarch64-linux-gnu.so +0 -0
- sqlspec/core/splitter.py +819 -0
- sqlspec/core/statement.cpython-312-aarch64-linux-gnu.so +0 -0
- sqlspec/core/statement.py +676 -0
- sqlspec/driver/__init__.py +19 -0
- sqlspec/driver/_async.py +502 -0
- sqlspec/driver/_common.py +631 -0
- sqlspec/driver/_sync.py +503 -0
- sqlspec/driver/mixins/__init__.py +6 -0
- sqlspec/driver/mixins/_result_tools.py +193 -0
- sqlspec/driver/mixins/_sql_translator.py +86 -0
- sqlspec/exceptions.py +193 -0
- sqlspec/extensions/__init__.py +0 -0
- sqlspec/extensions/aiosql/__init__.py +10 -0
- sqlspec/extensions/aiosql/adapter.py +461 -0
- sqlspec/extensions/litestar/__init__.py +6 -0
- sqlspec/extensions/litestar/_utils.py +52 -0
- sqlspec/extensions/litestar/cli.py +48 -0
- sqlspec/extensions/litestar/config.py +92 -0
- sqlspec/extensions/litestar/handlers.py +260 -0
- sqlspec/extensions/litestar/plugin.py +145 -0
- sqlspec/extensions/litestar/providers.py +454 -0
- sqlspec/loader.cpython-312-aarch64-linux-gnu.so +0 -0
- sqlspec/loader.py +760 -0
- sqlspec/migrations/__init__.py +35 -0
- sqlspec/migrations/base.py +414 -0
- sqlspec/migrations/commands.py +443 -0
- sqlspec/migrations/loaders.py +402 -0
- sqlspec/migrations/runner.py +213 -0
- sqlspec/migrations/tracker.py +140 -0
- sqlspec/migrations/utils.py +129 -0
- sqlspec/protocols.py +407 -0
- sqlspec/py.typed +0 -0
- sqlspec/storage/__init__.py +23 -0
- sqlspec/storage/backends/__init__.py +0 -0
- sqlspec/storage/backends/base.py +163 -0
- sqlspec/storage/backends/fsspec.py +386 -0
- sqlspec/storage/backends/obstore.py +459 -0
- sqlspec/storage/capabilities.py +102 -0
- sqlspec/storage/registry.py +239 -0
- sqlspec/typing.py +299 -0
- sqlspec/utils/__init__.py +3 -0
- sqlspec/utils/correlation.py +150 -0
- sqlspec/utils/deprecation.py +106 -0
- sqlspec/utils/fixtures.cpython-312-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/fixtures.py +58 -0
- sqlspec/utils/logging.py +127 -0
- sqlspec/utils/module_loader.py +89 -0
- sqlspec/utils/serializers.py +4 -0
- sqlspec/utils/singleton.py +32 -0
- sqlspec/utils/sync_tools.cpython-312-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/sync_tools.py +237 -0
- sqlspec/utils/text.cpython-312-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/text.py +96 -0
- sqlspec/utils/type_guards.cpython-312-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/type_guards.py +1139 -0
- sqlspec-0.16.1.dist-info/METADATA +365 -0
- sqlspec-0.16.1.dist-info/RECORD +148 -0
- sqlspec-0.16.1.dist-info/WHEEL +7 -0
- sqlspec-0.16.1.dist-info/entry_points.txt +2 -0
- sqlspec-0.16.1.dist-info/licenses/LICENSE +21 -0
- sqlspec-0.16.1.dist-info/licenses/NOTICE +29 -0
|
Binary file
|
sqlspec/core/hashing.py
ADDED
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
"""Statement hashing utilities for cache key generation.
|
|
2
|
+
|
|
3
|
+
This module provides centralized hashing logic for SQL statements,
|
|
4
|
+
including expressions, parameters, filters, and complete SQL objects.
|
|
5
|
+
|
|
6
|
+
Also supports fine-grained AST sub-expression caching.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from typing import TYPE_CHECKING, Any, Optional
|
|
10
|
+
|
|
11
|
+
from sqlglot import exp
|
|
12
|
+
|
|
13
|
+
from sqlspec.utils.type_guards import is_typed_parameter
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from sqlspec.core.filters import StatementFilter
|
|
17
|
+
from sqlspec.core.statement import SQL
|
|
18
|
+
|
|
19
|
+
__all__ = (
|
|
20
|
+
"hash_expression",
|
|
21
|
+
"hash_expression_node",
|
|
22
|
+
"hash_optimized_expression",
|
|
23
|
+
"hash_parameters",
|
|
24
|
+
"hash_sql_statement",
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def hash_expression(expr: Optional[exp.Expression], _seen: Optional[set[int]] = None) -> int:
|
|
29
|
+
"""Generate deterministic hash from AST structure.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
expr: SQLGlot Expression to hash
|
|
33
|
+
_seen: Set of seen object IDs to handle circular references
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
Deterministic hash of the AST structure
|
|
37
|
+
"""
|
|
38
|
+
if expr is None:
|
|
39
|
+
return hash(None)
|
|
40
|
+
|
|
41
|
+
if _seen is None:
|
|
42
|
+
_seen = set()
|
|
43
|
+
|
|
44
|
+
expr_id = id(expr)
|
|
45
|
+
if expr_id in _seen:
|
|
46
|
+
return hash(expr_id)
|
|
47
|
+
|
|
48
|
+
_seen.add(expr_id)
|
|
49
|
+
|
|
50
|
+
# Build hash from type and args
|
|
51
|
+
components: list[Any] = [type(expr).__name__]
|
|
52
|
+
|
|
53
|
+
for key, value in sorted(expr.args.items()):
|
|
54
|
+
components.extend((key, _hash_value(value, _seen)))
|
|
55
|
+
|
|
56
|
+
return hash(tuple(components))
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _hash_value(value: Any, _seen: set[int]) -> int:
|
|
60
|
+
"""Hash different value types consistently.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
value: Value to hash (can be Expression, list, dict, or primitive)
|
|
64
|
+
_seen: Set of seen object IDs to handle circular references
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
Deterministic hash of the value
|
|
68
|
+
"""
|
|
69
|
+
if isinstance(value, exp.Expression):
|
|
70
|
+
return hash_expression(value, _seen)
|
|
71
|
+
if isinstance(value, list):
|
|
72
|
+
return hash(tuple(_hash_value(v, _seen) for v in value))
|
|
73
|
+
if isinstance(value, dict):
|
|
74
|
+
items = sorted((k, _hash_value(v, _seen)) for k, v in value.items())
|
|
75
|
+
return hash(tuple(items))
|
|
76
|
+
if isinstance(value, tuple):
|
|
77
|
+
return hash(tuple(_hash_value(v, _seen) for v in value))
|
|
78
|
+
# Primitives: str, int, bool, None, etc.
|
|
79
|
+
return hash(value)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def hash_parameters(
|
|
83
|
+
positional_parameters: Optional[list[Any]] = None,
|
|
84
|
+
named_parameters: Optional[dict[str, Any]] = None,
|
|
85
|
+
original_parameters: Optional[Any] = None,
|
|
86
|
+
) -> int:
|
|
87
|
+
"""Generate hash for SQL parameters.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
positional_parameters: List of positional parameters
|
|
91
|
+
named_parameters: Dictionary of named parameters
|
|
92
|
+
original_parameters: Original parameters (for execute_many)
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
Combined hash of all parameters
|
|
96
|
+
"""
|
|
97
|
+
param_hash = 0
|
|
98
|
+
|
|
99
|
+
# Hash positional parameters
|
|
100
|
+
if positional_parameters:
|
|
101
|
+
from sqlspec.core.parameters import TypedParameter
|
|
102
|
+
|
|
103
|
+
hashable_parameters: list[tuple[Any, Any]] = []
|
|
104
|
+
for param in positional_parameters:
|
|
105
|
+
if isinstance(param, TypedParameter):
|
|
106
|
+
if isinstance(param.value, (list, dict)):
|
|
107
|
+
hashable_parameters.append((repr(param.value), param.original_type))
|
|
108
|
+
else:
|
|
109
|
+
hashable_parameters.append((param.value, param.original_type))
|
|
110
|
+
elif isinstance(param, (list, dict)):
|
|
111
|
+
# Convert unhashable types to hashable representations
|
|
112
|
+
hashable_parameters.append((repr(param), "unhashable"))
|
|
113
|
+
else:
|
|
114
|
+
# Check if param itself contains unhashable types
|
|
115
|
+
try:
|
|
116
|
+
hash(param)
|
|
117
|
+
hashable_parameters.append((param, "primitive"))
|
|
118
|
+
except TypeError:
|
|
119
|
+
# If unhashable, convert to string representation
|
|
120
|
+
hashable_parameters.append((repr(param), "unhashable_repr"))
|
|
121
|
+
|
|
122
|
+
param_hash ^= hash(tuple(hashable_parameters))
|
|
123
|
+
|
|
124
|
+
if named_parameters:
|
|
125
|
+
# Handle unhashable types in named parameters
|
|
126
|
+
hashable_items = []
|
|
127
|
+
for key, value in sorted(named_parameters.items()):
|
|
128
|
+
if is_typed_parameter(value):
|
|
129
|
+
# For TypedParameter, hash its value with type info
|
|
130
|
+
if isinstance(value.value, (list, dict)):
|
|
131
|
+
hashable_items.append((key, (repr(value.value), value.original_type)))
|
|
132
|
+
else:
|
|
133
|
+
hashable_items.append((key, (value.value, value.original_type)))
|
|
134
|
+
elif isinstance(value, (list, dict)):
|
|
135
|
+
hashable_items.append((key, (repr(value), "unhashable")))
|
|
136
|
+
else:
|
|
137
|
+
hashable_items.append((key, (value, "primitive")))
|
|
138
|
+
param_hash ^= hash(tuple(hashable_items))
|
|
139
|
+
|
|
140
|
+
# Hash original parameters (important for execute_many)
|
|
141
|
+
if original_parameters is not None:
|
|
142
|
+
if isinstance(original_parameters, list):
|
|
143
|
+
# For execute_many, hash the count and first few items to avoid
|
|
144
|
+
param_hash ^= hash(("original_count", len(original_parameters)))
|
|
145
|
+
if original_parameters:
|
|
146
|
+
# Hash first 3 items as representatives
|
|
147
|
+
sample_size = min(3, len(original_parameters))
|
|
148
|
+
sample_hash = hash(repr(original_parameters[:sample_size]))
|
|
149
|
+
param_hash ^= hash(("original_sample", sample_hash))
|
|
150
|
+
else:
|
|
151
|
+
param_hash ^= hash(("original", repr(original_parameters)))
|
|
152
|
+
|
|
153
|
+
return param_hash
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def _hash_filter_value(value: Any) -> int:
|
|
157
|
+
try:
|
|
158
|
+
return hash(value)
|
|
159
|
+
except TypeError:
|
|
160
|
+
return hash(repr(value))
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def hash_filters(filters: Optional[list["StatementFilter"]] = None) -> int:
|
|
164
|
+
"""Generate hash for statement filters.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
filters: List of statement filters
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
Hash of the filters
|
|
171
|
+
"""
|
|
172
|
+
if not filters:
|
|
173
|
+
return 0
|
|
174
|
+
|
|
175
|
+
# Use class names and any hashable attributes
|
|
176
|
+
filter_components = []
|
|
177
|
+
for f in filters:
|
|
178
|
+
# Use class name as primary identifier
|
|
179
|
+
components: list[Any] = [f.__class__.__name__]
|
|
180
|
+
|
|
181
|
+
# Add any hashable attributes if available
|
|
182
|
+
# Use getattr with default instead of hasattr for mypyc compatibility
|
|
183
|
+
filter_dict = getattr(f, "__dict__", None)
|
|
184
|
+
if filter_dict is not None:
|
|
185
|
+
for key, value in sorted(filter_dict.items()):
|
|
186
|
+
components.append((key, _hash_filter_value(value)))
|
|
187
|
+
|
|
188
|
+
filter_components.append(tuple(components))
|
|
189
|
+
|
|
190
|
+
return hash(tuple(filter_components))
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def hash_sql_statement(statement: "SQL") -> str:
|
|
194
|
+
"""Generate a complete cache key for a SQL statement.
|
|
195
|
+
|
|
196
|
+
This centralizes all the complex hashing logic that was previously
|
|
197
|
+
scattered across different parts of the codebase.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
statement: SQL statement object
|
|
201
|
+
|
|
202
|
+
Returns:
|
|
203
|
+
Cache key string
|
|
204
|
+
"""
|
|
205
|
+
from sqlspec.utils.type_guards import is_expression
|
|
206
|
+
|
|
207
|
+
# Hash the expression or raw SQL
|
|
208
|
+
if is_expression(statement._statement):
|
|
209
|
+
expr_hash = hash_expression(statement._statement)
|
|
210
|
+
else:
|
|
211
|
+
expr_hash = hash(statement._raw_sql)
|
|
212
|
+
|
|
213
|
+
# Hash all parameters
|
|
214
|
+
param_hash = hash_parameters(
|
|
215
|
+
positional_parameters=statement._positional_parameters,
|
|
216
|
+
named_parameters=statement._named_parameters,
|
|
217
|
+
original_parameters=statement._original_parameters,
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
# Hash filters
|
|
221
|
+
filter_hash = hash_filters(statement._filters)
|
|
222
|
+
|
|
223
|
+
# Combine with other state
|
|
224
|
+
state_components = [
|
|
225
|
+
expr_hash,
|
|
226
|
+
param_hash,
|
|
227
|
+
filter_hash,
|
|
228
|
+
hash(statement._dialect),
|
|
229
|
+
hash(statement._is_many),
|
|
230
|
+
hash(statement._is_script),
|
|
231
|
+
]
|
|
232
|
+
|
|
233
|
+
return f"sql:{hash(tuple(state_components))}"
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def hash_expression_node(node: exp.Expression, include_children: bool = True, dialect: Optional[str] = None) -> str:
|
|
237
|
+
"""Generate a cache key for an individual expression node.
|
|
238
|
+
|
|
239
|
+
This is used for sub-expression caching where we want to cache
|
|
240
|
+
frequently used SQL fragments like complex JOIN clauses or WHERE conditions.
|
|
241
|
+
|
|
242
|
+
Args:
|
|
243
|
+
node: The expression node to hash
|
|
244
|
+
include_children: Whether to include child nodes in the hash
|
|
245
|
+
dialect: SQL dialect for context-aware hashing
|
|
246
|
+
|
|
247
|
+
Returns:
|
|
248
|
+
Cache key string for the expression node
|
|
249
|
+
"""
|
|
250
|
+
if include_children:
|
|
251
|
+
# Full structural hash including all children
|
|
252
|
+
node_hash = hash_expression(node)
|
|
253
|
+
else:
|
|
254
|
+
# Shallow hash - just the node type and immediate args
|
|
255
|
+
components: list[Any] = [type(node).__name__]
|
|
256
|
+
for key, value in sorted(node.args.items()):
|
|
257
|
+
if not isinstance(value, (list, exp.Expression)):
|
|
258
|
+
# Only include primitive values, not child expressions
|
|
259
|
+
components.extend((key, hash(value)))
|
|
260
|
+
node_hash = hash(tuple(components))
|
|
261
|
+
|
|
262
|
+
dialect_part = f":{dialect}" if dialect else ""
|
|
263
|
+
return f"expr{dialect_part}:{node_hash}"
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def hash_optimized_expression(
|
|
267
|
+
expr: exp.Expression,
|
|
268
|
+
dialect: str,
|
|
269
|
+
schema: Optional[dict[str, Any]] = None,
|
|
270
|
+
optimizer_settings: Optional[dict[str, Any]] = None,
|
|
271
|
+
) -> str:
|
|
272
|
+
"""Generate a cache key for optimized expressions.
|
|
273
|
+
|
|
274
|
+
This creates a unique key that captures the expression structure,
|
|
275
|
+
dialect, schema context, and optimizer settings to ensure we only
|
|
276
|
+
reuse optimized expressions when all context matches.
|
|
277
|
+
|
|
278
|
+
Args:
|
|
279
|
+
expr: The unoptimized expression
|
|
280
|
+
dialect: Target SQL dialect
|
|
281
|
+
schema: Schema information
|
|
282
|
+
optimizer_settings: Additional optimizer configuration
|
|
283
|
+
|
|
284
|
+
Returns:
|
|
285
|
+
Cache key string for the optimized expression
|
|
286
|
+
"""
|
|
287
|
+
# Base expression hash
|
|
288
|
+
expr_hash = hash_expression(expr)
|
|
289
|
+
|
|
290
|
+
# Schema hash - simplified representation
|
|
291
|
+
schema_hash = 0
|
|
292
|
+
if schema:
|
|
293
|
+
# Hash table names and column counts to avoid deep schema hashing
|
|
294
|
+
schema_items = []
|
|
295
|
+
for table_name, table_schema in sorted(schema.items()):
|
|
296
|
+
if isinstance(table_schema, dict):
|
|
297
|
+
schema_items.append((table_name, len(table_schema)))
|
|
298
|
+
else:
|
|
299
|
+
schema_items.append((table_name, hash("unknown")))
|
|
300
|
+
schema_hash = hash(tuple(schema_items))
|
|
301
|
+
|
|
302
|
+
# Optimizer settings hash
|
|
303
|
+
settings_hash = 0
|
|
304
|
+
if optimizer_settings:
|
|
305
|
+
settings_items = sorted(optimizer_settings.items())
|
|
306
|
+
settings_hash = hash(tuple(settings_items))
|
|
307
|
+
|
|
308
|
+
# Combine all components
|
|
309
|
+
components = (expr_hash, dialect, schema_hash, settings_hash)
|
|
310
|
+
return f"opt:{hash(components)}"
|
|
Binary file
|