Apache Phoenix Core library providing SQL-on-HBase functionality with JDBC connectivity, query compilation, and transaction support
Phoenix's query compilation framework transforms SQL statements into optimized execution plans that leverage HBase's distributed architecture. This system provides query optimization, predicate pushdown, and efficient execution planning.
import org.apache.phoenix.query.*;
import org.apache.phoenix.compile.*;
import org.apache.phoenix.schema.*;
import org.apache.phoenix.expression.*;Base interface defining core Phoenix query services and configuration.
public interface QueryServices {
Configuration getConfiguration()
void close() throws SQLException
Props getProps()
StatsManager getStatsManager()
}Main implementation of Phoenix query services.
public class QueryServicesImpl implements QueryServices {
public QueryServicesImpl(Configuration config, Props props)
public Configuration getConfiguration()
public Props getProps()
public StatsManager getStatsManager()
}Usage:
Configuration config = HBaseConfiguration.create();
Props props = Props.create();
QueryServices queryServices = new QueryServicesImpl(config, props);Connection-specific query services providing metadata operations, table management, and HBase integration.
public interface ConnectionQueryServices extends QueryServices, MetaDataMutated {
// Table operations
PTable getTable(PName tableName) throws SQLException
TableDescriptor getTableDescriptor(byte[] tableName) throws SQLException
// Metadata operations
long getMetaDataMutated(PName schemaName, PName tableName, long tableSeqNum)
throws SQLException
// Admin operations
Admin getAdmin() throws SQLException
void dropTable(PName tableName) throws SQLException
// Statistics operations
void updateStatistics(List<Mutation> statsTable) throws SQLException
// Index operations
void createIndex(CreateIndexStatement statement, boolean allocateIndexId)
throws SQLException
void dropIndex(PName schemaName, PName indexName, PName tableName, long timestamp)
throws SQLException
}Main implementation of connection query services.
public class ConnectionQueryServicesImpl extends QueryServicesImpl
implements ConnectionQueryServices {
public ConnectionQueryServicesImpl(Configuration config, ConnectionInfo connectionInfo)
public PTable getTable(PName tableName) throws SQLException
public Admin getAdmin() throws SQLException
public long getMetaDataMutated(PName schemaName, PName tableName, long tableSeqNum)
}Usage:
ConnectionInfo connInfo = ConnectionInfo.create("jdbc:phoenix:localhost:2181");
ConnectionQueryServices queryServices = new ConnectionQueryServicesImpl(config, connInfo);
// Access table metadata
PName tableName = PNameFactory.newName("users");
PTable table = queryServices.getTable(tableName);
// Get HBase admin
Admin admin = queryServices.getAdmin();Query services implementation for connectionless mode (typically used for testing).
public class ConnectionlessQueryServicesImpl implements ConnectionQueryServices {
public ConnectionlessQueryServicesImpl(Configuration config, Props props)
// Provides minimal implementation without HBase connectivity
public PTable getTable(PName tableName) throws SQLException
public Admin getAdmin() throws SQLException
}Base interface for all query execution plans.
public interface QueryPlan {
StatementContext getContext()
ParameterMetaData getParameterMetaData()
ExplainPlan getExplainPlan() throws SQLException
ResultIterator iterator() throws SQLException
long getEstimatedSize()
Cost getCost()
}Interface for statement execution plans.
public interface StatementPlan extends QueryPlan {
Operation getOperation()
StatementType getStatementType()
}Interface for data mutation plans (INSERT, UPDATE, DELETE).
public interface MutationPlan extends StatementPlan {
MutationState execute() throws SQLException
long getEstimatedRowsToScan()
Long getEstimatedBytesToScan()
}Usage:
// Compile a query plan
QueryCompiler compiler = new QueryCompiler();
String sql = "SELECT * FROM users WHERE age > ?";
QueryPlan plan = compiler.compile(sql, context);
// Analyze the plan
ExplainPlan explainPlan = plan.getExplainPlan();
long estimatedSize = plan.getEstimatedSize();
// Execute the plan
ResultIterator iterator = plan.iterator();Main query compilation engine that transforms SQL into execution plans.
public class QueryCompiler {
public QueryPlan compile(SelectStatement select, StatementContext context)
throws SQLException
public QueryPlan compile(String sql, StatementContext context) throws SQLException
public MutationPlan compile(UpsertStatement upsert, StatementContext context)
throws SQLException
public QueryPlan compileJoin(SelectStatement select, StatementContext context)
throws SQLException
}Usage:
QueryCompiler compiler = new QueryCompiler();
StatementContext context = new StatementContext(connection, resolver);
// Compile SELECT statement
String selectSql = "SELECT id, name FROM users WHERE status = 'ACTIVE' ORDER BY created_date";
QueryPlan selectPlan = compiler.compile(selectSql, context);
// Compile INSERT statement
String upsertSql = "UPSERT INTO users (id, name, status) VALUES (?, ?, ?)";
MutationPlan upsertPlan = compiler.compile(parseUpsert(upsertSql), context);Compiles SQL expressions into Phoenix expression objects.
public class ExpressionCompiler extends ParseNodeVisitor<Expression> {
public ExpressionCompiler(StatementContext context)
public ExpressionCompiler(StatementContext context, GroupBy groupBy)
public Expression visit(LiteralParseNode node) throws SQLException
public Expression visit(ColumnParseNode node) throws SQLException
public Expression visit(FunctionParseNode node) throws SQLException
public Expression visit(ComparisonParseNode node) throws SQLException
}Usage:
StatementContext context = new StatementContext(connection, resolver);
ExpressionCompiler exprCompiler = new ExpressionCompiler(context);
// Compile individual expressions
ParseNode literalNode = new LiteralParseNode("'active'");
Expression literalExpr = exprCompiler.visit(literalNode);
ParseNode columnNode = new ColumnParseNode(null, "status", null);
Expression columnExpr = exprCompiler.visit(columnNode);Compiled representation of SELECT statements.
public class SelectStatement implements FilterableStatement {
public SelectStatement(FromClause from, HintNode hint, boolean distinct,
List<AliasedNode> select, ParseNode where,
List<ParseNode> groupBy, ParseNode having,
List<OrderByNode> orderBy, LimitNode limit)
public FromClause getFrom()
public List<AliasedNode> getSelect()
public ParseNode getWhere()
public List<ParseNode> getGroupBy()
public List<OrderByNode> getOrderBy()
public LimitNode getLimit()
}Compiler for CREATE TABLE statements.
public class CreateTableCompiler {
public MutationPlan compile(CreateTableStatement create) throws SQLException
public static class CreateTableMutationPlan implements MutationPlan {
public MutationState execute() throws SQLException
public ExplainPlan getExplainPlan() throws SQLException
public StatementContext getContext()
}
}Compiler for CREATE INDEX statements.
public class CreateIndexCompiler {
public MutationPlan compile(CreateIndexStatement create) throws SQLException
public static class CreateIndexMutationPlan implements MutationPlan {
public MutationState execute() throws SQLException
public long getEstimatedRowsToScan()
public Long getEstimatedBytesToScan()
}
}Compiler for CREATE SCHEMA statements.
public class CreateSchemaCompiler {
public MutationPlan compile(CreateSchemaStatement create) throws SQLException
public static class CreateSchemaMutationPlan implements MutationPlan {
public MutationState execute() throws SQLException
public StatementType getStatementType()
}
}Compiler for CREATE SEQUENCE statements.
public class CreateSequenceCompiler {
public MutationPlan compile(CreateSequenceStatement sequence) throws SQLException
public static class CreateSequenceMutationPlan implements MutationPlan {
public MutationState execute() throws SQLException
public long getEstimatedRowsToScan()
}
}Compiler for CREATE FUNCTION statements.
public class CreateFunctionCompiler {
public MutationPlan compile(CreateFunctionStatement function) throws SQLException
public static class CreateFunctionMutationPlan implements MutationPlan {
public MutationState execute() throws SQLException
public StatementContext getContext()
}
}Usage:
// Compile CREATE TABLE statement
CreateTableCompiler tableCompiler = new CreateTableCompiler();
CreateTableStatement createTable = parseCreateTable(
"CREATE TABLE users (id BIGINT PRIMARY KEY, name VARCHAR, email VARCHAR)"
);
MutationPlan tablePlan = tableCompiler.compile(createTable);
tablePlan.execute();
// Compile CREATE INDEX statement
CreateIndexCompiler indexCompiler = new CreateIndexCompiler();
CreateIndexStatement createIndex = parseCreateIndex(
"CREATE INDEX user_email_idx ON users (email)"
);
MutationPlan indexPlan = indexCompiler.compile(createIndex);
indexPlan.execute();Projects columns in query results.
public class ColumnProjector {
public ColumnProjector(String name, String tableName, String familyName,
String columnName, Expression expression, boolean caseSensitive)
public String getName()
public Expression getExpression()
public String getTableName()
public String getFamilyName()
public String getColumnName()
}Resolves column references in SQL expressions.
public interface ColumnResolver {
List<TableRef> getTables()
TableRef resolveTable(String schemaName, String tableName) throws SQLException
ColumnRef resolveColumn(String schemaName, String tableName, String colName)
throws SQLException
}Projects expressions in query results.
public class ExpressionProjector extends ColumnProjector {
public ExpressionProjector(String name, String tableName, Expression expression,
boolean isCaseSensitive)
public boolean hasValueExpression()
public KeyValueColumnExpression getKeyValueColumnExpression()
}Usage:
// Set up column resolver
ColumnResolver resolver = new MyColumnResolver(tables);
// Create column projector
Expression nameExpr = new ColumnExpression(nameColumn);
ColumnProjector nameProjector = new ColumnProjector(
"name", "users", "cf", "name", nameExpr, false
);
// Create expression projector
Expression upperNameExpr = new UpperFunction(Arrays.asList(nameExpr));
ExpressionProjector upperProjector = new ExpressionProjector(
"upper_name", "users", upperNameExpr, false
);Maintains state and context during query compilation and execution.
public class StatementContext {
public StatementContext(PhoenixConnection connection)
public StatementContext(PhoenixConnection connection, ColumnResolver resolver)
public PhoenixConnection getConnection()
public ColumnResolver getResolver()
public Scan getScan()
public SequenceManager getSequenceManager()
public GroupBy getGroupBy()
public OrderBy getOrderBy()
}Interface for statements that can be compiled into execution plans.
public interface CompilableStatement extends BindableStatement {
QueryPlan compilePlan(StatementContext context, Sequence.ValueOp seqAction)
throws SQLException
Operation getOperation()
}Usage:
// Create statement context
PhoenixConnection connection = getPhoenixConnection();
ColumnResolver resolver = createResolver(connection);
StatementContext context = new StatementContext(connection, resolver);
// Configure context
Scan scan = context.getScan();
scan.setCaching(1000);
scan.setBatch(100);
// Use context for compilation
QueryCompiler compiler = new QueryCompiler();
QueryPlan plan = compiler.compile(selectStatement, context);// Cost-based optimization
public class CostBasedOptimizer {
public QueryPlan optimize(QueryPlan plan, StatementContext context) throws SQLException
public Cost estimateCost(QueryPlan plan) throws SQLException
}
// Usage
CostBasedOptimizer optimizer = new CostBasedOptimizer();
QueryPlan optimizedPlan = optimizer.optimize(originalPlan, context);
Cost estimatedCost = optimizer.estimateCost(optimizedPlan);// Pushdown optimization for server-side filtering
public class PredicatePushdownOptimizer {
public Scan optimizeScan(Scan scan, Expression whereClause)
public Filter createPushdownFilter(Expression expression)
}
// Usage
PredicatePushdownOptimizer pushdown = new PredicatePushdownOptimizer();
Scan optimizedScan = pushdown.optimizeScan(originalScan, whereExpression);// Join strategy selection and optimization
public class JoinCompiler {
public QueryPlan compileJoin(SelectStatement select, StatementContext context)
throws SQLException
public JoinStrategy selectJoinStrategy(SelectStatement select)
}
// Usage
JoinCompiler joinCompiler = new JoinCompiler();
QueryPlan joinPlan = joinCompiler.compileJoin(joinSelect, context);// Set up compilation environment
PhoenixConnection connection = getConnection();
ColumnResolver resolver = createTableResolver(connection, "users");
StatementContext context = new StatementContext(connection, resolver);
// Compile a simple query
QueryCompiler compiler = new QueryCompiler();
String sql = "SELECT id, name FROM users WHERE status = 'ACTIVE'";
SelectStatement select = parseSelect(sql);
QueryPlan plan = compiler.compile(select, context);
// Examine the plan
ExplainPlan explainPlan = plan.getExplainPlan();
System.out.println("Query Plan: " + explainPlan.toString());
// Execute the plan
ResultIterator iterator = plan.iterator();// Compile aggregation query
String aggregateSql = """
SELECT department, COUNT(*), AVG(salary), MAX(hire_date)
FROM employees
WHERE status = 'ACTIVE'
GROUP BY department
HAVING COUNT(*) > 10
ORDER BY department
""";
QueryPlan aggPlan = compiler.compile(aggregateSql, context);
Cost cost = aggPlan.getCost();
long estimatedSize = aggPlan.getEstimatedSize();
System.out.println("Estimated cost: " + cost);
System.out.println("Estimated size: " + estimatedSize + " bytes");// Compile CREATE TABLE statement
CreateTableCompiler tableCompiler = new CreateTableCompiler();
String createTableSql = """
CREATE TABLE orders (
order_id BIGINT NOT NULL,
customer_id BIGINT NOT NULL,
order_date DATE,
amount DECIMAL(10,2),
status VARCHAR(20),
CONSTRAINT pk PRIMARY KEY (order_id)
)
""";
CreateTableStatement createTable = parseCreateTable(createTableSql);
MutationPlan tablePlan = tableCompiler.compile(createTable);
// Execute the DDL
MutationState result = tablePlan.execute();// Compile CREATE INDEX statement
CreateIndexCompiler indexCompiler = new CreateIndexCompiler();
String createIndexSql = "CREATE INDEX order_customer_idx ON orders (customer_id, order_date)";
CreateIndexStatement createIndex = parseCreateIndex(createIndexSql);
MutationPlan indexPlan = indexCompiler.compile(createIndex);
// Check estimated work
long estimatedRows = indexPlan.getEstimatedRowsToScan();
Long estimatedBytes = indexPlan.getEstimatedBytesToScan();
System.out.println("Index will scan approximately " + estimatedRows + " rows");
System.out.println("Index will scan approximately " + estimatedBytes + " bytes");
// Execute index creation
MutationState indexResult = indexPlan.execute();Install with Tessl CLI
npx tessl i tessl/maven-org-apache-phoenix--phoenix-core