use of herddb.model.planner.PlannerOp in project herddb by diennea.
the class CalcitePlanner method translate.
@Override
public TranslatedQuery translate(String defaultTableSpace, String query, List<Object> parameters, boolean scan, boolean allowCache, boolean returnValues, int maxRows) throws StatementExecutionException {
ensureDefaultTableSpaceBootedLocally(defaultTableSpace);
/* Strips out leading comments */
int idx = SQLUtils.findQueryStart(query);
if (idx != -1) {
query = query.substring(idx);
}
if (parameters == null) {
parameters = Collections.emptyList();
}
String cacheKey = "scan:" + scan + ",defaultTableSpace:" + defaultTableSpace + ",query:" + query + ",returnValues:" + returnValues + ",maxRows:" + maxRows;
boolean forceAcquireWriteLock;
if (// this looks very hacky
query.endsWith(" FOR UPDATE") && query.substring(0, 6).toLowerCase().equals("select")) {
forceAcquireWriteLock = true;
query = query.substring(0, query.length() - " FOR UPDATE".length());
} else {
forceAcquireWriteLock = false;
}
if (allowCache) {
ExecutionPlan cached = cache.get(cacheKey);
if (cached != null) {
return new TranslatedQuery(cached, new SQLStatementEvaluationContext(query, parameters, forceAcquireWriteLock, false));
}
}
if (isDDL(query)) {
query = JSQLParserPlanner.rewriteExecuteSyntax(query);
return fallback.translate(defaultTableSpace, query, parameters, scan, allowCache, returnValues, maxRows);
}
if (query.startsWith(TABLE_CONSISTENCY_COMMAND)) {
query = JSQLParserPlanner.rewriteExecuteSyntax(query);
return fallback.translate(defaultTableSpace, query, parameters, scan, allowCache, returnValues, maxRows);
}
if (query.startsWith(TABLESPACE_CONSISTENCY_COMMAND)) {
query = JSQLParserPlanner.rewriteExecuteSyntax(query);
return fallback.translate(defaultTableSpace, query, parameters, scan, allowCache, returnValues, maxRows);
}
if (!isCachable(query)) {
allowCache = false;
}
try {
if (query.startsWith("EXPLAIN ")) {
query = query.substring("EXPLAIN ".length());
PlannerResult plan = runPlanner(defaultTableSpace, query);
boolean upsert = detectUpsert(plan);
PlannerOp finalPlan = convertRelNode(plan.topNode, plan.originalRowType, returnValues, upsert).optimize();
ValuesOp values = new ValuesOp(manager.getNodeId(), new String[] { "name", "value" }, new Column[] { column("name", ColumnTypes.STRING), column("value", ColumnTypes.STRING) }, java.util.Arrays.asList(java.util.Arrays.asList(new ConstantExpression("query", ColumnTypes.NOTNULL_STRING), new ConstantExpression(query, ColumnTypes.NOTNULL_STRING)), java.util.Arrays.asList(new ConstantExpression("logicalplan", ColumnTypes.NOTNULL_STRING), new ConstantExpression(RelOptUtil.dumpPlan("", plan.logicalPlan, SqlExplainFormat.TEXT, SqlExplainLevel.ALL_ATTRIBUTES), ColumnTypes.NOTNULL_STRING)), java.util.Arrays.asList(new ConstantExpression("plan", ColumnTypes.NOTNULL_STRING), new ConstantExpression(RelOptUtil.dumpPlan("", plan.topNode, SqlExplainFormat.TEXT, SqlExplainLevel.ALL_ATTRIBUTES), ColumnTypes.NOTNULL_STRING)), java.util.Arrays.asList(new ConstantExpression("finalplan", ColumnTypes.NOTNULL_STRING), new ConstantExpression(finalPlan + "", ColumnTypes.NOTNULL_STRING))));
ExecutionPlan executionPlan = ExecutionPlan.simple(new SQLPlannedOperationStatement(values), values);
return new TranslatedQuery(executionPlan, new SQLStatementEvaluationContext(query, parameters, false, false));
}
if (query.startsWith("SHOW")) {
return calculateShowCreateTable(query, defaultTableSpace, parameters, manager);
}
PlannerResult plan = runPlanner(defaultTableSpace, query);
boolean upsert = detectUpsert(plan);
SQLPlannedOperationStatement sqlPlannedOperationStatement = new SQLPlannedOperationStatement(convertRelNode(plan.topNode, plan.originalRowType, returnValues, upsert).optimize());
if (LOG.isLoggable(DUMP_QUERY_LEVEL)) {
LOG.log(DUMP_QUERY_LEVEL, "Query: {0} --HerdDB Plan\n{1}", new Object[] { query, sqlPlannedOperationStatement.getRootOp() });
}
if (!scan) {
ScanStatement scanStatement = sqlPlannedOperationStatement.unwrap(ScanStatement.class);
if (scanStatement != null) {
Table tableDef = scanStatement.getTableDef();
CompiledSQLExpression where = scanStatement.getPredicate().unwrap(CompiledSQLExpression.class);
SQLRecordKeyFunction keyFunction = IndexUtils.findIndexAccess(where, tableDef.getPrimaryKey(), tableDef, "=", tableDef);
if (keyFunction == null || !keyFunction.isFullPrimaryKey()) {
throw new StatementExecutionException("unsupported GET not on PK, bad where clause: " + query);
}
GetStatement get = new GetStatement(scanStatement.getTableSpace(), scanStatement.getTable(), keyFunction, scanStatement.getPredicate(), true);
ExecutionPlan executionPlan = ExecutionPlan.simple(get);
if (allowCache) {
cache.put(cacheKey, executionPlan);
}
return new TranslatedQuery(executionPlan, new SQLStatementEvaluationContext(query, parameters, forceAcquireWriteLock, false));
}
}
if (maxRows > 0) {
PlannerOp op = new LimitOp(sqlPlannedOperationStatement.getRootOp(), new ConstantExpression(maxRows, ColumnTypes.NOTNULL_LONG), new ConstantExpression(0, ColumnTypes.NOTNULL_LONG)).optimize();
sqlPlannedOperationStatement = new SQLPlannedOperationStatement(op);
}
PlannerOp rootOp = sqlPlannedOperationStatement.getRootOp();
ExecutionPlan executionPlan;
if (rootOp.isSimpleStatementWrapper()) {
executionPlan = ExecutionPlan.simple(rootOp.unwrap(herddb.model.Statement.class), rootOp);
} else {
executionPlan = ExecutionPlan.simple(sqlPlannedOperationStatement, rootOp);
}
if (allowCache) {
cache.put(cacheKey, executionPlan);
}
return new TranslatedQuery(executionPlan, new SQLStatementEvaluationContext(query, parameters, forceAcquireWriteLock, false));
} catch (CalciteContextException ex) {
LOG.log(Level.INFO, "Error while parsing '" + ex.getOriginalStatement() + "'", ex);
// TODO can this be done better ?
throw new StatementExecutionException(ex.getMessage());
} catch (RelConversionException | ValidationException | SqlParseException ex) {
LOG.log(Level.INFO, "Error while parsing '" + query + "'", ex);
// TODO can this be done better ?
throw new StatementExecutionException(ex.getMessage().replace("org.apache.calcite.runtime.CalciteContextException: ", ""), ex);
} catch (MetadataStorageManagerException ex) {
LOG.log(Level.INFO, "Error while parsing '" + query + "'", ex);
throw new StatementExecutionException(ex);
}
}
use of herddb.model.planner.PlannerOp in project herddb by diennea.
the class CalcitePlanner method planEnumerableUnion.
private PlannerOp planEnumerableUnion(EnumerableUnion op, RelDataType rowType, boolean returnValues) {
if (!op.all) {
throw new StatementExecutionException("not suppoer UNION, all=false");
}
List<PlannerOp> inputs = new ArrayList<>(op.getInputs().size());
for (RelNode input : op.getInputs()) {
PlannerOp inputOp = convertRelNode(input, rowType, false, false).optimize();
inputs.add(inputOp);
}
return new UnionAllOp(inputs);
}
use of herddb.model.planner.PlannerOp in project herddb by diennea.
the class CalcitePlanner method planEnumerableMergeJoin.
private PlannerOp planEnumerableMergeJoin(EnumerableMergeJoin op, RelDataType rowType) {
// please note that EnumerableMergeJoin has a condition field which actually is not useful
PlannerOp left = convertRelNode(op.getLeft(), null, false, false);
PlannerOp right = convertRelNode(op.getRight(), null, false, false);
final JoinInfo analyzeCondition = op.analyzeCondition();
int[] leftKeys = analyzeCondition.leftKeys.toIntArray();
int[] rightKeys = analyzeCondition.rightKeys.toIntArray();
boolean generateNullsOnLeft = op.getJoinType().generatesNullsOnLeft();
boolean generateNullsOnRight = op.getJoinType().generatesNullsOnRight();
final RelDataType _rowType = rowType == null ? op.getRowType() : rowType;
List<CompiledSQLExpression> nonEquiConditions = convertJoinNonEquiConditions(analyzeCondition);
List<RelDataTypeField> fieldList = _rowType.getFieldList();
Column[] columns = new Column[fieldList.size()];
String[] fieldNames = new String[columns.length];
int i = 0;
for (RelDataTypeField field : fieldList) {
Column col = Column.column(field.getName().toLowerCase(), convertToHerdType(field.getType()));
fieldNames[i] = col.name;
columns[i++] = col;
}
return new JoinOp(fieldNames, columns, leftKeys, left, rightKeys, right, generateNullsOnLeft, generateNullsOnRight, true, nonEquiConditions);
}
use of herddb.model.planner.PlannerOp in project herddb by diennea.
the class CalcitePlanner method planEnumerableHashJoin.
private PlannerOp planEnumerableHashJoin(EnumerableHashJoin op, RelDataType rowType) {
// please note that EnumerableSemiJoin has a condition field which actually is not useful
PlannerOp left = convertRelNode(op.getLeft(), null, false, false);
PlannerOp right = convertRelNode(op.getRight(), null, false, false);
final JoinInfo analyzeCondition = op.analyzeCondition();
int[] leftKeys = analyzeCondition.leftKeys.toIntArray();
int[] rightKeys = analyzeCondition.rightKeys.toIntArray();
boolean generateNullsOnLeft = op.getJoinType().generatesNullsOnLeft();
boolean generateNullsOnRight = op.getJoinType().generatesNullsOnRight();
List<CompiledSQLExpression> nonEquiConditions = convertJoinNonEquiConditions(analyzeCondition);
final RelDataType _rowType = rowType == null ? op.getRowType() : rowType;
List<RelDataTypeField> fieldList = _rowType.getFieldList();
Column[] columns = new Column[fieldList.size()];
String[] fieldNames = new String[columns.length];
int i = 0;
for (RelDataTypeField field : fieldList) {
Column col = Column.column(field.getName().toLowerCase(), convertToHerdType(field.getType()));
fieldNames[i] = col.name;
columns[i++] = col;
}
if (op.isSemiJoin()) {
return new SemiJoinOp(fieldNames, columns, leftKeys, left, rightKeys, right);
} else {
return new JoinOp(fieldNames, columns, leftKeys, left, rightKeys, right, generateNullsOnLeft, generateNullsOnRight, false, nonEquiConditions);
}
}
use of herddb.model.planner.PlannerOp in project herddb by diennea.
the class CalcitePlanner method planInsert.
private PlannerOp planInsert(EnumerableTableModify dml, boolean returnValues, boolean upsert) {
final String tableSpace = dml.getTable().getQualifiedName().get(0);
final String tableName = dml.getTable().getQualifiedName().get(1);
DMLStatement statement = null;
if (dml.getInput() instanceof EnumerableProject) {
// fastest path for insert into TABLE(s,b,c) values(?,?,?)
EnumerableProject project = (EnumerableProject) dml.getInput();
if (project.getInput() instanceof EnumerableValues) {
EnumerableValues values = (EnumerableValues) project.getInput();
if (values.getTuples().size() == 1) {
final TableImpl tableImpl = (TableImpl) dml.getTable().unwrap(org.apache.calcite.schema.Table.class);
Table table = tableImpl.tableManager.getTable();
int index = 0;
List<RexNode> projects = project.getProjects();
List<CompiledSQLExpression> keyValueExpression = new ArrayList<>();
List<String> keyExpressionToColumn = new ArrayList<>();
List<CompiledSQLExpression> valuesExpressions = new ArrayList<>();
List<String> valuesColumns = new ArrayList<>();
boolean invalid = false;
for (Column column : table.getColumns()) {
CompiledSQLExpression exp = SQLExpressionCompiler.compileExpression(projects.get(index));
if (exp instanceof ConstantExpression || exp instanceof JdbcParameterExpression || exp instanceof TypedJdbcParameterExpression) {
boolean isAlwaysNull = (exp instanceof ConstantExpression) && ((ConstantExpression) exp).isNull();
if (!isAlwaysNull) {
if (table.isPrimaryKeyColumn(column.name)) {
keyExpressionToColumn.add(column.name);
keyValueExpression.add(exp);
}
valuesColumns.add(column.name);
valuesExpressions.add(exp);
}
index++;
} else {
invalid = true;
break;
}
}
if (!invalid) {
RecordFunction keyfunction;
if (keyValueExpression.isEmpty() && table.auto_increment) {
keyfunction = new AutoIncrementPrimaryKeyRecordFunction();
} else {
if (keyValueExpression.size() != table.primaryKey.length) {
throw new StatementExecutionException("you must set a value for the primary key (expressions=" + keyValueExpression.size() + ")");
}
keyfunction = new SQLRecordKeyFunction(keyExpressionToColumn, keyValueExpression, table);
}
RecordFunction valuesfunction = new SQLRecordFunction(valuesColumns, table, valuesExpressions);
statement = new InsertStatement(tableSpace, tableName, keyfunction, valuesfunction, upsert).setReturnValues(returnValues);
}
}
}
}
if (statement != null) {
return new SimpleInsertOp(statement);
}
PlannerOp input = convertRelNode(dml.getInput(), null, false, false);
try {
return new InsertOp(tableSpace, tableName, input, returnValues, upsert);
} catch (IllegalArgumentException err) {
throw new StatementExecutionException(err);
}
}
Aggregations