You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							142 lines
						
					
					
						
							3.1 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							142 lines
						
					
					
						
							3.1 KiB
						
					
					
				
								package sqlutil
							 | 
						|
								
							 | 
						|
								import (
							 | 
						|
									"strings"
							 | 
						|
								)
							 | 
						|
								
							 | 
						|
								// SplitStatements splits a query string into individual SQL statements.
							 | 
						|
								// This robust implementation handles SQL comments, quoted strings, and escaped characters.
							 | 
						|
								//
							 | 
						|
								// Features:
							 | 
						|
								// - Handles single-line comments (-- comment)
							 | 
						|
								// - Handles multi-line comments (/* comment */)
							 | 
						|
								// - Properly escapes single quotes in strings ('don”t')
							 | 
						|
								// - Properly escapes double quotes in identifiers ("column""name")
							 | 
						|
								// - Ignores semicolons within quoted strings and comments
							 | 
						|
								// - Returns clean, trimmed statements with empty statements filtered out
							 | 
						|
								func SplitStatements(query string) []string {
							 | 
						|
									var statements []string
							 | 
						|
									var current strings.Builder
							 | 
						|
								
							 | 
						|
									query = strings.TrimSpace(query)
							 | 
						|
									if query == "" {
							 | 
						|
										return []string{}
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									runes := []rune(query)
							 | 
						|
									i := 0
							 | 
						|
								
							 | 
						|
									for i < len(runes) {
							 | 
						|
										char := runes[i]
							 | 
						|
								
							 | 
						|
										// Handle single-line comments (-- comment)
							 | 
						|
										if char == '-' && i+1 < len(runes) && runes[i+1] == '-' {
							 | 
						|
											// Skip the entire comment without including it in any statement
							 | 
						|
											for i < len(runes) && runes[i] != '\n' && runes[i] != '\r' {
							 | 
						|
												i++
							 | 
						|
											}
							 | 
						|
											// Skip the newline if present
							 | 
						|
											if i < len(runes) {
							 | 
						|
												i++
							 | 
						|
											}
							 | 
						|
											continue
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										// Handle multi-line comments (/* comment */)
							 | 
						|
										if char == '/' && i+1 < len(runes) && runes[i+1] == '*' {
							 | 
						|
											// Skip the /* opening
							 | 
						|
											i++
							 | 
						|
											i++
							 | 
						|
								
							 | 
						|
											// Skip to end of comment or end of input without including content
							 | 
						|
											for i < len(runes) {
							 | 
						|
												if runes[i] == '*' && i+1 < len(runes) && runes[i+1] == '/' {
							 | 
						|
													i++ // Skip the *
							 | 
						|
													i++ // Skip the /
							 | 
						|
													break
							 | 
						|
												}
							 | 
						|
												i++
							 | 
						|
											}
							 | 
						|
											continue
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										// Handle single-quoted strings
							 | 
						|
										if char == '\'' {
							 | 
						|
											current.WriteRune(char)
							 | 
						|
											i++
							 | 
						|
								
							 | 
						|
											for i < len(runes) {
							 | 
						|
												char = runes[i]
							 | 
						|
												current.WriteRune(char)
							 | 
						|
								
							 | 
						|
												if char == '\'' {
							 | 
						|
													// Check if it's an escaped quote
							 | 
						|
													if i+1 < len(runes) && runes[i+1] == '\'' {
							 | 
						|
														i++ // Skip the next quote (it's escaped)
							 | 
						|
														if i < len(runes) {
							 | 
						|
															current.WriteRune(runes[i])
							 | 
						|
														}
							 | 
						|
													} else {
							 | 
						|
														break // End of string
							 | 
						|
													}
							 | 
						|
												}
							 | 
						|
												i++
							 | 
						|
											}
							 | 
						|
											i++
							 | 
						|
											continue
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										// Handle double-quoted identifiers
							 | 
						|
										if char == '"' {
							 | 
						|
											current.WriteRune(char)
							 | 
						|
											i++
							 | 
						|
								
							 | 
						|
											for i < len(runes) {
							 | 
						|
												char = runes[i]
							 | 
						|
												current.WriteRune(char)
							 | 
						|
								
							 | 
						|
												if char == '"' {
							 | 
						|
													// Check if it's an escaped quote
							 | 
						|
													if i+1 < len(runes) && runes[i+1] == '"' {
							 | 
						|
														i++ // Skip the next quote (it's escaped)
							 | 
						|
														if i < len(runes) {
							 | 
						|
															current.WriteRune(runes[i])
							 | 
						|
														}
							 | 
						|
													} else {
							 | 
						|
														break // End of identifier
							 | 
						|
													}
							 | 
						|
												}
							 | 
						|
												i++
							 | 
						|
											}
							 | 
						|
											i++
							 | 
						|
											continue
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										// Handle semicolon (statement separator)
							 | 
						|
										if char == ';' {
							 | 
						|
											stmt := strings.TrimSpace(current.String())
							 | 
						|
											if stmt != "" {
							 | 
						|
												statements = append(statements, stmt)
							 | 
						|
											}
							 | 
						|
											current.Reset()
							 | 
						|
										} else {
							 | 
						|
											current.WriteRune(char)
							 | 
						|
										}
							 | 
						|
										i++
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Add any remaining statement
							 | 
						|
									if current.Len() > 0 {
							 | 
						|
										stmt := strings.TrimSpace(current.String())
							 | 
						|
										if stmt != "" {
							 | 
						|
											statements = append(statements, stmt)
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// If no statements found, return the original query as a single statement
							 | 
						|
									if len(statements) == 0 {
							 | 
						|
										return []string{strings.TrimSpace(strings.TrimSuffix(strings.TrimSpace(query), ";"))}
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									return statements
							 | 
						|
								}
							 |