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.
Files changed (86) hide show
  1. backend/__init__.py +1 -0
  2. backend/api/__init__.py +1 -0
  3. backend/api/main.py +732 -0
  4. backend/api/middleware.py +274 -0
  5. backend/api/rate_limit_store.py +105 -0
  6. backend/api/readiness.py +178 -0
  7. backend/core/__init__.py +57 -0
  8. backend/core/cache.py +261 -0
  9. backend/core/column_hint_validation.py +22 -0
  10. backend/core/config.py +546 -0
  11. backend/core/constants.py +84 -0
  12. backend/core/exceptions.py +124 -0
  13. backend/core/function_call_scanner.py +64 -0
  14. backend/core/function_semantics.py +148 -0
  15. backend/core/functions_db.json +601 -0
  16. backend/core/functions_lookup.py +332 -0
  17. backend/core/metadata.py +71 -0
  18. backend/core/nl2sql.py +85 -0
  19. backend/core/nl2sql_components/__init__.py +72 -0
  20. backend/core/nl2sql_components/aggregations.py +35 -0
  21. backend/core/nl2sql_components/boolean_conditions.py +279 -0
  22. backend/core/nl2sql_components/core_extract.py +106 -0
  23. backend/core/nl2sql_components/evidence.py +122 -0
  24. backend/core/nl2sql_components/mappings.py +185 -0
  25. backend/core/nl2sql_components/relations.py +180 -0
  26. backend/core/nl2sql_components/templates.py +130 -0
  27. backend/core/nl2sql_components/tokenizer.py +187 -0
  28. backend/core/nl2sql_legacy.py +22 -0
  29. backend/core/nl2sql_pipeline/__init__.py +13 -0
  30. backend/core/nl2sql_pipeline/aggregations.py +26 -0
  31. backend/core/nl2sql_pipeline/clause_extract.py +97 -0
  32. backend/core/nl2sql_pipeline/dialect.py +139 -0
  33. backend/core/nl2sql_pipeline/intent.py +85 -0
  34. backend/core/nl2sql_pipeline/ir.py +70 -0
  35. backend/core/nl2sql_pipeline/models.py +30 -0
  36. backend/core/nl2sql_pipeline/orchestrator.py +576 -0
  37. backend/core/nl2sql_pipeline/predicates.py +182 -0
  38. backend/core/nl2sql_pipeline/renderer.py +248 -0
  39. backend/core/nl2sql_pipeline/resolution.py +69 -0
  40. backend/core/nl2sql_pipeline/suggestions.py +30 -0
  41. backend/core/nl2sql_pipeline/templates.py +371 -0
  42. backend/core/nl2sql_pipeline/validation.py +28 -0
  43. backend/core/p1_sql_scanner.py +196 -0
  44. backend/core/p2_data_validation.py +72 -0
  45. backend/core/parser.py +280 -0
  46. backend/core/post_processor.py +129 -0
  47. backend/core/rules.py +808 -0
  48. backend/core/semantic_diff.py +385 -0
  49. backend/core/transpiler.py +791 -0
  50. backend/core/type_mapping.json +593 -0
  51. backend/core/type_mapping.py +765 -0
  52. backend/utils/__init__.py +2 -0
  53. backend/utils/validators.py +407 -0
  54. frontend/__init__.py +10 -0
  55. frontend/app_context_v2.py +201 -0
  56. frontend/core/__init__.py +33 -0
  57. frontend/core/design_tokens.py +127 -0
  58. frontend/core/escaping.py +13 -0
  59. frontend/core/navigation.py +135 -0
  60. frontend/core/state.py +612 -0
  61. frontend/core/styles.py +523 -0
  62. frontend/core/themes.py +69 -0
  63. frontend/core/viewmodels.py +499 -0
  64. frontend/pages/__init__.py +0 -0
  65. frontend/pages/convert.py +283 -0
  66. frontend/pages/diff.py +157 -0
  67. frontend/pages/functions.py +100 -0
  68. frontend/pages/history.py +144 -0
  69. frontend/pages/lineage.py +168 -0
  70. frontend/pages/nl2sql.py +305 -0
  71. frontend/pages/query_analysis.py +120 -0
  72. frontend/pages/runtime.py +66 -0
  73. frontend/pages/settings.py +60 -0
  74. frontend/pages/templates.py +67 -0
  75. frontend/pages/types.py +110 -0
  76. frontend/templates_v2.py +53 -0
  77. frontend/ui/__init__.py +0 -0
  78. frontend/ui/command_palette.py +153 -0
  79. frontend/ui/diff.py +275 -0
  80. frontend/ui/editor.py +102 -0
  81. frontend/ui/status.py +255 -0
  82. sql_dialect_master-1.1.1.dist-info/METADATA +360 -0
  83. sql_dialect_master-1.1.1.dist-info/RECORD +86 -0
  84. sql_dialect_master-1.1.1.dist-info/WHEEL +5 -0
  85. sql_dialect_master-1.1.1.dist-info/licenses/LICENSE +21 -0
  86. 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"