validateFile validates a single SQL file or direct SQL input
(filename string)
| 220 | |
| 221 | // validateFile validates a single SQL file or direct SQL input |
| 222 | func (v *Validator) validateFile(filename string) output.FileValidationResult { |
| 223 | result := output.FileValidationResult{ |
| 224 | Path: filename, |
| 225 | } |
| 226 | |
| 227 | // Use robust input detection with security checks |
| 228 | inputResult, err := DetectAndReadInput(filename) |
| 229 | if err != nil { |
| 230 | // Special handling for empty files - they're considered valid |
| 231 | if strings.Contains(err.Error(), "file is empty") { |
| 232 | result.Valid = true |
| 233 | result.Size = 0 |
| 234 | return result |
| 235 | } |
| 236 | // Map file path errors to "file access validation failed" for consistency |
| 237 | if strings.Contains(err.Error(), "invalid file path") || strings.Contains(err.Error(), "security validation failed") { |
| 238 | result.Error = fmt.Errorf("file access validation failed: %w", err) |
| 239 | } else { |
| 240 | result.Error = fmt.Errorf("input processing failed: %w", err) |
| 241 | } |
| 242 | return result |
| 243 | } |
| 244 | |
| 245 | data := inputResult.Content |
| 246 | result.Size = int64(len(data)) |
| 247 | |
| 248 | if len(data) == 0 { |
| 249 | result.Valid = true |
| 250 | return result // Empty inputs are considered valid |
| 251 | } |
| 252 | |
| 253 | // Use pooled tokenizer for performance with dialect support |
| 254 | tkz := tokenizer.GetTokenizer() |
| 255 | defer tokenizer.PutTokenizer(tkz) |
| 256 | |
| 257 | // Configure dialect if specified |
| 258 | if v.Opts.Dialect != "" { |
| 259 | tkz.SetDialect(keywords.SQLDialect(v.Opts.Dialect)) |
| 260 | } |
| 261 | |
| 262 | // Tokenize |
| 263 | tokens, err := tkz.Tokenize(data) |
| 264 | if err != nil { |
| 265 | result.Error = fmt.Errorf("tokenization failed: %w", err) |
| 266 | return result |
| 267 | } |
| 268 | |
| 269 | if len(tokens) == 0 { |
| 270 | result.Valid = true |
| 271 | return result |
| 272 | } |
| 273 | |
| 274 | // Convert TokenWithSpan to Token using centralized converter |
| 275 | |
| 276 | // Parse to validate syntax with proper error handling for memory management |
| 277 | p := parser.NewParser(parser.WithDialect(v.Opts.Dialect)) |
| 278 | astObj, err := p.ParseFromModelTokens(tokens) |
| 279 | if err != nil { |