mirror of
https://github.com/chartdb/chartdb.git
synced 2025-10-23 07:11:56 +00:00
Compare commits
1 Commits
619cdc564c
...
jf/fix_err
Author | SHA1 | Date | |
---|---|---|---|
|
c7d1c2ffa7 |
@@ -57,11 +57,36 @@ export const SQLValidationStatus: React.FC<SQLValidationStatusProps> = ({
|
||||
|
||||
// If we have parser errors (errorMessage) after validation
|
||||
if (errorMessage && !hasErrors) {
|
||||
// Check if the error is related to parsing issues
|
||||
const isParsingError =
|
||||
errorMessage.toLowerCase().includes('error parsing') ||
|
||||
errorMessage.toLowerCase().includes('unexpected');
|
||||
|
||||
return (
|
||||
<>
|
||||
<Separator className="mb-1 mt-2" />
|
||||
<div className="mb-1 flex shrink-0 items-center gap-2">
|
||||
<p className="text-xs text-red-700">{errorMessage}</p>
|
||||
<div className="rounded-md border border-red-200 bg-red-50 dark:border-red-800 dark:bg-red-950">
|
||||
<div className="space-y-3 p-3 pt-2 text-red-700 dark:text-red-300">
|
||||
<div className="flex items-start gap-2">
|
||||
<MessageCircleWarning className="mt-0.5 size-4 shrink-0 text-red-700 dark:text-red-300" />
|
||||
<div className="flex-1 text-sm text-red-700 dark:text-red-300">
|
||||
<div className="font-medium">
|
||||
{isParsingError
|
||||
? 'SQL Parsing Failed'
|
||||
: 'SQL Import Error'}
|
||||
</div>
|
||||
<div className="mt-1 text-xs">
|
||||
{errorMessage}
|
||||
</div>
|
||||
{isParsingError && (
|
||||
<div className="mt-2 text-xs opacity-90">
|
||||
This may indicate incompatible SQL
|
||||
syntax for the selected database type.
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
105
src/lib/data/sql-import/validators/dialect-detection.ts
Normal file
105
src/lib/data/sql-import/validators/dialect-detection.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* Shared utilities for detecting SQL dialect-specific syntax
|
||||
* Used across all validators to identify incompatible SQL dialects
|
||||
*/
|
||||
|
||||
import type { ValidationError } from './postgresql-validator';
|
||||
|
||||
interface DialectDetectionResult {
|
||||
detected: boolean;
|
||||
dialect: string;
|
||||
lines: number[];
|
||||
features: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect Oracle-specific SQL syntax in the given SQL content
|
||||
*/
|
||||
export function detectOracleSQL(lines: string[]): DialectDetectionResult {
|
||||
const oracleTypeLines: number[] = [];
|
||||
const detectedFeatures = new Set<string>();
|
||||
|
||||
lines.forEach((line, index) => {
|
||||
const upperLine = line.trim().toUpperCase();
|
||||
|
||||
// Check for Oracle-specific data types
|
||||
if (upperLine.includes('VARCHAR2')) {
|
||||
detectedFeatures.add('VARCHAR2');
|
||||
oracleTypeLines.push(index + 1);
|
||||
}
|
||||
|
||||
if (
|
||||
upperLine.match(/\bNUMBER\s*\(/i) ||
|
||||
upperLine.match(/\bNUMBER\b(?!\s*\()/i)
|
||||
) {
|
||||
detectedFeatures.add('NUMBER');
|
||||
oracleTypeLines.push(index + 1);
|
||||
}
|
||||
|
||||
// Could add more Oracle-specific features in the future:
|
||||
// - CLOB, BLOB data types
|
||||
// - ROWNUM pseudo-column
|
||||
// - CONNECT BY for hierarchical queries
|
||||
// - MINUS set operator (vs EXCEPT in other DBs)
|
||||
});
|
||||
|
||||
return {
|
||||
detected: oracleTypeLines.length > 0,
|
||||
dialect: 'Oracle',
|
||||
lines: oracleTypeLines,
|
||||
features: Array.from(detectedFeatures),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an Oracle SQL error for the target database type
|
||||
*/
|
||||
export function createOracleError(
|
||||
detection: DialectDetectionResult,
|
||||
targetDatabase: 'MySQL' | 'PostgreSQL' | 'SQL Server' | 'SQLite'
|
||||
): ValidationError {
|
||||
const lineList = detection.lines.slice(0, 5).join(', ');
|
||||
const moreLines =
|
||||
detection.lines.length > 5
|
||||
? ` and ${detection.lines.length - 5} more locations`
|
||||
: '';
|
||||
|
||||
const featuresText = detection.features.join(', ');
|
||||
|
||||
// Database-specific conversion suggestions
|
||||
const conversionMap = {
|
||||
MySQL: 'VARCHAR2 → VARCHAR, NUMBER → INT/DECIMAL/NUMERIC',
|
||||
PostgreSQL: 'VARCHAR2 → VARCHAR, NUMBER → NUMERIC/INTEGER',
|
||||
'SQL Server': 'VARCHAR2 → VARCHAR, NUMBER → INT/DECIMAL/NUMERIC',
|
||||
SQLite: 'VARCHAR2 → TEXT, NUMBER → INTEGER/REAL',
|
||||
};
|
||||
|
||||
return {
|
||||
line: detection.lines[0],
|
||||
message: `Oracle SQL syntax detected (${featuresText} types found on lines: ${lineList}${moreLines})`,
|
||||
type: 'syntax',
|
||||
suggestion: `This appears to be Oracle SQL. Please convert to ${targetDatabase} syntax: ${conversionMap[targetDatabase]}`,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect any foreign SQL dialect in the given content
|
||||
* Returns null if no foreign dialect is detected
|
||||
*/
|
||||
export function detectForeignDialect(
|
||||
lines: string[],
|
||||
targetDatabase: 'MySQL' | 'PostgreSQL' | 'SQL Server' | 'SQLite'
|
||||
): ValidationError | null {
|
||||
// Check for Oracle SQL
|
||||
const oracleDetection = detectOracleSQL(lines);
|
||||
if (oracleDetection.detected) {
|
||||
return createOracleError(oracleDetection, targetDatabase);
|
||||
}
|
||||
|
||||
// Future: Could add detection for other dialects
|
||||
// - DB2 specific syntax
|
||||
// - Teradata specific syntax
|
||||
// - etc.
|
||||
|
||||
return null;
|
||||
}
|
@@ -8,6 +8,7 @@ import type {
|
||||
ValidationError,
|
||||
ValidationWarning,
|
||||
} from './postgresql-validator';
|
||||
import { detectForeignDialect } from './dialect-detection';
|
||||
|
||||
/**
|
||||
* Validates MySQL SQL syntax
|
||||
@@ -34,13 +35,16 @@ export function validateMySQLDialect(sql: string): ValidationResult {
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: Implement MySQL-specific validation
|
||||
// For now, just do basic checks
|
||||
|
||||
// Check for common MySQL syntax patterns
|
||||
const lines = sql.split('\n');
|
||||
let tableCount = 0;
|
||||
|
||||
// Check for foreign SQL dialects
|
||||
const foreignDialectError = detectForeignDialect(lines, 'MySQL');
|
||||
if (foreignDialectError) {
|
||||
errors.push(foreignDialectError);
|
||||
}
|
||||
|
||||
lines.forEach((line, index) => {
|
||||
const trimmedLine = line.trim();
|
||||
|
||||
|
@@ -3,6 +3,8 @@
|
||||
* Provides user-friendly error messages for common SQL syntax issues
|
||||
*/
|
||||
|
||||
import { detectForeignDialect } from './dialect-detection';
|
||||
|
||||
export interface ValidationResult {
|
||||
isValid: boolean;
|
||||
errors: ValidationError[];
|
||||
@@ -212,7 +214,13 @@ export function validatePostgreSQLDialect(sql: string): ValidationResult {
|
||||
});
|
||||
}
|
||||
|
||||
// 9. Count CREATE TABLE statements
|
||||
// 9. Check for foreign SQL dialects
|
||||
const foreignDialectError = detectForeignDialect(lines, 'PostgreSQL');
|
||||
if (foreignDialectError) {
|
||||
errors.push(foreignDialectError);
|
||||
}
|
||||
|
||||
// 10. Count CREATE TABLE statements
|
||||
let tableCount = 0;
|
||||
const createTableRegex =
|
||||
/CREATE\s+TABLE(?:\s+IF\s+NOT\s+EXISTS)?(?:\s+ONLY)?\s+(?:"?[^"\s.]+?"?\.)?["'`]?[^"'`\s.(]+["'`]?/gi;
|
||||
|
@@ -8,6 +8,7 @@ import type {
|
||||
ValidationError,
|
||||
ValidationWarning,
|
||||
} from './postgresql-validator';
|
||||
import { detectForeignDialect } from './dialect-detection';
|
||||
|
||||
/**
|
||||
* Validates SQLite SQL syntax
|
||||
@@ -41,6 +42,12 @@ export function validateSQLiteDialect(sql: string): ValidationResult {
|
||||
const lines = sql.split('\n');
|
||||
let tableCount = 0;
|
||||
|
||||
// Check for foreign SQL dialects
|
||||
const foreignDialectError = detectForeignDialect(lines, 'SQLite');
|
||||
if (foreignDialectError) {
|
||||
errors.push(foreignDialectError);
|
||||
}
|
||||
|
||||
lines.forEach((line, index) => {
|
||||
const trimmedLine = line.trim();
|
||||
|
||||
|
@@ -8,6 +8,7 @@ import type {
|
||||
ValidationError,
|
||||
ValidationWarning,
|
||||
} from './postgresql-validator';
|
||||
import { detectForeignDialect } from './dialect-detection';
|
||||
|
||||
/**
|
||||
* Validates SQL Server SQL syntax
|
||||
@@ -34,13 +35,16 @@ export function validateSQLServerDialect(sql: string): ValidationResult {
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: Implement SQL Server-specific validation
|
||||
// For now, just do basic checks
|
||||
|
||||
// Check for common SQL Server syntax patterns
|
||||
const lines = sql.split('\n');
|
||||
let tableCount = 0;
|
||||
|
||||
// Check for foreign SQL dialects
|
||||
const foreignDialectError = detectForeignDialect(lines, 'SQL Server');
|
||||
if (foreignDialectError) {
|
||||
errors.push(foreignDialectError);
|
||||
}
|
||||
|
||||
lines.forEach((line, index) => {
|
||||
const trimmedLine = line.trim();
|
||||
|
||||
|
Reference in New Issue
Block a user