use of com.questdb.common.RecordColumnMetadata in project questdb by bluestreak01.
the class QueryHandler method resume.
@SuppressWarnings("ConstantConditions")
@Override
public void resume(IOContext context) throws IOException {
QueryHandlerContext ctx = localContext.get(context);
if (ctx == null || ctx.cursor == null) {
return;
}
final ChunkedResponse r = context.chunkedResponse();
final int columnCount = ctx.metadata.getColumnCount();
OUT: while (true) {
try {
SWITCH: switch(ctx.queryState) {
case QUERY_PREFIX:
if (ctx.noMeta) {
r.put('{').putQuoted("dataset").put(":[");
ctx.queryState = QUERY_RECORD_START;
break;
}
r.bookmark();
r.put('{').putQuoted("query").put(':').encodeUtf8AndQuote(ctx.query);
r.put(',').putQuoted("columns").put(':').put('[');
ctx.queryState = QUERY_METADATA;
ctx.columnIndex = 0;
// fall through
case QUERY_METADATA:
for (; ctx.columnIndex < columnCount; ctx.columnIndex++) {
RecordColumnMetadata column = ctx.metadata.getColumnQuick(ctx.columnIndex);
r.bookmark();
if (ctx.columnIndex > 0) {
r.put(',');
}
r.put('{').putQuoted("name").put(':').putQuoted(column.getName()).put(',').putQuoted("type").put(':').putQuoted(ColumnType.nameOf(column.getType()));
r.put('}');
}
ctx.queryState = QUERY_META_SUFFIX;
// fall through
case QUERY_META_SUFFIX:
r.bookmark();
r.put("],\"dataset\":[");
ctx.queryState = QUERY_RECORD_START;
// fall through
case QUERY_RECORD_START:
if (ctx.record == null) {
// check if cursor has any records
while (true) {
if (ctx.cursor.hasNext()) {
ctx.record = ctx.cursor.next();
ctx.count++;
if (ctx.fetchAll && ctx.count > ctx.stop) {
ctx.cancellationHandler.check();
continue;
}
if (ctx.count > ctx.skip) {
break;
}
} else {
ctx.queryState = QUERY_DATA_SUFFIX;
break SWITCH;
}
}
}
if (ctx.count > ctx.stop) {
ctx.queryState = QUERY_DATA_SUFFIX;
break;
}
r.bookmark();
if (ctx.count > ctx.skip + 1) {
r.put(',');
}
r.put('[');
ctx.queryState = QUERY_RECORD_COLUMNS;
ctx.columnIndex = 0;
// fall through
case QUERY_RECORD_COLUMNS:
for (; ctx.columnIndex < columnCount; ctx.columnIndex++) {
RecordColumnMetadata m = ctx.metadata.getColumnQuick(ctx.columnIndex);
r.bookmark();
if (ctx.columnIndex > 0) {
r.put(',');
}
putValue(r, m.getType(), ctx.record, ctx.columnIndex);
}
ctx.queryState = QUERY_RECORD_SUFFIX;
case QUERY_RECORD_SUFFIX:
r.bookmark();
r.put(']');
ctx.record = null;
ctx.queryState = QUERY_RECORD_START;
break;
case QUERY_DATA_SUFFIX:
sendDone(r, ctx);
break OUT;
default:
break OUT;
}
} catch (ResponseContentBufferTooSmallException ignored) {
if (r.resetToBookmark()) {
r.sendChunk();
} else {
// what we have here is out unit of data, column value or query
// is larger that response content buffer
// all we can do in this scenario is to log appropriately
// and disconnect socket
ctx.info().$("Response buffer is too small, state=").$(ctx.queryState).$();
throw DisconnectedChannelException.INSTANCE;
}
}
}
}
use of com.questdb.common.RecordColumnMetadata in project questdb by bluestreak01.
the class QueryFilterAnalyser method analyzeEquals0.
private boolean analyzeEquals0(AliasTranslator translator, IntrinsicModel model, ExprNode node, ExprNode a, ExprNode b, RecordMetadata m) throws ParserException {
if (Chars.equals(a.token, b.token)) {
node.intrinsicValue = IntrinsicValue.TRUE;
return true;
}
if (a.type == ExprNode.LITERAL && b.type == ExprNode.CONSTANT) {
if (isTimestamp(a)) {
CharSequence seq = quoteEraser.ofQuoted(b.token);
model.intersectIntervals(seq, 0, seq.length(), b.position);
node.intrinsicValue = IntrinsicValue.TRUE;
return true;
} else {
CharSequence column = translator.translateAlias(a.token);
int index = m.getColumnIndexQuiet(column);
if (index == -1) {
throw QueryError.invalidColumn(a.position, a.token);
}
RecordColumnMetadata meta = m.getColumnQuick(index);
switch(meta.getType()) {
case ColumnType.SYMBOL:
case ColumnType.STRING:
case ColumnType.LONG:
case ColumnType.INT:
if (meta.isIndexed()) {
// check if we are limited by preferred column
if (preferredKeyColumn != null && !Chars.equals(preferredKeyColumn, column)) {
return false;
}
boolean newColumn = true;
// check if we already have indexed column and it is of worse selectivity
if (model.keyColumn != null && (newColumn = !Chars.equals(model.keyColumn, column)) && meta.getBucketCount() <= m.getColumn(model.keyColumn).getBucketCount()) {
return false;
}
String value = Chars.equals("null", b.token) ? null : Chars.stripQuotes(b.token);
if (newColumn) {
model.keyColumn = column.toString();
model.keyValues.clear();
model.keyValuePositions.clear();
model.keyValues.add(value);
model.keyValuePositions.add(b.position);
for (int n = 0, k = keyNodes.size(); n < k; n++) {
keyNodes.getQuick(n).intrinsicValue = IntrinsicValue.UNDEFINED;
}
keyNodes.clear();
} else {
// otherwise invalidate entire model
if (model.keyValues.contains(value)) {
model.keyValues.clear();
model.keyValuePositions.clear();
model.keyValues.add(value);
model.keyValuePositions.add(b.position);
} else {
model.intrinsicValue = IntrinsicValue.FALSE;
return false;
}
}
keyNodes.add(node);
node.intrinsicValue = IntrinsicValue.TRUE;
return true;
}
// fall through
default:
return false;
}
}
}
return false;
}
use of com.questdb.common.RecordColumnMetadata in project questdb by bluestreak01.
the class QueryFilterAnalyser method analyzeNotEquals0.
private boolean analyzeNotEquals0(AliasTranslator translator, IntrinsicModel model, ExprNode node, ExprNode a, ExprNode b, RecordMetadata m) throws ParserException {
if (Chars.equals(a.token, b.token)) {
model.intrinsicValue = IntrinsicValue.FALSE;
return true;
}
if (a.type == ExprNode.LITERAL && b.type == ExprNode.CONSTANT) {
if (isTimestamp(a)) {
CharSequence seq = quoteEraser.ofQuoted(b.token);
model.subtractIntervals(seq, 0, seq.length(), b.position);
node.intrinsicValue = IntrinsicValue.TRUE;
return true;
} else {
String column = translator.translateAlias(a.token).toString();
int index = m.getColumnIndexQuiet(column);
if (index == -1) {
throw QueryError.invalidColumn(a.position, a.token);
}
RecordColumnMetadata meta = m.getColumnQuick(index);
switch(meta.getType()) {
case ColumnType.SYMBOL:
case ColumnType.STRING:
case ColumnType.LONG:
case ColumnType.INT:
if (meta.isIndexed()) {
// check if we are limited by preferred column
if (preferredKeyColumn != null && !preferredKeyColumn.equals(column)) {
return false;
}
keyExclNodes.add(node);
return false;
}
break;
default:
break;
}
}
}
return false;
}
use of com.questdb.common.RecordColumnMetadata in project questdb by bluestreak01.
the class QueryFilterAnalyser method analyzeInLambda.
private boolean analyzeInLambda(IntrinsicModel model, CharSequence col, RecordMetadata meta, ExprNode node) throws ParserException {
RecordColumnMetadata colMeta = meta.getColumn(col);
if (colMeta.isIndexed()) {
if (preferredKeyColumn != null && !col.equals(preferredKeyColumn)) {
return false;
}
if (node.rhs == null || node.rhs.type != ExprNode.LAMBDA) {
return false;
}
// check if we already have indexed column and it is of worse selectivity
if (model.keyColumn != null && (!Chars.equals(model.keyColumn, col)) && colMeta.getBucketCount() <= meta.getColumn(model.keyColumn).getBucketCount()) {
return false;
}
if ((col.equals(model.keyColumn) && model.keyValuesIsLambda) || node.paramCount > 2) {
throw ParserException.$(node.position, "Multiple lambda expressions not supported");
}
model.keyValues.clear();
model.keyValuePositions.clear();
model.keyValues.add(unquote(node.rhs.token));
model.keyValuePositions.add(node.position);
model.keyValuesIsLambda = true;
// revert previously processed nodes
for (int n = 0, k = keyNodes.size(); n < k; n++) {
keyNodes.getQuick(n).intrinsicValue = IntrinsicValue.UNDEFINED;
}
keyNodes.clear();
model.keyColumn = col;
keyNodes.add(node);
node.intrinsicValue = IntrinsicValue.TRUE;
return true;
}
return false;
}
use of com.questdb.common.RecordColumnMetadata in project questdb by bluestreak01.
the class QueryFilterAnalyser method analyzeListOfValues.
private boolean analyzeListOfValues(IntrinsicModel model, CharSequence col, RecordMetadata meta, ExprNode node) {
RecordColumnMetadata colMeta = meta.getColumn(col);
if (colMeta.isIndexed()) {
boolean newColumn = true;
if (preferredKeyColumn != null && !col.equals(preferredKeyColumn)) {
return false;
}
// check if we already have indexed column and it is of worse selectivity
if (model.keyColumn != null && (newColumn = !Chars.equals(model.keyColumn, col)) && colMeta.getBucketCount() <= meta.getColumn(model.keyColumn).getBucketCount()) {
return false;
}
int i = node.paramCount - 1;
tempKeys.clear();
tempPos.clear();
// if any of values is not an indexed constant - bail out
if (i == 1) {
if (node.rhs == null || node.rhs.type != ExprNode.CONSTANT) {
return false;
}
if (tempKeys.add(unquote(node.rhs.token))) {
tempPos.add(node.position);
}
} else {
for (i--; i > -1; i--) {
ExprNode c = node.args.getQuick(i);
if (c.type != ExprNode.CONSTANT) {
return false;
}
if (tempKeys.add(unquote(c.token))) {
tempPos.add(c.position);
}
}
}
// and reset intrinsic values on nodes associated with old column
if (newColumn) {
model.keyValues.clear();
model.keyValuePositions.clear();
model.keyValues.addAll(tempKeys);
model.keyValuePositions.addAll(tempPos);
for (int n = 0, k = keyNodes.size(); n < k; n++) {
keyNodes.getQuick(n).intrinsicValue = IntrinsicValue.UNDEFINED;
}
keyNodes.clear();
model.keyColumn = col;
keyNodes.add(node);
node.intrinsicValue = IntrinsicValue.TRUE;
return true;
} else if (!model.keyValuesIsLambda) {
// calculate overlap of values
replaceAllWithOverlap(model);
keyNodes.add(node);
node.intrinsicValue = IntrinsicValue.TRUE;
return true;
}
}
return false;
}
Aggregations