Newer
Older
cactus / src / main / java / com / cube / sql / CubicIndexSQLParser.java
@agalyaramadoss agalyaramadoss on 16 Feb 6 KB added document
package com.cube.sql;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Enhanced SQL Parser with Cubic Index support
 * 
 * Additional syntax:
 * - CREATE INDEX idx_name ON table(column)
 * - DROP INDEX idx_name
 * - SHOW INDEXES ON table
 */
public class CubicIndexSQLParser {
    
    // Patterns for index-related SQL
    private static final Pattern CREATE_INDEX_PATTERN = Pattern.compile(
        "CREATE\\s+INDEX\\s+(\\w+)\\s+ON\\s+([\\w.]+)\\s*\\(\\s*(\\w+)\\s*\\)",
        Pattern.CASE_INSENSITIVE
    );
    
    private static final Pattern DROP_INDEX_PATTERN = Pattern.compile(
        "DROP\\s+INDEX\\s+(\\w+)",
        Pattern.CASE_INSENSITIVE
    );
    
    private static final Pattern SHOW_INDEXES_PATTERN = Pattern.compile(
        "SHOW\\s+INDEXES\\s+ON\\s+([\\w.]+)",
        Pattern.CASE_INSENSITIVE
    );
    
    /**
     * Parse SQL with index support
     */
    public static IndexedParsedSQL parseWithIndex(String sql) {
        if (sql == null || sql.trim().isEmpty()) {
            throw new IllegalArgumentException("SQL statement is empty");
        }
        
        sql = sql.trim();
        if (sql.endsWith(";")) {
            sql = sql.substring(0, sql.length() - 1).trim();
        }
        
        String upperSQL = sql.toUpperCase();
        
        // Check for index-specific commands
        if (upperSQL.startsWith("CREATE INDEX")) {
            return parseCreateIndex(sql);
        } else if (upperSQL.startsWith("DROP INDEX")) {
            return parseDropIndex(sql);
        } else if (upperSQL.startsWith("SHOW INDEXES")) {
            return parseShowIndexes(sql);
        }
        
        // Fall back to regular SQL parsing
        SQLParser.ParsedSQL parsed = SQLParser.parse(sql);
        return convertToIndexed(parsed, sql);
    }
    
    /**
     * Parse CREATE INDEX statement
     * 
     * Syntax: CREATE INDEX idx_name ON table(column)
     * Example: CREATE INDEX idx_email ON users(email)
     */
    private static IndexedParsedSQL parseCreateIndex(String sql) {
        Matcher matcher = CREATE_INDEX_PATTERN.matcher(sql);
        
        if (!matcher.find()) {
            throw new IllegalArgumentException("Invalid CREATE INDEX syntax: " + sql);
        }
        
        String indexName = matcher.group(1);
        String tableName = matcher.group(2);
        String columnName = matcher.group(3);
        
        // Parse table name (might include keyspace)
        String keyspace = "default";
        String table = tableName;
        
        if (tableName.contains(".")) {
            String[] parts = tableName.split("\\.");
            keyspace = parts[0];
            table = parts[1];
        }
        
        return new IndexedParsedSQL.Builder()
            .type(SQLParser.SQLType.CREATE_INDEX)
            .keyspace(keyspace)
            .table(table)
            .indexName(indexName)
            .indexColumn(columnName)
            .indexType(IndexedParsedSQL.IndexType.CUBIC)
            .originalSQL(sql)
            .build();
    }
    
    /**
     * Parse DROP INDEX statement
     * 
     * Syntax: DROP INDEX idx_name
     * Example: DROP INDEX idx_email
     */
    private static IndexedParsedSQL parseDropIndex(String sql) {
        Matcher matcher = DROP_INDEX_PATTERN.matcher(sql);
        
        if (!matcher.find()) {
            throw new IllegalArgumentException("Invalid DROP INDEX syntax: " + sql);
        }
        
        String indexName = matcher.group(1);
        
        return new IndexedParsedSQL.Builder()
            .type(SQLParser.SQLType.DROP_INDEX)
            .indexName(indexName)
            .originalSQL(sql)
            .build();
    }
    
    /**
     * Parse SHOW INDEXES statement
     * 
     * Syntax: SHOW INDEXES ON table
     * Example: SHOW INDEXES ON users
     */
    private static IndexedParsedSQL parseShowIndexes(String sql) {
        Matcher matcher = SHOW_INDEXES_PATTERN.matcher(sql);
        
        if (!matcher.find()) {
            throw new IllegalArgumentException("Invalid SHOW INDEXES syntax: " + sql);
        }
        
        String tableName = matcher.group(1);
        
        // Parse table name
        String keyspace = "default";
        String table = tableName;
        
        if (tableName.contains(".")) {
            String[] parts = tableName.split("\\.");
            keyspace = parts[0];
            table = parts[1];
        }
        
        return new IndexedParsedSQL.Builder()
            .type(SQLParser.SQLType.SHOW_INDEXES)
            .keyspace(keyspace)
            .table(table)
            .originalSQL(sql)
            .build();
    }
    
    /**
     * Convert regular ParsedSQL to IndexedParsedSQL
     */
    private static IndexedParsedSQL convertToIndexed(SQLParser.ParsedSQL parsed, String originalSQL) {
        // Determine primary key from column definitions
        String primaryKey = parsed.getPrimaryKey();
        if (primaryKey == null && parsed.getColumnDefinitions() != null) {
            primaryKey = parsed.getColumnDefinitions().keySet().iterator().hasNext() ?
                parsed.getColumnDefinitions().keySet().iterator().next() : null;
        }
        
        return new IndexedParsedSQL.Builder()
            .type(parsed.getType())
            .keyspace(parsed.getKeyspace())
            .table(parsed.getTable())
            .columns(parsed.getColumns())
            .whereClause(parsed.getWhereClause())
            .selectColumns(parsed.getSelectColumns())
            .columnDefinitions(parsed.getColumnDefinitions())
            .primaryKey(primaryKey)
            .indexType(IndexedParsedSQL.IndexType.PRIMARY)
            .originalSQL(originalSQL)
            .build();
    }
    
    /**
     * Validate index name
     */
    public static boolean isValidIndexName(String indexName) {
        return indexName != null && indexName.matches("[a-zA-Z_][a-zA-Z0-9_]*");
    }
    
    /**
     * Generate index key for storage
     */
    public static String generateIndexKey(String keyspace, String table, String column) {
        return keyspace + "." + table + "." + column;
    }
    
    /**
     * Parse index key
     */
    public static String[] parseIndexKey(String indexKey) {
        if (indexKey == null) {
            return null;
        }
        
        String[] parts = indexKey.split("\\.");
        if (parts.length != 3) {
            return null;
        }
        
        return parts; // [keyspace, table, column]
    }
}