New creates a new Keywords instance with the specified SQL dialect and case sensitivity. The dialect parameter determines which dialect-specific keywords to include: - DialectGeneric: Standard SQL keywords only - DialectPostgreSQL: Includes PostgreSQL extensions (ILIKE, LATERAL, MATERIALIZED, RETUR
(dialect SQLDialect, ignoreCase bool)
| 229 | // fmt.Println("LATERAL is a PostgreSQL keyword") |
| 230 | // } |
| 231 | func New(dialect SQLDialect, ignoreCase bool) *Keywords { |
| 232 | k := &Keywords{ |
| 233 | reservedKeywords: make(map[string]bool), |
| 234 | keywordMap: make(map[string]Keyword), |
| 235 | dialect: dialect, |
| 236 | ignoreCase: true, // Always use case-insensitive comparison for SQL keywords |
| 237 | CompoundKeywords: make(map[string]models.TokenType), |
| 238 | } |
| 239 | |
| 240 | // Initialize compound keywords |
| 241 | k.CompoundKeywords["GROUP BY"] = models.TokenTypeKeyword |
| 242 | k.CompoundKeywords["ORDER BY"] = models.TokenTypeKeyword |
| 243 | k.CompoundKeywords["LEFT JOIN"] = models.TokenTypeKeyword |
| 244 | k.CompoundKeywords["FULL JOIN"] = models.TokenTypeKeyword |
| 245 | k.CompoundKeywords["CROSS JOIN"] = models.TokenTypeKeyword |
| 246 | k.CompoundKeywords["NATURAL JOIN"] = models.TokenTypeKeyword |
| 247 | k.CompoundKeywords["GROUPING SETS"] = models.TokenTypeKeyword // SQL-99 grouping operation |
| 248 | // Materialized views and DDL compound keywords |
| 249 | k.CompoundKeywords["MATERIALIZED VIEW"] = models.TokenTypeKeyword |
| 250 | k.CompoundKeywords["IF EXISTS"] = models.TokenTypeKeyword |
| 251 | k.CompoundKeywords["IF NOT EXISTS"] = models.TokenTypeKeyword |
| 252 | k.CompoundKeywords["OR REPLACE"] = models.TokenTypeKeyword |
| 253 | k.CompoundKeywords["WITH DATA"] = models.TokenTypeKeyword |
| 254 | k.CompoundKeywords["WITH NO DATA"] = models.TokenTypeKeyword |
| 255 | // Partitioning compound keywords |
| 256 | k.CompoundKeywords["PARTITION BY"] = models.TokenTypeKeyword |
| 257 | k.CompoundKeywords["LESS THAN"] = models.TokenTypeKeyword |
| 258 | k.CompoundKeywords["CHECK OPTION"] = models.TokenTypeKeyword |
| 259 | |
| 260 | // Add standard keywords |
| 261 | k.addKeywordsWithCategory(RESERVED_FOR_TABLE_ALIAS) |
| 262 | k.addKeywordsWithCategory(ADDITIONAL_KEYWORDS) |
| 263 | |
| 264 | // Add dialect-specific keywords |
| 265 | switch dialect { |
| 266 | case DialectMySQL: |
| 267 | k.addKeywordsWithCategory(MYSQL_SPECIFIC) |
| 268 | case DialectMariaDB: |
| 269 | // MariaDB is a superset of MySQL — load MySQL base first, then MariaDB extras |
| 270 | k.addKeywordsWithCategory(MYSQL_SPECIFIC) |
| 271 | k.addKeywordsWithCategory(MARIADB_SPECIFIC) |
| 272 | case DialectPostgreSQL: |
| 273 | k.addKeywordsWithCategory(POSTGRESQL_SPECIFIC) |
| 274 | case DialectSQLite: |
| 275 | k.addKeywordsWithCategory(SQLITE_SPECIFIC) |
| 276 | case DialectSnowflake: |
| 277 | k.addKeywordsWithCategory(SNOWFLAKE_SPECIFIC) |
| 278 | case DialectClickHouse: |
| 279 | k.addKeywordsWithCategory(CLICKHOUSE_SPECIFIC) |
| 280 | } |
| 281 | |
| 282 | // Build O(1) lookup cache for compound keyword first-words |
| 283 | k.compoundKeywordStarts = make(map[string]bool, len(k.CompoundKeywords)) |
| 284 | for compound := range k.CompoundKeywords { |
| 285 | if idx := strings.Index(compound, " "); idx > 0 { |
| 286 | k.compoundKeywordStarts[compound[:idx]] = true |
| 287 | } |
| 288 | } |