sql-dialect-master 1.1.1__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.
- backend/__init__.py +1 -0
- backend/api/__init__.py +1 -0
- backend/api/main.py +732 -0
- backend/api/middleware.py +274 -0
- backend/api/rate_limit_store.py +105 -0
- backend/api/readiness.py +178 -0
- backend/core/__init__.py +57 -0
- backend/core/cache.py +261 -0
- backend/core/column_hint_validation.py +22 -0
- backend/core/config.py +546 -0
- backend/core/constants.py +84 -0
- backend/core/exceptions.py +124 -0
- backend/core/function_call_scanner.py +64 -0
- backend/core/function_semantics.py +148 -0
- backend/core/functions_db.json +601 -0
- backend/core/functions_lookup.py +332 -0
- backend/core/metadata.py +71 -0
- backend/core/nl2sql.py +85 -0
- backend/core/nl2sql_components/__init__.py +72 -0
- backend/core/nl2sql_components/aggregations.py +35 -0
- backend/core/nl2sql_components/boolean_conditions.py +279 -0
- backend/core/nl2sql_components/core_extract.py +106 -0
- backend/core/nl2sql_components/evidence.py +122 -0
- backend/core/nl2sql_components/mappings.py +185 -0
- backend/core/nl2sql_components/relations.py +180 -0
- backend/core/nl2sql_components/templates.py +130 -0
- backend/core/nl2sql_components/tokenizer.py +187 -0
- backend/core/nl2sql_legacy.py +22 -0
- backend/core/nl2sql_pipeline/__init__.py +13 -0
- backend/core/nl2sql_pipeline/aggregations.py +26 -0
- backend/core/nl2sql_pipeline/clause_extract.py +97 -0
- backend/core/nl2sql_pipeline/dialect.py +139 -0
- backend/core/nl2sql_pipeline/intent.py +85 -0
- backend/core/nl2sql_pipeline/ir.py +70 -0
- backend/core/nl2sql_pipeline/models.py +30 -0
- backend/core/nl2sql_pipeline/orchestrator.py +576 -0
- backend/core/nl2sql_pipeline/predicates.py +182 -0
- backend/core/nl2sql_pipeline/renderer.py +248 -0
- backend/core/nl2sql_pipeline/resolution.py +69 -0
- backend/core/nl2sql_pipeline/suggestions.py +30 -0
- backend/core/nl2sql_pipeline/templates.py +371 -0
- backend/core/nl2sql_pipeline/validation.py +28 -0
- backend/core/p1_sql_scanner.py +196 -0
- backend/core/p2_data_validation.py +72 -0
- backend/core/parser.py +280 -0
- backend/core/post_processor.py +129 -0
- backend/core/rules.py +808 -0
- backend/core/semantic_diff.py +385 -0
- backend/core/transpiler.py +791 -0
- backend/core/type_mapping.json +593 -0
- backend/core/type_mapping.py +765 -0
- backend/utils/__init__.py +2 -0
- backend/utils/validators.py +407 -0
- frontend/__init__.py +10 -0
- frontend/app_context_v2.py +201 -0
- frontend/core/__init__.py +33 -0
- frontend/core/design_tokens.py +127 -0
- frontend/core/escaping.py +13 -0
- frontend/core/navigation.py +135 -0
- frontend/core/state.py +612 -0
- frontend/core/styles.py +523 -0
- frontend/core/themes.py +69 -0
- frontend/core/viewmodels.py +499 -0
- frontend/pages/__init__.py +0 -0
- frontend/pages/convert.py +283 -0
- frontend/pages/diff.py +157 -0
- frontend/pages/functions.py +100 -0
- frontend/pages/history.py +144 -0
- frontend/pages/lineage.py +168 -0
- frontend/pages/nl2sql.py +305 -0
- frontend/pages/query_analysis.py +120 -0
- frontend/pages/runtime.py +66 -0
- frontend/pages/settings.py +60 -0
- frontend/pages/templates.py +67 -0
- frontend/pages/types.py +110 -0
- frontend/templates_v2.py +53 -0
- frontend/ui/__init__.py +0 -0
- frontend/ui/command_palette.py +153 -0
- frontend/ui/diff.py +275 -0
- frontend/ui/editor.py +102 -0
- frontend/ui/status.py +255 -0
- sql_dialect_master-1.1.1.dist-info/METADATA +360 -0
- sql_dialect_master-1.1.1.dist-info/RECORD +86 -0
- sql_dialect_master-1.1.1.dist-info/WHEEL +5 -0
- sql_dialect_master-1.1.1.dist-info/licenses/LICENSE +21 -0
- sql_dialect_master-1.1.1.dist-info/top_level.txt +2 -0
backend/core/config.py
ADDED
|
@@ -0,0 +1,546 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Centralized configuration for SQL Dialect Master.
|
|
3
|
+
|
|
4
|
+
All configuration constants and settings are defined here for consistency
|
|
5
|
+
across all modules.
|
|
6
|
+
|
|
7
|
+
Supports configuration via:
|
|
8
|
+
- Environment variables (prefix: SDM_)
|
|
9
|
+
- .env file in project root
|
|
10
|
+
- Default values
|
|
11
|
+
"""
|
|
12
|
+
import logging
|
|
13
|
+
import sys
|
|
14
|
+
from enum import Enum
|
|
15
|
+
from typing import Any, Dict, List, Optional, TypedDict
|
|
16
|
+
|
|
17
|
+
from pydantic import Field
|
|
18
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
19
|
+
|
|
20
|
+
# =============================================================================
|
|
21
|
+
# Logging Configuration
|
|
22
|
+
# =============================================================================
|
|
23
|
+
|
|
24
|
+
def setup_logging(
|
|
25
|
+
level: int = logging.INFO,
|
|
26
|
+
format_string: str = None,
|
|
27
|
+
log_file: str = None
|
|
28
|
+
) -> logging.Logger:
|
|
29
|
+
"""Configure logging for SQL Dialect Master.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
level: Logging level (default: INFO)
|
|
33
|
+
format_string: Custom format string
|
|
34
|
+
log_file: Optional file path for logging
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
Root logger for the package
|
|
38
|
+
"""
|
|
39
|
+
if format_string is None:
|
|
40
|
+
format_string = (
|
|
41
|
+
"%(asctime)s | %(levelname)-8s | %(name)s:%(funcName)s:%(lineno)d | %(message)s"
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
formatter = logging.Formatter(format_string, datefmt="%Y-%m-%d %H:%M:%S")
|
|
45
|
+
root_logger = logging.getLogger("backend")
|
|
46
|
+
root_logger.setLevel(level)
|
|
47
|
+
# Replacing setup_logging() must not silently drop handlers a caller
|
|
48
|
+
# attached to the "backend" logger. Remove only the handler types this
|
|
49
|
+
# function manages — the stdout console handler and any file handler it
|
|
50
|
+
# previously installed — so a second call is idempotent without clearing
|
|
51
|
+
# the caller's own logging config.
|
|
52
|
+
for existing in list(root_logger.handlers):
|
|
53
|
+
if isinstance(existing, logging.StreamHandler) and not isinstance(existing, logging.FileHandler):
|
|
54
|
+
if getattr(existing, "stream", None) in (sys.stdout, sys.stderr, None):
|
|
55
|
+
root_logger.removeHandler(existing)
|
|
56
|
+
elif isinstance(existing, logging.FileHandler):
|
|
57
|
+
root_logger.removeHandler(existing)
|
|
58
|
+
|
|
59
|
+
console_handler = logging.StreamHandler(sys.stdout)
|
|
60
|
+
console_handler.setLevel(level)
|
|
61
|
+
console_handler.setFormatter(formatter)
|
|
62
|
+
root_logger.addHandler(console_handler)
|
|
63
|
+
|
|
64
|
+
if log_file:
|
|
65
|
+
file_handler = logging.FileHandler(log_file, encoding="utf-8")
|
|
66
|
+
file_handler.setLevel(level)
|
|
67
|
+
file_handler.setFormatter(formatter)
|
|
68
|
+
root_logger.addHandler(file_handler)
|
|
69
|
+
|
|
70
|
+
return root_logger
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
logger = logging.getLogger(__name__)
|
|
74
|
+
|
|
75
|
+
# =============================================================================
|
|
76
|
+
# Supported Dialects - Single Source of Truth
|
|
77
|
+
# =============================================================================
|
|
78
|
+
|
|
79
|
+
SUPPORTED_DIALECTS: List[str] = [
|
|
80
|
+
"hive", "mysql", "oracle", "tsql", "postgres", "spark",
|
|
81
|
+
"trino", "snowflake", "redshift", "clickhouse", "duckdb", "databricks"
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
class DialectCategory(Enum):
|
|
85
|
+
"""Database dialect categories."""
|
|
86
|
+
RDBMS = "RDBMS"
|
|
87
|
+
BIG_DATA = "Big Data"
|
|
88
|
+
CLOUD_DW = "Cloud DW"
|
|
89
|
+
OLAP = "OLAP"
|
|
90
|
+
EMBEDDED = "Embedded"
|
|
91
|
+
|
|
92
|
+
from dataclasses import dataclass
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@dataclass
|
|
96
|
+
class DialectInfo:
|
|
97
|
+
"""Information about a SQL dialect."""
|
|
98
|
+
id: str
|
|
99
|
+
name: str
|
|
100
|
+
icon: str
|
|
101
|
+
category: DialectCategory
|
|
102
|
+
color: str
|
|
103
|
+
description: str = ""
|
|
104
|
+
|
|
105
|
+
DIALECT_METADATA: Dict[str, DialectInfo] = {
|
|
106
|
+
"hive": DialectInfo("hive", "Apache Hive", "🐝", DialectCategory.BIG_DATA, "#FDEE21", "Hadoop data warehouse"),
|
|
107
|
+
"mysql": DialectInfo("mysql", "MySQL", "🐬", DialectCategory.RDBMS, "#00758F", "Popular open-source RDBMS"),
|
|
108
|
+
"oracle": DialectInfo("oracle", "Oracle Database", "🔴", DialectCategory.RDBMS, "#F80000", "Enterprise RDBMS"),
|
|
109
|
+
"tsql": DialectInfo("tsql", "SQL Server (T-SQL)", "🟦", DialectCategory.RDBMS, "#CC2927", "Microsoft SQL Server"),
|
|
110
|
+
"postgres": DialectInfo("postgres", "PostgreSQL", "🐘", DialectCategory.RDBMS, "#336791", "Advanced open-source RDBMS"),
|
|
111
|
+
"spark": DialectInfo("spark", "Apache Spark SQL", "⚡", DialectCategory.BIG_DATA, "#E25A1C", "Distributed SQL engine"),
|
|
112
|
+
"trino": DialectInfo("trino", "Trino (Presto)", "🔷", DialectCategory.BIG_DATA, "#DD00A1", "Distributed SQL query engine"),
|
|
113
|
+
"snowflake": DialectInfo("snowflake", "Snowflake", "❄️", DialectCategory.CLOUD_DW, "#29B5E8", "Cloud data platform"),
|
|
114
|
+
"redshift": DialectInfo("redshift", "Amazon Redshift", "🔶", DialectCategory.CLOUD_DW, "#8C4FFF", "AWS data warehouse"),
|
|
115
|
+
"clickhouse": DialectInfo("clickhouse", "ClickHouse", "🏠", DialectCategory.OLAP, "#FFCC00", "Column-oriented OLAP"),
|
|
116
|
+
"duckdb": DialectInfo("duckdb", "DuckDB", "🦆", DialectCategory.EMBEDDED, "#FFF000", "In-process analytical DB"),
|
|
117
|
+
"databricks": DialectInfo("databricks", "Databricks SQL", "🧱", DialectCategory.BIG_DATA, "#FF3621", "Unified analytics platform"),
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def get_dialect_ui_info() -> Dict[str, Dict[str, str]]:
|
|
122
|
+
"""Get dialect info formatted for UI display."""
|
|
123
|
+
return {
|
|
124
|
+
d.id: {"icon": d.icon, "name": d.name, "color": d.color}
|
|
125
|
+
for d in DIALECT_METADATA.values()
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def get_dialect_api_info() -> Dict[str, Dict[str, str]]:
|
|
130
|
+
"""Get dialect info formatted for API responses."""
|
|
131
|
+
return {
|
|
132
|
+
d.id: {"icon": d.icon, "name": d.name, "category": d.category.value}
|
|
133
|
+
for d in DIALECT_METADATA.values()
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def get_dialect_label(dialect: str) -> str:
|
|
138
|
+
"""Get formatted dialect label with icon for display."""
|
|
139
|
+
info = DIALECT_METADATA.get(dialect)
|
|
140
|
+
if info:
|
|
141
|
+
return f"{info.icon} {dialect.upper()}"
|
|
142
|
+
return f"📄 {dialect.upper()}"
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
# =============================================================================
|
|
146
|
+
# Type Definitions for Type Safety
|
|
147
|
+
# =============================================================================
|
|
148
|
+
|
|
149
|
+
class FunctionParameter(TypedDict):
|
|
150
|
+
"""Function parameter definition."""
|
|
151
|
+
name: str
|
|
152
|
+
type: str
|
|
153
|
+
required: bool
|
|
154
|
+
description: str
|
|
155
|
+
|
|
156
|
+
class FunctionInfo(TypedDict, total=False):
|
|
157
|
+
"""SQL function information."""
|
|
158
|
+
name: str
|
|
159
|
+
category: str
|
|
160
|
+
description: str
|
|
161
|
+
parameters: List[FunctionParameter]
|
|
162
|
+
dialects: Dict[str, str]
|
|
163
|
+
examples: Dict[str, str]
|
|
164
|
+
notes: str
|
|
165
|
+
|
|
166
|
+
class TypeMappingInfo(TypedDict, total=False):
|
|
167
|
+
"""Type mapping information."""
|
|
168
|
+
hive: str
|
|
169
|
+
mysql: str
|
|
170
|
+
oracle: str
|
|
171
|
+
tsql: str
|
|
172
|
+
postgres: str
|
|
173
|
+
spark: str
|
|
174
|
+
trino: str
|
|
175
|
+
snowflake: str
|
|
176
|
+
redshift: str
|
|
177
|
+
clickhouse: str
|
|
178
|
+
duckdb: str
|
|
179
|
+
databricks: str
|
|
180
|
+
notes: str
|
|
181
|
+
|
|
182
|
+
class TranspileResultDict(TypedDict, total=False):
|
|
183
|
+
"""Transpile result dictionary."""
|
|
184
|
+
success: bool
|
|
185
|
+
source_sql: str
|
|
186
|
+
target_sql: Optional[str]
|
|
187
|
+
source_dialect: str
|
|
188
|
+
target_dialect: str
|
|
189
|
+
error: Optional[str]
|
|
190
|
+
error_code: Optional[str]
|
|
191
|
+
compatibility_notes: List[str]
|
|
192
|
+
transformations: List[str]
|
|
193
|
+
warnings: List[str]
|
|
194
|
+
target_validation_state: str
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
# =============================================================================
|
|
198
|
+
# Application Settings (Pydantic)
|
|
199
|
+
# =============================================================================
|
|
200
|
+
|
|
201
|
+
from backend.core.metadata import API_VERSION as _METADATA_API_VERSION
|
|
202
|
+
|
|
203
|
+
class AppSettings(BaseSettings):
|
|
204
|
+
"""Application settings using Pydantic.
|
|
205
|
+
|
|
206
|
+
All settings can be overridden via environment variables with SDM_ prefix.
|
|
207
|
+
Example: SDM_CACHE_ENABLED=false
|
|
208
|
+
"""
|
|
209
|
+
model_config = SettingsConfigDict(
|
|
210
|
+
env_prefix="SDM_",
|
|
211
|
+
env_file=".env",
|
|
212
|
+
env_file_encoding="utf-8",
|
|
213
|
+
extra="ignore"
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
# API settings
|
|
217
|
+
api_version: str = _METADATA_API_VERSION
|
|
218
|
+
api_title: str = "SQL Dialect Master API"
|
|
219
|
+
allowed_origins: str = (
|
|
220
|
+
"http://localhost:8501,http://localhost:8000,"
|
|
221
|
+
"http://127.0.0.1:8501,http://127.0.0.1:8000"
|
|
222
|
+
)
|
|
223
|
+
max_batch_size: int = 100
|
|
224
|
+
request_timeout: int = 30
|
|
225
|
+
|
|
226
|
+
# Cache settings
|
|
227
|
+
cache_enabled: bool = True
|
|
228
|
+
cache_ttl: int = 300
|
|
229
|
+
cache_max_size: int = Field(1000, gt=0)
|
|
230
|
+
|
|
231
|
+
# Rate limiting
|
|
232
|
+
rate_limit_enabled: bool = True
|
|
233
|
+
rate_limit_requests: int = 100
|
|
234
|
+
rate_limit_window: int = 60
|
|
235
|
+
|
|
236
|
+
# NL2SQL settings
|
|
237
|
+
nl2sql_confidence_threshold: float = 0.6
|
|
238
|
+
nl2sql_max_suggestions: int = 5
|
|
239
|
+
nl2sql_max_input_length: int = 8192
|
|
240
|
+
|
|
241
|
+
# SQL Transpiler / Parser settings
|
|
242
|
+
#
|
|
243
|
+
# Canonical maximum SQL input length. ``parser_max_sql_length`` is a
|
|
244
|
+
# compatibility alias (the .env example ships both names) and falls back
|
|
245
|
+
# to ``transpiler_max_sql_length``. Business code must read the
|
|
246
|
+
# settings object — never ``os.getenv`` directly.
|
|
247
|
+
transpiler_pretty_default: bool = True
|
|
248
|
+
transpiler_max_sql_length: int = 100000
|
|
249
|
+
parser_max_sql_length: int = 100000
|
|
250
|
+
|
|
251
|
+
# Function encyclopedia
|
|
252
|
+
function_search_limit: int = 50
|
|
253
|
+
function_fuzzy_threshold: float = 0.4
|
|
254
|
+
|
|
255
|
+
# Security settings
|
|
256
|
+
security_check_enabled: bool = True
|
|
257
|
+
security_block_dangerous: bool = True
|
|
258
|
+
|
|
259
|
+
# Logging settings
|
|
260
|
+
log_level: str = "INFO"
|
|
261
|
+
log_file: str = ""
|
|
262
|
+
|
|
263
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
264
|
+
"""Convert settings to dictionary."""
|
|
265
|
+
return self.model_dump()
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
settings = AppSettings()
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
# =============================================================================
|
|
272
|
+
# Security Patterns for SQL Validation
|
|
273
|
+
# =============================================================================
|
|
274
|
+
|
|
275
|
+
import re
|
|
276
|
+
|
|
277
|
+
_DANGEROUS_SQL_PATTERNS_RAW: List[tuple] = [
|
|
278
|
+
(r";\s*(DROP|DELETE|TRUNCATE|ALTER|CREATE|INSERT|UPDATE)\s+",
|
|
279
|
+
"Multiple statements with dangerous operations detected"),
|
|
280
|
+
(r"--\s*.*\s*(DROP|DELETE|TRUNCATE)",
|
|
281
|
+
"SQL comment may hide dangerous operation"),
|
|
282
|
+
(r"UNION\s+(ALL\s+)?SELECT\s+.*(FROM\s+information_schema|FROM\s+sys\.|@@version|user\(\))",
|
|
283
|
+
"Potential SQL injection pattern detected"),
|
|
284
|
+
(r"(information_schema|sys\.tables|sysobjects|pg_catalog|all_tables)",
|
|
285
|
+
"System table access detected"),
|
|
286
|
+
(r"(xp_cmdshell|sp_executesql|EXEC\s*\(|EXECUTE\s+IMMEDIATE)",
|
|
287
|
+
"Command execution attempt detected"),
|
|
288
|
+
(r"(INTO\s+OUTFILE|INTO\s+DUMPFILE|LOAD_FILE|UTL_FILE)",
|
|
289
|
+
"File operation detected"),
|
|
290
|
+
(r"\bOR\s+['\"]?1['\"]?\s*=\s*['\"]?1['\"]?",
|
|
291
|
+
"Classic OR 1=1 injection pattern detected"),
|
|
292
|
+
(r"\bOR\s+['\"][\w]+['\"]\s*=\s*['\"][\w]+['\"]",
|
|
293
|
+
"OR string comparison injection pattern detected"),
|
|
294
|
+
(r"\b(AND|OR)\s+\d+\s*=\s*\d+",
|
|
295
|
+
"Tautology attack pattern detected"),
|
|
296
|
+
(r"0x[0-9a-fA-F]{8,}",
|
|
297
|
+
"Suspicious hex-encoded value detected"),
|
|
298
|
+
(r";\s*SELECT\s+",
|
|
299
|
+
"Stacked query injection pattern detected"),
|
|
300
|
+
(r"(SLEEP\s*\(\s*\d+\s*\)|BENCHMARK\s*\(|WAITFOR\s+DELAY|PG_SLEEP)",
|
|
301
|
+
"Timing-based attack pattern detected"),
|
|
302
|
+
(r"(SHOW\s+DATABASES|SHOW\s+TABLES|DESCRIBE\s+|SP_COLUMNS)",
|
|
303
|
+
"Database enumeration attempt detected"),
|
|
304
|
+
]
|
|
305
|
+
|
|
306
|
+
_WARNING_SQL_PATTERNS_RAW: List[tuple] = [
|
|
307
|
+
(r"DELETE\s+FROM\s+\w+\s*(?!WHERE)",
|
|
308
|
+
"DELETE without WHERE clause - will affect all rows"),
|
|
309
|
+
(r"UPDATE\s+\w+\s+SET\s+.*(?!WHERE)",
|
|
310
|
+
"UPDATE without WHERE clause - will affect all rows"),
|
|
311
|
+
(r"DROP\s+(TABLE|DATABASE|SCHEMA|INDEX|VIEW)",
|
|
312
|
+
"DROP operation detected - data loss risk"),
|
|
313
|
+
(r"TRUNCATE\s+TABLE",
|
|
314
|
+
"TRUNCATE operation detected - data loss risk"),
|
|
315
|
+
(r"(GRANT|REVOKE)\s+",
|
|
316
|
+
"Permission modification detected"),
|
|
317
|
+
(r"LIMIT\s+\d{6,}",
|
|
318
|
+
"Very large LIMIT value may impact performance"),
|
|
319
|
+
(r"SELECT\s+\*\s+FROM",
|
|
320
|
+
"SELECT * detected - consider specifying columns explicitly"),
|
|
321
|
+
]
|
|
322
|
+
|
|
323
|
+
DANGEROUS_SQL_PATTERNS: List[tuple] = [
|
|
324
|
+
(re.compile(pattern, re.IGNORECASE | re.MULTILINE), message)
|
|
325
|
+
for pattern, message in _DANGEROUS_SQL_PATTERNS_RAW
|
|
326
|
+
]
|
|
327
|
+
|
|
328
|
+
WARNING_SQL_PATTERNS: List[tuple] = [
|
|
329
|
+
(re.compile(pattern, re.IGNORECASE | re.MULTILINE), message)
|
|
330
|
+
for pattern, message in _WARNING_SQL_PATTERNS_RAW
|
|
331
|
+
]
|
|
332
|
+
|
|
333
|
+
# =============================================================================
|
|
334
|
+
# Function Categories
|
|
335
|
+
# =============================================================================
|
|
336
|
+
|
|
337
|
+
FUNCTION_CATEGORIES: List[str] = [
|
|
338
|
+
"string", "date", "math", "aggregate", "window",
|
|
339
|
+
"conditional", "conversion", "json", "array", "system", "geo"
|
|
340
|
+
]
|
|
341
|
+
|
|
342
|
+
CATEGORY_DESCRIPTIONS: Dict[str, str] = {
|
|
343
|
+
"string": "String manipulation functions (CONCAT, SUBSTRING, TRIM, etc.)",
|
|
344
|
+
"date": "Date and time functions (DATE_ADD, DATEDIFF, NOW, etc.)",
|
|
345
|
+
"math": "Mathematical functions (ABS, ROUND, FLOOR, etc.)",
|
|
346
|
+
"aggregate": "Aggregation functions (SUM, COUNT, AVG, etc.)",
|
|
347
|
+
"window": "Window functions (ROW_NUMBER, RANK, LAG, etc.)",
|
|
348
|
+
"conditional": "Conditional functions (CASE, IF, COALESCE, etc.)",
|
|
349
|
+
"conversion": "Type conversion functions (CAST, CONVERT, etc.)",
|
|
350
|
+
"json": "JSON manipulation functions (JSON_EXTRACT, etc.)",
|
|
351
|
+
"array": "Array functions (EXPLODE, COLLECT_LIST, etc.)",
|
|
352
|
+
"system": "System functions (VERSION, DATABASE, etc.)",
|
|
353
|
+
"geo": "Geospatial functions (ST_DISTANCE, ST_CONTAINS, etc.)"
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
# =============================================================================
|
|
357
|
+
# Type Categories
|
|
358
|
+
# =============================================================================
|
|
359
|
+
|
|
360
|
+
TYPE_CATEGORIES: Dict[str, List[str]] = {
|
|
361
|
+
"String Types": ["STRING", "VARCHAR", "CHAR", "TEXT", "MEDIUMTEXT", "LONGTEXT"],
|
|
362
|
+
"Numeric Types": ["BIGINT", "INT", "SMALLINT", "TINYINT", "DOUBLE", "FLOAT", "DECIMAL", "MONEY", "SERIAL"],
|
|
363
|
+
"Boolean & Bit": ["BOOLEAN", "BIT"],
|
|
364
|
+
"Date/Time Types": ["DATE", "TIME", "TIMESTAMP", "TIMESTAMP_TZ", "INTERVAL", "YEAR"],
|
|
365
|
+
"Complex Types": ["ARRAY", "MAP", "STRUCT", "JSON", "JSONB", "XML"],
|
|
366
|
+
"Binary Types": ["BINARY"],
|
|
367
|
+
"Special Types": ["UUID", "INET", "GEOMETRY", "GEOGRAPHY", "ENUM", "SET"]
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
# =============================================================================
|
|
371
|
+
# Compatibility Notes Database
|
|
372
|
+
# =============================================================================
|
|
373
|
+
|
|
374
|
+
COMPATIBILITY_NOTES: Dict[tuple, List[str]] = {
|
|
375
|
+
("hive", "mysql"): [
|
|
376
|
+
"Hive ARRAY/MAP types converted to JSON",
|
|
377
|
+
"LATERAL VIEW EXPLODE may need manual adjustment",
|
|
378
|
+
"Hive STRING maps to VARCHAR(65535) or TEXT"
|
|
379
|
+
],
|
|
380
|
+
("hive", "oracle"): [
|
|
381
|
+
"Hive ARRAY/MAP types converted to JSON/VARRAY",
|
|
382
|
+
"LATERAL VIEW EXPLODE → JSON_TABLE transformation",
|
|
383
|
+
"Hive STRING maps to CLOB or VARCHAR2(4000)"
|
|
384
|
+
],
|
|
385
|
+
("hive", "postgres"): [
|
|
386
|
+
"LATERAL VIEW EXPLODE → UNNEST transformation",
|
|
387
|
+
"Hive MAP → JSONB recommended",
|
|
388
|
+
"COLLECT_LIST → ARRAY_AGG"
|
|
389
|
+
],
|
|
390
|
+
("hive", "tsql"): [
|
|
391
|
+
"Hive ARRAY → JSON or table-valued parameter",
|
|
392
|
+
"LIMIT → TOP or OFFSET FETCH",
|
|
393
|
+
"Hive STRING → NVARCHAR(MAX)"
|
|
394
|
+
],
|
|
395
|
+
("hive", "snowflake"): [
|
|
396
|
+
"LATERAL VIEW EXPLODE → LATERAL FLATTEN",
|
|
397
|
+
"Hive STRUCT → OBJECT type",
|
|
398
|
+
"DATE_ADD syntax differs"
|
|
399
|
+
],
|
|
400
|
+
("hive", "spark"): [
|
|
401
|
+
"Most syntax compatible",
|
|
402
|
+
"Check UDF compatibility",
|
|
403
|
+
"Spark may have additional optimizations"
|
|
404
|
+
],
|
|
405
|
+
("oracle", "hive"): [
|
|
406
|
+
"LISTAGG → ARRAY_JOIN(COLLECT_LIST()) transformation",
|
|
407
|
+
"CONNECT BY → WITH RECURSIVE transformation",
|
|
408
|
+
"Oracle NUMBER → Hive DECIMAL with precision check"
|
|
409
|
+
],
|
|
410
|
+
("oracle", "mysql"): [
|
|
411
|
+
"NVL → IFNULL or COALESCE",
|
|
412
|
+
"DECODE → CASE WHEN",
|
|
413
|
+
"ROWNUM → LIMIT"
|
|
414
|
+
],
|
|
415
|
+
("oracle", "postgres"): [
|
|
416
|
+
"NVL → COALESCE",
|
|
417
|
+
"SYSDATE → CURRENT_TIMESTAMP",
|
|
418
|
+
"DECODE → CASE WHEN"
|
|
419
|
+
],
|
|
420
|
+
("mysql", "postgres"): [
|
|
421
|
+
"GROUP_CONCAT → STRING_AGG transformation",
|
|
422
|
+
"IFNULL → COALESCE transformation",
|
|
423
|
+
"AUTO_INCREMENT → SERIAL/IDENTITY"
|
|
424
|
+
],
|
|
425
|
+
("mysql", "oracle"): [
|
|
426
|
+
"LIMIT → FETCH FIRST or ROWNUM",
|
|
427
|
+
"NOW() → SYSDATE",
|
|
428
|
+
"IFNULL → NVL"
|
|
429
|
+
],
|
|
430
|
+
("mysql", "hive"): [
|
|
431
|
+
"AUTO_INCREMENT not supported in Hive",
|
|
432
|
+
"JSON functions syntax differs",
|
|
433
|
+
"DATE_FORMAT patterns differ"
|
|
434
|
+
],
|
|
435
|
+
("tsql", "mysql"): [
|
|
436
|
+
"STRING_AGG → GROUP_CONCAT transformation",
|
|
437
|
+
"TOP → LIMIT transformation",
|
|
438
|
+
"GETDATE() → NOW() transformation"
|
|
439
|
+
],
|
|
440
|
+
("tsql", "postgres"): [
|
|
441
|
+
"TOP → LIMIT",
|
|
442
|
+
"GETDATE() → CURRENT_TIMESTAMP",
|
|
443
|
+
"ISNULL → COALESCE"
|
|
444
|
+
],
|
|
445
|
+
("tsql", "hive"): [
|
|
446
|
+
"TOP → LIMIT",
|
|
447
|
+
"CROSS/OUTER APPLY → LATERAL VIEW",
|
|
448
|
+
"STRING_AGG → CONCAT_WS(COLLECT_LIST())"
|
|
449
|
+
],
|
|
450
|
+
("postgres", "mysql"): [
|
|
451
|
+
"STRING_AGG → GROUP_CONCAT transformation",
|
|
452
|
+
"ARRAY types → JSON transformation",
|
|
453
|
+
"SERIAL → AUTO_INCREMENT",
|
|
454
|
+
"CONCAT NULL semantics differ: PostgreSQL ignores NULL args (returns non-NULL), MySQL propagates NULL (returns NULL if any arg is NULL)"
|
|
455
|
+
],
|
|
456
|
+
("postgres", "oracle"): [
|
|
457
|
+
"ARRAY_AGG → LISTAGG",
|
|
458
|
+
"CURRENT_TIMESTAMP → SYSDATE",
|
|
459
|
+
"LIMIT → FETCH FIRST"
|
|
460
|
+
],
|
|
461
|
+
("postgres", "hive"): [
|
|
462
|
+
"ARRAY_AGG → COLLECT_LIST",
|
|
463
|
+
"UNNEST → LATERAL VIEW EXPLODE",
|
|
464
|
+
"STRING_AGG → CONCAT_WS(COLLECT_LIST())"
|
|
465
|
+
],
|
|
466
|
+
("spark", "hive"): [
|
|
467
|
+
"Most syntax compatible",
|
|
468
|
+
"Check Spark-specific functions",
|
|
469
|
+
"DataFrame operations need conversion"
|
|
470
|
+
],
|
|
471
|
+
("spark", "snowflake"): [
|
|
472
|
+
"EXPLODE → LATERAL FLATTEN",
|
|
473
|
+
"COLLECT_LIST → ARRAY_AGG",
|
|
474
|
+
"Spark UDFs not supported"
|
|
475
|
+
],
|
|
476
|
+
("spark", "trino"): [
|
|
477
|
+
"Most syntax compatible",
|
|
478
|
+
"COLLECT_LIST → ARRAY_AGG",
|
|
479
|
+
"Check function availability"
|
|
480
|
+
],
|
|
481
|
+
("snowflake", "postgres"): [
|
|
482
|
+
"FLATTEN → UNNEST",
|
|
483
|
+
"VARIANT → JSONB",
|
|
484
|
+
"PARSE_JSON → ::JSONB cast"
|
|
485
|
+
],
|
|
486
|
+
("snowflake", "hive"): [
|
|
487
|
+
"FLATTEN → LATERAL VIEW EXPLODE",
|
|
488
|
+
"VARIANT → STRING (JSON)",
|
|
489
|
+
"OBJECT → STRUCT"
|
|
490
|
+
],
|
|
491
|
+
("trino", "postgres"): [
|
|
492
|
+
"ROW → composite type",
|
|
493
|
+
"ARRAY syntax compatible",
|
|
494
|
+
"Check function names"
|
|
495
|
+
],
|
|
496
|
+
("trino", "hive"): [
|
|
497
|
+
"ROW → STRUCT",
|
|
498
|
+
"Most syntax compatible",
|
|
499
|
+
"Check UDF availability"
|
|
500
|
+
],
|
|
501
|
+
("clickhouse", "postgres"): [
|
|
502
|
+
"Array JOIN → UNNEST",
|
|
503
|
+
"groupArray → ARRAY_AGG",
|
|
504
|
+
"ClickHouse-specific functions need alternatives"
|
|
505
|
+
],
|
|
506
|
+
("clickhouse", "mysql"): [
|
|
507
|
+
"Array JOIN → JSON_TABLE",
|
|
508
|
+
"groupArray → JSON_ARRAYAGG",
|
|
509
|
+
"DateTime64 → DATETIME(6)"
|
|
510
|
+
],
|
|
511
|
+
("redshift", "postgres"): [
|
|
512
|
+
"SUPER → JSONB",
|
|
513
|
+
"GETDATE → CURRENT_TIMESTAMP",
|
|
514
|
+
"Most syntax compatible"
|
|
515
|
+
],
|
|
516
|
+
("redshift", "snowflake"): [
|
|
517
|
+
"SUPER → VARIANT",
|
|
518
|
+
"Similar cloud DW syntax",
|
|
519
|
+
"Check function availability"
|
|
520
|
+
],
|
|
521
|
+
("duckdb", "postgres"): [
|
|
522
|
+
"LIST → ARRAY",
|
|
523
|
+
"Most syntax compatible",
|
|
524
|
+
"Check extension functions"
|
|
525
|
+
],
|
|
526
|
+
("duckdb", "hive"): [
|
|
527
|
+
"LIST → ARRAY",
|
|
528
|
+
"STRUCT syntax similar",
|
|
529
|
+
"Check function availability"
|
|
530
|
+
],
|
|
531
|
+
("databricks", "spark"): [
|
|
532
|
+
"Fully compatible",
|
|
533
|
+
"Databricks-specific features may not transfer",
|
|
534
|
+
"Unity Catalog references need adjustment"
|
|
535
|
+
],
|
|
536
|
+
("databricks", "hive"): [
|
|
537
|
+
"Most syntax compatible",
|
|
538
|
+
"Delta Lake features not supported",
|
|
539
|
+
"Check function availability"
|
|
540
|
+
],
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
|
|
544
|
+
def get_compatibility_notes(source: str, target: str) -> List[str]:
|
|
545
|
+
"""Get compatibility notes for a dialect pair."""
|
|
546
|
+
return COMPATIBILITY_NOTES.get((source.lower(), target.lower()), [])
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Application constants for SQL Dialect Master.
|
|
3
|
+
|
|
4
|
+
Centralizes all magic numbers and hardcoded values for better maintainability.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
# =============================================================================
|
|
8
|
+
# UI Constants
|
|
9
|
+
# =============================================================================
|
|
10
|
+
|
|
11
|
+
# SQL Editor
|
|
12
|
+
SQL_INPUT_HEIGHT = 220
|
|
13
|
+
SQL_BATCH_INPUT_HEIGHT = 120
|
|
14
|
+
SQL_LINEAGE_INPUT_HEIGHT = 180
|
|
15
|
+
SQL_EXPLAIN_INPUT_HEIGHT = 120
|
|
16
|
+
|
|
17
|
+
# Preview lengths (for truncating display)
|
|
18
|
+
SQL_PREVIEW_LENGTH = 200
|
|
19
|
+
HISTORY_PREVIEW_LENGTH = 40
|
|
20
|
+
FAVORITE_LABEL_LENGTH = 25
|
|
21
|
+
|
|
22
|
+
# Limits
|
|
23
|
+
MAX_HISTORY_DISPLAY = 5
|
|
24
|
+
MAX_FAVORITES_DISPLAY = 5
|
|
25
|
+
MAX_FUNCTION_SEARCH_RESULTS = 30
|
|
26
|
+
MAX_OUTPUT_COLUMNS_LINEAGE = 6
|
|
27
|
+
|
|
28
|
+
# =============================================================================
|
|
29
|
+
# API Constants
|
|
30
|
+
# =============================================================================
|
|
31
|
+
|
|
32
|
+
MAX_SQL_LENGTH = 100000 # Maximum SQL input length
|
|
33
|
+
MAX_BATCH_SIZE = 100 # Maximum statements in batch conversion
|
|
34
|
+
DEFAULT_SEARCH_LIMIT = 20
|
|
35
|
+
|
|
36
|
+
# =============================================================================
|
|
37
|
+
# Cache Constants
|
|
38
|
+
# =============================================================================
|
|
39
|
+
|
|
40
|
+
TRANSPILE_CACHE_MAX_SIZE = 1000
|
|
41
|
+
TRANSPILE_CACHE_TTL = 300 # 5 minutes
|
|
42
|
+
|
|
43
|
+
FUNCTION_CACHE_MAX_SIZE = 500
|
|
44
|
+
FUNCTION_CACHE_TTL = 600 # 10 minutes
|
|
45
|
+
|
|
46
|
+
TYPE_CACHE_MAX_SIZE = 200
|
|
47
|
+
TYPE_CACHE_TTL = 600 # 10 minutes
|
|
48
|
+
|
|
49
|
+
# =============================================================================
|
|
50
|
+
# NL2SQL Constants
|
|
51
|
+
# =============================================================================
|
|
52
|
+
|
|
53
|
+
NL2SQL_HIGH_CONFIDENCE_THRESHOLD = 0.7
|
|
54
|
+
NL2SQL_MEDIUM_CONFIDENCE_THRESHOLD = 0.5
|
|
55
|
+
|
|
56
|
+
# =============================================================================
|
|
57
|
+
# Security Constants
|
|
58
|
+
# =============================================================================
|
|
59
|
+
|
|
60
|
+
# Patterns that indicate potentially dangerous SQL
|
|
61
|
+
DANGEROUS_PATTERNS = [
|
|
62
|
+
r'\bDROP\s+DATABASE\b',
|
|
63
|
+
r'\bDROP\s+TABLE\b',
|
|
64
|
+
r'\bTRUNCATE\b',
|
|
65
|
+
r'\bDELETE\s+FROM\s+\w+\s*;?\s*$', # DELETE without WHERE
|
|
66
|
+
r'\bUPDATE\s+\w+\s+SET\s+.*(?!WHERE)', # UPDATE without WHERE
|
|
67
|
+
r';\s*--', # SQL injection pattern
|
|
68
|
+
r'\bEXEC\s*\(',
|
|
69
|
+
r'\bxp_cmdshell\b',
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
# =============================================================================
|
|
73
|
+
# Version Info
|
|
74
|
+
# =============================================================================
|
|
75
|
+
#
|
|
76
|
+
# Canonical product version lives in backend.core.metadata. This module
|
|
77
|
+
# re-exports it for backward compatibility — it must NOT carry its own
|
|
78
|
+
# hardcoded number (an earlier drift bug pinned this file to 1.0.0 while
|
|
79
|
+
# the release was 1.1.0).
|
|
80
|
+
from backend.core.metadata import PROJECT_VERSION as _CANONICAL_VERSION
|
|
81
|
+
|
|
82
|
+
VERSION = _CANONICAL_VERSION
|
|
83
|
+
APP_NAME = "SQL Dialect Master"
|
|
84
|
+
APP_DESCRIPTION = "Enterprise-grade multi-database SQL conversion platform"
|