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 | |
| }
 |