use of com.questdb.griffin.common.ExprNode in project questdb by bluestreak01.
the class SqlLexerOptimiser method moveWhereInsideSubQueries.
private void moveWhereInsideSubQueries(QueryModel model) throws ParserException {
model.getParsedWhere().clear();
final ObjList<ExprNode> nodes = model.parseWhereClause();
model.setWhereClause(null);
final int n = nodes.size();
if (n > 0) {
for (int i = 0; i < n; i++) {
final ExprNode node = nodes.getQuick(i);
// collect table references this where clause element
literalCollectorAIndexes.clear();
literalCollectorANames.clear();
literalCollector.withModel(model);
literalCollector.resetNullCount();
traversalAlgo.traverse(node, literalCollector.lhs());
// at this point we must not have constant conditions in where clause
assert literalCollectorAIndexes.size() > 0;
// by now all where clause must reference single table only and all column references have to be valid
// they would have been rewritten and validated as join analysis stage
final int tableIndex = literalCollectorAIndexes.getQuick(0);
final QueryModel parent = model.getJoinModels().getQuick(tableIndex);
final QueryModel nested = parent.getNestedModel();
if (nested == null) {
// there is no nested model for this table, keep where clause element with this model
addWhereNode(parent, node);
} else {
try {
traversalAlgo.traverse(node, literalCheckingVisitor.of(nested.getColumnNameTypeMap()));
// go ahead and rewrite expression
traversalAlgo.traverse(node, literalRewritingVisitor.of(nested.getAliasToColumnMap()));
// whenever nested model has explicitly defined columns it must also
// have its owen nested model, where we assign new "where" clauses
addWhereNode(nested, node);
} catch (NonLiteralException ignore) {
// keep node where it is
addWhereNode(parent, node);
}
}
}
model.getParsedWhere().clear();
}
if (model.getNestedModel() != null) {
moveWhereInsideSubQueries(model.getNestedModel());
}
ObjList<QueryModel> joinModels = model.getJoinModels();
for (int i = 0, m = joinModels.size(); i < m; i++) {
QueryModel nested = joinModels.getQuick(i);
if (nested != model) {
moveWhereInsideSubQueries(nested);
}
}
}
use of com.questdb.griffin.common.ExprNode in project questdb by bluestreak01.
the class SqlLexerOptimiser method resolveJoinColumns.
private void resolveJoinColumns(QueryModel model) throws ParserException {
ObjList<QueryModel> joinModels = model.getJoinModels();
final int size = joinModels.size();
final CharSequence modelAlias = setAndGetModelAlias(model);
// collect own alias
collectAlias(model, 0, model);
if (size > 1) {
for (int i = 1; i < size; i++) {
final QueryModel jm = joinModels.getQuick(i);
final ObjList<ExprNode> jc = jm.getJoinColumns();
final int joinColumnsSize = jc.size();
if (joinColumnsSize > 0) {
final CharSequence jmAlias = setAndGetModelAlias(jm);
ExprNode joinCriteria = jm.getJoinCriteria();
for (int j = 0; j < joinColumnsSize; j++) {
ExprNode node = jc.getQuick(j);
ExprNode eq = makeOperation("=", makeModelAlias(modelAlias, node), makeModelAlias(jmAlias, node));
if (joinCriteria == null) {
joinCriteria = eq;
} else {
joinCriteria = makeOperation("and", joinCriteria, eq);
}
}
jm.setJoinCriteria(joinCriteria);
}
resolveJoinColumns(jm);
collectAlias(model, i, jm);
}
}
if (model.getNestedModel() != null) {
resolveJoinColumns(model.getNestedModel());
}
}
use of com.questdb.griffin.common.ExprNode in project questdb by bluestreak01.
the class SqlLexerOptimiser method rewriteCase.
private ExprNode rewriteCase(ExprNode node) throws ParserException {
traversalAlgo.traverse(node, node1 -> {
if (node1.type == ExprNode.FUNCTION && Chars.equals("case", node1.token)) {
tempExprNodes.clear();
ExprNode literal = null;
ExprNode elseExpr;
boolean convertToSwitch = true;
final int paramCount = node1.paramCount;
final int lim;
if ((paramCount & 1) == 1) {
elseExpr = node1.args.getQuick(0);
lim = 0;
} else {
elseExpr = null;
lim = -1;
}
for (int i = paramCount - 1; i > lim; i--) {
if ((i & 1) == 1) {
// this is "then" clause, copy it as as
tempExprNodes.add(node1.args.getQuick(i));
continue;
}
ExprNode where = node1.args.getQuick(i);
if (where.type == ExprNode.OPERATION && where.token.charAt(0) == '=') {
ExprNode thisConstant;
ExprNode thisLiteral;
if (where.lhs.type == ExprNode.CONSTANT && where.rhs.type == ExprNode.LITERAL) {
thisConstant = where.lhs;
thisLiteral = where.rhs;
} else if (where.lhs.type == ExprNode.LITERAL && where.rhs.type == ExprNode.CONSTANT) {
thisConstant = where.rhs;
thisLiteral = where.lhs;
} else {
convertToSwitch = false;
// not supported
break;
}
if (literal == null) {
literal = thisLiteral;
tempExprNodes.add(thisConstant);
} else if (Chars.equals(literal.token, thisLiteral.token)) {
tempExprNodes.add(thisConstant);
} else {
convertToSwitch = false;
// not supported
break;
}
} else {
convertToSwitch = false;
// not supported
break;
}
}
if (convertToSwitch) {
node1.token = "switch";
node1.args.clear();
node1.args.add(literal);
node1.args.add(elseExpr);
node1.args.addAll(tempExprNodes);
}
}
});
return node;
}
use of com.questdb.griffin.common.ExprNode in project questdb by bluestreak01.
the class SqlLexerOptimiser method parseSelectClause.
private void parseSelectClause(QueryModel model) throws ParserException {
while (true) {
CharSequence tok = tok("column");
final ExprNode expr;
// this is quite dramatic workaround for lexer
// because lexer tokenizes expressions, for something like 'a.*' it would
// produce two tokens, 'a.' and '*'
// we should be able to tell if they are together or there is whitespace between them
// for example "a. *' would also produce two token and it must be a error
// to determine if wildcard is correct we would rely on token position
final char last = tok.charAt(tok.length() - 1);
if (last == '*') {
expr = nextLiteral(lexer.toImmutable(tok), lexer.position());
} else if (last == '.') {
// stash 'a.' token
final int pos = lexer.position() + tok.length();
Lexer2.NameAssembler nameAssembler = lexer.getNameAssembler();
nameAssembler.put(tok);
tok = tok("*");
if (Chars.equals(tok, '*')) {
if (lexer.position() > pos) {
throw ParserException.$(pos, "whitespace is not allowed");
}
nameAssembler.put('*');
expr = nextLiteral(nameAssembler.toImmutable(), lexer.position());
} else {
throw ParserException.$(pos, "'*' expected");
}
} else {
lexer.unparse();
expr = expr();
if (expr == null) {
throw ParserException.$(lexer.position(), "missing expression");
}
}
CharSequence alias;
tok = tok("',', 'from', 'over' or literal");
if (columnAliasStop.excludes(tok)) {
if (Chars.indexOf(tok, '.') != -1) {
throw ParserException.$(lexer.position(), "'.' is not allowed here");
}
alias = lexer.toImmutable(tok);
tok = tok("',', 'from' or 'over'");
} else {
alias = createColumnAlias(expr, model);
}
if (Chars.equals(tok, "over")) {
// analytic
expectTok('(');
AnalyticColumn col = analyticColumnPool.next().of(alias, expr);
tok = tok("'");
if (Chars.equals(tok, "partition")) {
expectTok("by");
ObjList<ExprNode> partitionBy = col.getPartitionBy();
do {
partitionBy.add(expectLiteral());
tok = tok("'order' or ')'");
} while (Chars.equals(tok, ','));
}
if (Chars.equals(tok, "order")) {
expectTok("by");
do {
ExprNode e = expectLiteral();
tok = tok("'asc' or 'desc'");
if (Chars.equalsIgnoreCase(tok, "desc")) {
col.addOrderBy(e, QueryModel.ORDER_DIRECTION_DESCENDING);
tok = tok("',' or ')'");
} else {
col.addOrderBy(e, QueryModel.ORDER_DIRECTION_ASCENDING);
if (Chars.equalsIgnoreCase(tok, "asc")) {
tok = tok("',' or ')'");
}
}
} while (Chars.equals(tok, ','));
}
expectTok(tok, lexer.position(), ')');
model.addColumn(col);
tok = tok("'from' or ','");
} else {
model.addColumn(queryColumnPool.next().of(alias, expr));
}
if (Chars.equals(tok, "from")) {
break;
}
if (!Chars.equals(tok, ',')) {
throw err("',' or 'from' expected");
}
}
}
use of com.questdb.griffin.common.ExprNode in project questdb by bluestreak01.
the class QueryModel method getTableMetadata.
public RecordMetadata getTableMetadata(CairoEngine engine, FlyweightCharSequence charSequence) throws ParserException {
// table name must not contain quotes by now
ExprNode readerNode = getTableName();
int lo = 0;
int hi = readerNode.token.length();
if (Chars.startsWith(readerNode.token, NO_ROWID_MARKER)) {
lo += NO_ROWID_MARKER.length();
}
if (lo == hi) {
throw ParserException.$(readerNode.position, "come on, where is table name?");
}
int status = engine.getStatus(readerNode.token, lo, hi);
if (status == TableUtils.TABLE_DOES_NOT_EXIST) {
throw ParserException.$(readerNode.position, "table does not exist");
}
if (status == TableUtils.TABLE_RESERVED) {
throw ParserException.$(readerNode.position, "table directory is of unknown format");
}
try (TableReader r = engine.getReader(charSequence.of(readerNode.token, lo, hi - lo))) {
return r.getMetadata();
} catch (EntryLockedException e) {
throw ParserException.position(readerNode.position).put("table is locked: ").put(charSequence);
} catch (CairoException e) {
throw ParserException.position(readerNode.position).put(e);
}
}
Aggregations