未验证 提交 bd4da5b8 编写于 作者: V Vlad Ilyushchenko 提交者: GitHub

chore: excluding test function factories from production run. Added handling...

chore: excluding test function factories from production run. Added handling of unexpected exceptions. Fixed #367 (#392)
上级 359601fd
...@@ -949,6 +949,11 @@ public class PropServerConfiguration implements ServerConfiguration { ...@@ -949,6 +949,11 @@ public class PropServerConfiguration implements ServerConfiguration {
return indexValueBlockSize; return indexValueBlockSize;
} }
@Override
public boolean enableTestFactories() {
return false;
}
@Override @Override
public int getDoubleToStrCastScale() { public int getDoubleToStrCastScale() {
return doubleToStrCastScale; return doubleToStrCastScale;
......
...@@ -161,4 +161,6 @@ public interface CairoConfiguration { ...@@ -161,4 +161,6 @@ public interface CairoConfiguration {
int getGroupByPoolCapacity(); int getGroupByPoolCapacity();
int getGroupByMapCapacity(); int getGroupByMapCapacity();
boolean enableTestFactories();
} }
...@@ -24,7 +24,9 @@ ...@@ -24,7 +24,9 @@
package io.questdb.cairo; package io.questdb.cairo;
public class CairoError extends Error { import io.questdb.std.FlyweightMessageContainer;
public class CairoError extends Error implements FlyweightMessageContainer {
public CairoError(Throwable cause) { public CairoError(Throwable cause) {
super(cause); super(cause);
} }
...@@ -32,4 +34,9 @@ public class CairoError extends Error { ...@@ -32,4 +34,9 @@ public class CairoError extends Error {
public CairoError(String message) { public CairoError(String message) {
super(message); super(message);
} }
@Override
public CharSequence getFlyweightMessage() {
return getMessage();
}
} }
...@@ -24,12 +24,13 @@ ...@@ -24,12 +24,13 @@
package io.questdb.cairo; package io.questdb.cairo;
import io.questdb.std.FlyweightMessageContainer;
import io.questdb.std.Sinkable; import io.questdb.std.Sinkable;
import io.questdb.std.ThreadLocal; import io.questdb.std.ThreadLocal;
import io.questdb.std.str.CharSink; import io.questdb.std.str.CharSink;
import io.questdb.std.str.StringSink; import io.questdb.std.str.StringSink;
public class CairoException extends RuntimeException implements Sinkable { public class CairoException extends RuntimeException implements Sinkable, FlyweightMessageContainer {
private static final ThreadLocal<CairoException> tlException = new ThreadLocal<>(CairoException::new); private static final ThreadLocal<CairoException> tlException = new ThreadLocal<>(CairoException::new);
protected final StringSink message = new StringSink(); protected final StringSink message = new StringSink();
private int errno; private int errno;
...@@ -63,6 +64,7 @@ public class CairoException extends RuntimeException implements Sinkable { ...@@ -63,6 +64,7 @@ public class CairoException extends RuntimeException implements Sinkable {
return this; return this;
} }
@Override
public CharSequence getFlyweightMessage() { public CharSequence getFlyweightMessage() {
return message; return message;
} }
......
...@@ -52,6 +52,11 @@ public class DefaultCairoConfiguration implements CairoConfiguration { ...@@ -52,6 +52,11 @@ public class DefaultCairoConfiguration implements CairoConfiguration {
return 16; return 16;
} }
@Override
public boolean enableTestFactories() {
return true;
}
@Override @Override
public int getCreateAsSelectRetryCount() { public int getCreateAsSelectRetryCount() {
return 5; return 5;
......
...@@ -28,14 +28,7 @@ import io.questdb.cairo.CairoSecurityContext; ...@@ -28,14 +28,7 @@ import io.questdb.cairo.CairoSecurityContext;
import io.questdb.cairo.security.CairoSecurityContextImpl; import io.questdb.cairo.security.CairoSecurityContextImpl;
import io.questdb.log.Log; import io.questdb.log.Log;
import io.questdb.log.LogFactory; import io.questdb.log.LogFactory;
import io.questdb.network.IOContext; import io.questdb.network.*;
import io.questdb.network.IODispatcher;
import io.questdb.network.IOOperation;
import io.questdb.network.Net;
import io.questdb.network.NetworkFacade;
import io.questdb.network.PeerDisconnectedException;
import io.questdb.network.PeerIsSlowToReadException;
import io.questdb.network.ServerDisconnectException;
import io.questdb.std.Chars; import io.questdb.std.Chars;
import io.questdb.std.Mutable; import io.questdb.std.Mutable;
import io.questdb.std.ObjectPool; import io.questdb.std.ObjectPool;
...@@ -177,7 +170,7 @@ public class HttpConnectionContext implements IOContext, Locality, Mutable { ...@@ -177,7 +170,7 @@ public class HttpConnectionContext implements IOContext, Locality, Mutable {
return responseSink.getSimple(); return responseSink.getSimple();
} }
private void completeRequest(HttpRequestProcessor processor) throws PeerDisconnectedException, PeerIsSlowToReadException { private void completeRequest(HttpRequestProcessor processor) throws PeerDisconnectedException, PeerIsSlowToReadException, ServerDisconnectException {
LOG.debug().$("complete [fd=").$(fd).$(']').$(); LOG.debug().$("complete [fd=").$(fd).$(']').$();
processor.onRequestComplete(this); processor.onRequestComplete(this);
} }
......
...@@ -24,12 +24,13 @@ ...@@ -24,12 +24,13 @@
package io.questdb.cutlass.http; package io.questdb.cutlass.http;
import io.questdb.std.FlyweightMessageContainer;
import io.questdb.std.Sinkable; import io.questdb.std.Sinkable;
import io.questdb.std.ThreadLocal; import io.questdb.std.ThreadLocal;
import io.questdb.std.str.CharSink; import io.questdb.std.str.CharSink;
import io.questdb.std.str.StringSink; import io.questdb.std.str.StringSink;
public class HttpException extends RuntimeException implements Sinkable { public class HttpException extends RuntimeException implements Sinkable, FlyweightMessageContainer {
private static final ThreadLocal<HttpException> tlException = new ThreadLocal<>(HttpException::new); private static final ThreadLocal<HttpException> tlException = new ThreadLocal<>(HttpException::new);
private final StringSink message = new StringSink(); private final StringSink message = new StringSink();
...@@ -41,7 +42,7 @@ public class HttpException extends RuntimeException implements Sinkable { ...@@ -41,7 +42,7 @@ public class HttpException extends RuntimeException implements Sinkable {
} }
public CharSequence getFlyweightMessage() { public CharSequence getFlyweightMessage() {
return tlException.get().getFlyweightMessage(); return message;
} }
@Override @Override
......
...@@ -31,7 +31,7 @@ import io.questdb.network.ServerDisconnectException; ...@@ -31,7 +31,7 @@ import io.questdb.network.ServerDisconnectException;
public interface HttpRequestProcessor { public interface HttpRequestProcessor {
void onHeadersReady(HttpConnectionContext context); void onHeadersReady(HttpConnectionContext context);
void onRequestComplete(HttpConnectionContext context) throws PeerDisconnectedException, PeerIsSlowToReadException; void onRequestComplete(HttpConnectionContext context) throws PeerDisconnectedException, PeerIsSlowToReadException, ServerDisconnectException;
default void resumeRecv(HttpConnectionContext context) { default void resumeRecv(HttpConnectionContext context) {
} }
......
...@@ -24,10 +24,6 @@ ...@@ -24,10 +24,6 @@
package io.questdb.cutlass.http.processors; package io.questdb.cutlass.http.processors;
import java.io.Closeable;
import org.jetbrains.annotations.Nullable;
import io.questdb.MessageBus; import io.questdb.MessageBus;
import io.questdb.cairo.CairoEngine; import io.questdb.cairo.CairoEngine;
import io.questdb.cairo.CairoError; import io.questdb.cairo.CairoError;
...@@ -36,11 +32,7 @@ import io.questdb.cairo.sql.InsertMethod; ...@@ -36,11 +32,7 @@ import io.questdb.cairo.sql.InsertMethod;
import io.questdb.cairo.sql.InsertStatement; import io.questdb.cairo.sql.InsertStatement;
import io.questdb.cairo.sql.ReaderOutOfDateException; import io.questdb.cairo.sql.ReaderOutOfDateException;
import io.questdb.cairo.sql.RecordCursorFactory; import io.questdb.cairo.sql.RecordCursorFactory;
import io.questdb.cutlass.http.HttpChunkedResponseSocket; import io.questdb.cutlass.http.*;
import io.questdb.cutlass.http.HttpConnectionContext;
import io.questdb.cutlass.http.HttpRequestHeader;
import io.questdb.cutlass.http.HttpRequestProcessor;
import io.questdb.cutlass.http.LocalValue;
import io.questdb.cutlass.text.Utf8Exception; import io.questdb.cutlass.text.Utf8Exception;
import io.questdb.griffin.CompiledQuery; import io.questdb.griffin.CompiledQuery;
import io.questdb.griffin.SqlCompiler; import io.questdb.griffin.SqlCompiler;
...@@ -48,17 +40,12 @@ import io.questdb.griffin.SqlException; ...@@ -48,17 +40,12 @@ import io.questdb.griffin.SqlException;
import io.questdb.griffin.SqlExecutionContextImpl; import io.questdb.griffin.SqlExecutionContextImpl;
import io.questdb.log.Log; import io.questdb.log.Log;
import io.questdb.log.LogFactory; import io.questdb.log.LogFactory;
import io.questdb.network.IOOperation; import io.questdb.network.*;
import io.questdb.network.NoSpaceLeftInResponseBufferException; import io.questdb.std.*;
import io.questdb.network.PeerDisconnectedException;
import io.questdb.network.PeerIsSlowToReadException;
import io.questdb.std.Chars;
import io.questdb.std.Misc;
import io.questdb.std.NanosecondClock;
import io.questdb.std.Numbers;
import io.questdb.std.NumericException;
import io.questdb.std.ObjList;
import io.questdb.std.str.DirectByteCharSequence; import io.questdb.std.str.DirectByteCharSequence;
import org.jetbrains.annotations.Nullable;
import java.io.Closeable;
public class JsonQueryProcessor implements HttpRequestProcessor, Closeable { public class JsonQueryProcessor implements HttpRequestProcessor, Closeable {
private static final LocalValue<JsonQueryProcessorState> LV = new LocalValue<>(); private static final LocalValue<JsonQueryProcessorState> LV = new LocalValue<>();
...@@ -102,7 +89,7 @@ public class JsonQueryProcessor implements HttpRequestProcessor, Closeable { ...@@ -102,7 +89,7 @@ public class JsonQueryProcessor implements HttpRequestProcessor, Closeable {
Misc.free(compiler); Misc.free(compiler);
} }
public void execute0(JsonQueryProcessorState state) throws PeerDisconnectedException, PeerIsSlowToReadException { public void execute0(JsonQueryProcessorState state) throws PeerDisconnectedException, PeerIsSlowToReadException, ServerDisconnectException {
state.startExecutionTimer(); state.startExecutionTimer();
final HttpConnectionContext context = state.getHttpConnectionContext(); final HttpConnectionContext context = state.getHttpConnectionContext();
// do not set random for new request to avoid copying random from previous request into next one // do not set random for new request to avoid copying random from previous request into next one
...@@ -129,9 +116,12 @@ public class JsonQueryProcessor implements HttpRequestProcessor, Closeable { ...@@ -129,9 +116,12 @@ public class JsonQueryProcessor implements HttpRequestProcessor, Closeable {
} catch (SqlException e) { } catch (SqlException e) {
syntaxError(context.getChunkedResponseSocket(), e, state, configuration.getKeepAliveHeader()); syntaxError(context.getChunkedResponseSocket(), e, state, configuration.getKeepAliveHeader());
readyForNextRequest(context); readyForNextRequest(context);
} catch (CairoException | CairoError e) { } catch (CairoError | CairoException e) {
internalError(context.getChunkedResponseSocket(), e, state); internalError(context.getChunkedResponseSocket(), e.getFlyweightMessage(), e, state);
readyForNextRequest(context); readyForNextRequest(context);
} catch (Throwable e) {
LOG.error().$("Uh-oh. Error!").$(e).$();
throw ServerDisconnectException.INSTANCE;
} }
} }
...@@ -142,7 +132,7 @@ public class JsonQueryProcessor implements HttpRequestProcessor, Closeable { ...@@ -142,7 +132,7 @@ public class JsonQueryProcessor implements HttpRequestProcessor, Closeable {
@Override @Override
public void onRequestComplete( public void onRequestComplete(
HttpConnectionContext context HttpConnectionContext context
) throws PeerDisconnectedException, PeerIsSlowToReadException { ) throws PeerDisconnectedException, PeerIsSlowToReadException, ServerDisconnectException {
JsonQueryProcessorState state = LV.get(context); JsonQueryProcessorState state = LV.get(context);
if (state == null) { if (state == null) {
LV.set(context, state = new JsonQueryProcessorState( LV.set(context, state = new JsonQueryProcessorState(
...@@ -360,11 +350,12 @@ public class JsonQueryProcessor implements HttpRequestProcessor, Closeable { ...@@ -360,11 +350,12 @@ public class JsonQueryProcessor implements HttpRequestProcessor, Closeable {
private void internalError( private void internalError(
HttpChunkedResponseSocket socket, HttpChunkedResponseSocket socket,
CharSequence message,
Throwable e, Throwable e,
JsonQueryProcessorState state JsonQueryProcessorState state
) throws PeerDisconnectedException, PeerIsSlowToReadException { ) throws PeerDisconnectedException, PeerIsSlowToReadException {
state.error().$("Server error executing query ").utf8(state.getQuery()).$(e).$(); state.error().$("internal error [q=`").utf8(state.getQuery()).$("`, ex=").$(e).$();
sendException(socket, 0, e.getMessage(), 500, state.getQuery(), configuration.getKeepAliveHeader()); sendException(socket, 0, message, 500, state.getQuery(), configuration.getKeepAliveHeader());
} }
private boolean parseUrl( private boolean parseUrl(
......
...@@ -24,9 +24,7 @@ ...@@ -24,9 +24,7 @@
package io.questdb.cutlass.http.processors; package io.questdb.cutlass.http.processors;
import io.questdb.cairo.CairoEngine; import io.questdb.cairo.*;
import io.questdb.cairo.ColumnType;
import io.questdb.cairo.PartitionBy;
import io.questdb.cairo.sql.RecordMetadata; import io.questdb.cairo.sql.RecordMetadata;
import io.questdb.cutlass.http.*; import io.questdb.cutlass.http.*;
import io.questdb.cutlass.text.Atomicity; import io.questdb.cutlass.text.Atomicity;
...@@ -35,10 +33,7 @@ import io.questdb.cutlass.text.TextLoader; ...@@ -35,10 +33,7 @@ import io.questdb.cutlass.text.TextLoader;
import io.questdb.log.Log; import io.questdb.log.Log;
import io.questdb.log.LogFactory; import io.questdb.log.LogFactory;
import io.questdb.network.*; import io.questdb.network.*;
import io.questdb.std.CharSequenceIntHashMap; import io.questdb.std.*;
import io.questdb.std.Chars;
import io.questdb.std.LongList;
import io.questdb.std.Misc;
import io.questdb.std.str.CharSink; import io.questdb.std.str.CharSink;
import java.io.Closeable; import java.io.Closeable;
...@@ -264,7 +259,7 @@ public class TextImportProcessor implements HttpRequestProcessor, HttpMultipartC ...@@ -264,7 +259,7 @@ public class TextImportProcessor implements HttpRequestProcessor, HttpMultipartC
transientState.analysed = true; transientState.analysed = true;
transientState.textLoader.setState(TextLoader.LOAD_DATA); transientState.textLoader.setState(TextLoader.LOAD_DATA);
} }
} catch (TextException e) { } catch (TextException | CairoException | CairoError e) {
handleTextException(e); handleTextException(e);
} }
} }
...@@ -338,7 +333,7 @@ public class TextImportProcessor implements HttpRequestProcessor, HttpMultipartC ...@@ -338,7 +333,7 @@ public class TextImportProcessor implements HttpRequestProcessor, HttpMultipartC
if (transientState.messagePart == MESSAGE_DATA) { if (transientState.messagePart == MESSAGE_DATA) {
sendResponse(transientContext); sendResponse(transientContext);
} }
} catch (TextException e) { } catch (TextException | CairoException | CairoError e) {
handleTextException(e); handleTextException(e);
} }
} }
...@@ -398,7 +393,7 @@ public class TextImportProcessor implements HttpRequestProcessor, HttpMultipartC ...@@ -398,7 +393,7 @@ public class TextImportProcessor implements HttpRequestProcessor, HttpMultipartC
state.clear(); state.clear();
} }
private void handleTextException(TextException e) private void handleTextException(FlyweightMessageContainer e)
throws PeerDisconnectedException, PeerIsSlowToReadException, ServerDisconnectException { throws PeerDisconnectedException, PeerIsSlowToReadException, ServerDisconnectException {
sendError(transientContext, e.getFlyweightMessage(), Chars.equalsNc("json", transientContext.getRequestHeader().getUrlParam("fmt"))); sendError(transientContext, e.getFlyweightMessage(), Chars.equalsNc("json", transientContext.getRequestHeader().getUrlParam("fmt")));
throw ServerDisconnectException.INSTANCE; throw ServerDisconnectException.INSTANCE;
......
...@@ -24,12 +24,13 @@ ...@@ -24,12 +24,13 @@
package io.questdb.cutlass.json; package io.questdb.cutlass.json;
import io.questdb.std.FlyweightMessageContainer;
import io.questdb.std.Sinkable; import io.questdb.std.Sinkable;
import io.questdb.std.ThreadLocal; import io.questdb.std.ThreadLocal;
import io.questdb.std.str.CharSink; import io.questdb.std.str.CharSink;
import io.questdb.std.str.StringSink; import io.questdb.std.str.StringSink;
public class JsonException extends Exception implements Sinkable { public class JsonException extends Exception implements Sinkable, FlyweightMessageContainer {
private static final ThreadLocal<JsonException> tlException = new ThreadLocal<>(JsonException::new); private static final ThreadLocal<JsonException> tlException = new ThreadLocal<>(JsonException::new);
private final StringSink message = new StringSink(); private final StringSink message = new StringSink();
private int position; private int position;
...@@ -45,6 +46,7 @@ public class JsonException extends Exception implements Sinkable { ...@@ -45,6 +46,7 @@ public class JsonException extends Exception implements Sinkable {
return ex; return ex;
} }
@Override
public CharSequence getFlyweightMessage() { public CharSequence getFlyweightMessage() {
return message; return message;
} }
......
...@@ -24,13 +24,14 @@ ...@@ -24,13 +24,14 @@
package io.questdb.cutlass.text; package io.questdb.cutlass.text;
import io.questdb.std.FlyweightMessageContainer;
import io.questdb.std.Numbers; import io.questdb.std.Numbers;
import io.questdb.std.Sinkable; import io.questdb.std.Sinkable;
import io.questdb.std.ThreadLocal; import io.questdb.std.ThreadLocal;
import io.questdb.std.str.CharSink; import io.questdb.std.str.CharSink;
import io.questdb.std.str.StringSink; import io.questdb.std.str.StringSink;
public class TextException extends Exception implements Sinkable { public class TextException extends Exception implements Sinkable, FlyweightMessageContainer {
private static final ThreadLocal<TextException> tlException = new ThreadLocal<>(TextException::new); private static final ThreadLocal<TextException> tlException = new ThreadLocal<>(TextException::new);
private final StringSink message = new StringSink(); private final StringSink message = new StringSink();
...@@ -42,6 +43,7 @@ public class TextException extends Exception implements Sinkable { ...@@ -42,6 +43,7 @@ public class TextException extends Exception implements Sinkable {
return te; return te;
} }
@Override
public CharSequence getFlyweightMessage() { public CharSequence getFlyweightMessage() {
return message; return message;
} }
......
...@@ -81,7 +81,7 @@ public class FunctionParser implements PostOrderTreeTraversalAlgo.Visitor { ...@@ -81,7 +81,7 @@ public class FunctionParser implements PostOrderTreeTraversalAlgo.Visitor {
public FunctionParser(CairoConfiguration configuration, Iterable<FunctionFactory> functionFactories) { public FunctionParser(CairoConfiguration configuration, Iterable<FunctionFactory> functionFactories) {
this.configuration = configuration; this.configuration = configuration;
loadFunctionFactories(functionFactories); loadFunctionFactories(functionFactories, configuration.enableTestFactories());
} }
public static int getArgType(char c) { public static int getArgType(char c) {
...@@ -204,14 +204,14 @@ public class FunctionParser implements PostOrderTreeTraversalAlgo.Visitor { ...@@ -204,14 +204,14 @@ public class FunctionParser implements PostOrderTreeTraversalAlgo.Visitor {
return ex; return ex;
} }
private static SqlException invalidArgument(CharSequence message, ExpressionNode node, ObjList<Function> args, CharSequence expected, int offset, int count) { private static SqlException invalidArgument(ExpressionNode node, ObjList<Function> args, CharSequence expected, int offset, int count) {
SqlException ex = SqlException.position(node.position); SqlException ex = SqlException.position(node.position);
ex.put(message); ex.put("unexpected argument for function: ");
ex.put(node.token); ex.put(node.token);
ex.put(". expected args: "); ex.put(". expected args: ");
ex.put('('); ex.put('(');
if (expected != null) { if (expected != null) {
for (int i = 0, n = count; i < n; i++) { for (int i = 0; i < count; i++) {
if (i > 0) { if (i > 0) {
ex.put(','); ex.put(',');
} }
...@@ -670,9 +670,9 @@ public class FunctionParser implements PostOrderTreeTraversalAlgo.Visitor { ...@@ -670,9 +670,9 @@ public class FunctionParser implements PostOrderTreeTraversalAlgo.Visitor {
if (candidateSignature != null) { if (candidateSignature != null) {
final int sigArgOffset = candidateSignature.indexOf('(') + 1; final int sigArgOffset = candidateSignature.indexOf('(') + 1;
int sigArgCount = candidateSignature.length() - 1 - sigArgOffset; int sigArgCount = candidateSignature.length() - 1 - sigArgOffset;
throw invalidArgument("unexpected argument for function: ", node, args, candidateSignature, sigArgOffset, sigArgCount); throw invalidArgument(node, args, candidateSignature, sigArgOffset, sigArgCount);
} else { } else {
throw invalidArgument("unexpected argument for function: ", node, args, "", 0, 0); throw invalidArgument(node, args, "", 0, 0);
} }
} }
...@@ -815,41 +815,43 @@ public class FunctionParser implements PostOrderTreeTraversalAlgo.Visitor { ...@@ -815,41 +815,43 @@ public class FunctionParser implements PostOrderTreeTraversalAlgo.Visitor {
addFactoryToList(extraList, name, factory); addFactoryToList(extraList, name, factory);
} }
private void loadFunctionFactories(Iterable<FunctionFactory> functionFactories) { private void loadFunctionFactories(Iterable<FunctionFactory> functionFactories, boolean enableTestFactories) {
LOG.info().$("loading functions [test=").$(enableTestFactories).$(']').$();
for (FunctionFactory factory : functionFactories) { for (FunctionFactory factory : functionFactories) {
if (!factory.getClass().getName().contains("test") || enableTestFactories) {
final String sig = factory.getSignature();
final int openBraceIndex;
try {
openBraceIndex = validateSignatureAndGetNameSeparator(sig);
} catch (SqlException e) {
LOG.error().$((Sinkable) e).$(" [signature=").$(factory.getSignature()).$(",class=").$(factory.getClass().getName()).$(']').$();
continue;
}
final String sig = factory.getSignature(); final String name = sig.substring(0, openBraceIndex);
final int openBraceIndex; addFactoryToList(factories, name, factory);
try {
openBraceIndex = validateSignatureAndGetNameSeparator(sig); // Add != counterparts to equality function factories
} catch (SqlException e) { if (factory instanceof AbstractBooleanFunctionFactory) {
LOG.error().$((Sinkable) e).$(" [signature=").$(factory.getSignature()).$(",class=").$(factory.getClass().getName()).$(']').$(); switch (name) {
continue; case "=":
} addFactory(booleanFactories, "!=", factory);
break;
final String name = sig.substring(0, openBraceIndex); case "<":
addFactoryToList(factories, name, factory); // `a < b` == `a >= b`
addFactory(booleanFactories, ">=", factory);
// Add != counterparts to equality function factories if (sig.charAt(2) == sig.charAt(3)) {
if (factory instanceof AbstractBooleanFunctionFactory) { // `a < b` == `b > a`
switch (name) { addFactory(commutativeBooleanFactories, ">", factory);
case "=": // `a < b` == `b > a` == `b <= a`
addFactory(booleanFactories, "!=", factory); addFactory(booleanFactories, "<=", factory);
break; addFactory(commutativeBooleanFactories, "<=", factory);
case "<": }
// `a < b` == `a >= b` break;
addFactory(booleanFactories, ">=", factory); }
if (sig.charAt(2) == sig.charAt(3)) { } else if (factory.isGroupBy()) {
// `a < b` == `b > a` groupByFunctionNames.add(name);
addFactory(commutativeBooleanFactories, ">", factory);
// `a < b` == `b > a` == `b <= a`
addFactory(booleanFactories, "<=", factory);
addFactory(commutativeBooleanFactories, "<=", factory);
}
break;
} }
} else if (factory.isGroupBy()) {
groupByFunctionNames.add(name);
} }
} }
} }
......
...@@ -25,12 +25,13 @@ ...@@ -25,12 +25,13 @@
package io.questdb.griffin; package io.questdb.griffin;
import io.questdb.cairo.ColumnType; import io.questdb.cairo.ColumnType;
import io.questdb.std.FlyweightMessageContainer;
import io.questdb.std.Sinkable; import io.questdb.std.Sinkable;
import io.questdb.std.ThreadLocal; import io.questdb.std.ThreadLocal;
import io.questdb.std.str.CharSink; import io.questdb.std.str.CharSink;
import io.questdb.std.str.StringSink; import io.questdb.std.str.StringSink;
public class SqlException extends Exception implements Sinkable { public class SqlException extends Exception implements Sinkable, FlyweightMessageContainer {
private static final ThreadLocal<SqlException> tlException = new ThreadLocal<>(SqlException::new); private static final ThreadLocal<SqlException> tlException = new ThreadLocal<>(SqlException::new);
private final StringSink message = new StringSink(); private final StringSink message = new StringSink();
private int position; private int position;
...@@ -75,6 +76,7 @@ public class SqlException extends Exception implements Sinkable { ...@@ -75,6 +76,7 @@ public class SqlException extends Exception implements Sinkable {
.put(", to=").put(toName).put(']'); .put(", to=").put(toName).put(']');
} }
@Override
public CharSequence getFlyweightMessage() { public CharSequence getFlyweightMessage() {
return message; return message;
} }
......
...@@ -24,12 +24,13 @@ ...@@ -24,12 +24,13 @@
package io.questdb.griffin.engine.functions.bind; package io.questdb.griffin.engine.functions.bind;
import io.questdb.std.FlyweightMessageContainer;
import io.questdb.std.Sinkable; import io.questdb.std.Sinkable;
import io.questdb.std.ThreadLocal; import io.questdb.std.ThreadLocal;
import io.questdb.std.str.CharSink; import io.questdb.std.str.CharSink;
import io.questdb.std.str.StringSink; import io.questdb.std.str.StringSink;
public class BindException extends RuntimeException implements Sinkable { public class BindException extends RuntimeException implements Sinkable, FlyweightMessageContainer {
private static final ThreadLocal<BindException> tlException = new ThreadLocal<>(BindException::new); private static final ThreadLocal<BindException> tlException = new ThreadLocal<>(BindException::new);
private final StringSink message = new StringSink(); private final StringSink message = new StringSink();
...@@ -43,6 +44,7 @@ public class BindException extends RuntimeException implements Sinkable { ...@@ -43,6 +44,7 @@ public class BindException extends RuntimeException implements Sinkable {
return ex; return ex;
} }
@Override
public CharSequence getFlyweightMessage() { public CharSequence getFlyweightMessage() {
return message; return message;
} }
......
/*******************************************************************************
* ___ _ ____ ____
* / _ \ _ _ ___ ___| |_| _ \| __ )
* | | | | | | |/ _ \/ __| __| | | | _ \
* | |_| | |_| | __/\__ \ |_| |_| | |_) |
* \__\_\\__,_|\___||___/\__|____/|____/
*
* Copyright (c) 2014-2019 Appsicle
* Copyright (c) 2019-2020 QuestDB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
package io.questdb.griffin.engine.functions.test;
import io.questdb.cairo.CairoConfiguration;
import io.questdb.cairo.sql.Function;
import io.questdb.cairo.sql.Record;
import io.questdb.cairo.sql.SymbolTableSource;
import io.questdb.griffin.FunctionFactory;
import io.questdb.griffin.SqlException;
import io.questdb.griffin.SqlExecutionContext;
import io.questdb.griffin.engine.functions.BooleanFunction;
import io.questdb.std.ObjList;
public class TestNPEFactory implements FunctionFactory {
@Override
public String getSignature() {
return "npe()";
}
@Override
public Function newInstance(ObjList<Function> args, int position, CairoConfiguration configuration) throws SqlException {
return NPEFunction.INSTANCE;
}
private static class NPEFunction extends BooleanFunction {
private final static NPEFunction INSTANCE = new NPEFunction(0);
public NPEFunction(int position) {
super(position);
}
@Override
public boolean getBool(Record rec) {
throw new NullPointerException();
}
@Override
public void init(SymbolTableSource symbolTableSource, SqlExecutionContext executionContext) {
}
}
}
...@@ -39,8 +39,8 @@ public class ShowColumnsRecordCursorFactory implements RecordCursorFactory { ...@@ -39,8 +39,8 @@ public class ShowColumnsRecordCursorFactory implements RecordCursorFactory {
private static final int N_TYPE_COL = 1; private static final int N_TYPE_COL = 1;
static { static {
final GenericRecordMetadata metadata = new GenericRecordMetadata(); final GenericRecordMetadata metadata = new GenericRecordMetadata();
metadata.add(new TableColumnMetadata("columnName", ColumnType.STRING)); metadata.add(new TableColumnMetadata("column", ColumnType.STRING));
metadata.add(new TableColumnMetadata("columnType", ColumnType.STRING)); metadata.add(new TableColumnMetadata("type", ColumnType.STRING));
METADATA = metadata; METADATA = metadata;
} }
......
/*******************************************************************************
* ___ _ ____ ____
* / _ \ _ _ ___ ___| |_| _ \| __ )
* | | | | | | |/ _ \/ __| __| | | | _ \
* | |_| | |_| | __/\__ \ |_| |_| | |_) |
* \__\_\\__,_|\___||___/\__|____/|____/
*
* Copyright (c) 2014-2019 Appsicle
* Copyright (c) 2019-2020 QuestDB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
package io.questdb.std;
@FunctionalInterface
public interface FlyweightMessageContainer {
CharSequence getFlyweightMessage();
}
...@@ -84,6 +84,7 @@ open module io.questdb { ...@@ -84,6 +84,7 @@ open module io.questdb {
// test functions // test functions
io.questdb.griffin.engine.functions.test.TestMatchFunctionFactory, io.questdb.griffin.engine.functions.test.TestMatchFunctionFactory,
TestSumXDoubleGroupByFunctionFactory, TestSumXDoubleGroupByFunctionFactory,
io.questdb.griffin.engine.functions.test.TestNPEFactory,
io.questdb.griffin.engine.functions.test.TestSumTDoubleGroupByFunctionFactory, io.questdb.griffin.engine.functions.test.TestSumTDoubleGroupByFunctionFactory,
io.questdb.griffin.engine.functions.test.TestSumStringGroupByFunctionFactory, io.questdb.griffin.engine.functions.test.TestSumStringGroupByFunctionFactory,
io.questdb.griffin.engine.functions.bool.OrFunctionFactory, io.questdb.griffin.engine.functions.bool.OrFunctionFactory,
......
...@@ -52,7 +52,7 @@ public class ShowTablesTest extends AbstractGriffinTest { ...@@ -52,7 +52,7 @@ public class ShowTablesTest extends AbstractGriffinTest {
public void testShowColumnsWithSimpleTable() throws Exception { public void testShowColumnsWithSimpleTable() throws Exception {
assertMemoryLeak(() -> { assertMemoryLeak(() -> {
compiler.compile("create table balances(cust_id int, ccy symbol, balance double)", sqlExecutionContext); compiler.compile("create table balances(cust_id int, ccy symbol, balance double)", sqlExecutionContext);
assertQuery("columnName\tcolumnType\ncust_id\tINT\nccy\tSYMBOL\nbalance\tDOUBLE\n", "show columns from balances", null, false, sqlExecutionContext, false); assertQuery("column\ttype\ncust_id\tINT\nccy\tSYMBOL\nbalance\tDOUBLE\n", "show columns from balances", null, false, sqlExecutionContext, false);
}); });
} }
...@@ -107,7 +107,7 @@ public class ShowTablesTest extends AbstractGriffinTest { ...@@ -107,7 +107,7 @@ public class ShowTablesTest extends AbstractGriffinTest {
public void testShowColumnsWithFunction() throws Exception { public void testShowColumnsWithFunction() throws Exception {
assertMemoryLeak(() -> { assertMemoryLeak(() -> {
compiler.compile("create table balances(cust_id int, ccy symbol, balance double)", sqlExecutionContext); compiler.compile("create table balances(cust_id int, ccy symbol, balance double)", sqlExecutionContext);
assertQuery("columnName\tcolumnType\ncust_id\tINT\nccy\tSYMBOL\nbalance\tDOUBLE\n", "select * from table_columns('balances')", null, false, sqlExecutionContext, false); assertQuery("column\ttype\ncust_id\tINT\nccy\tSYMBOL\nbalance\tDOUBLE\n", "select * from table_columns('balances')", null, false, sqlExecutionContext, false);
}); });
} }
......
...@@ -70,10 +70,36 @@ ...@@ -70,10 +70,36 @@
# #
################################################################################ ################################################################################
################################################################################
# ___ _ ____ ____
# / _ \ _ _ ___ ___| |_| _ \| __ )
# | | | | | | |/ _ \/ __| __| | | | _ \
# | |_| | |_| | __/\__ \ |_| |_| | |_) |
# \__\_\\__,_|\___||___/\__|____/|____/
#
# Copyright (c) 2014-2019 Appsicle
# Copyright (c) 2019-2020 QuestDB
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
################################################################################
io.questdb.griffin.engine.functions.test.TestMatchFunctionFactory io.questdb.griffin.engine.functions.test.TestMatchFunctionFactory
io.questdb.griffin.engine.functions.test.TestSumXDoubleGroupByFunctionFactory io.questdb.griffin.engine.functions.test.TestSumXDoubleGroupByFunctionFactory
io.questdb.griffin.engine.functions.test.TestSumTDoubleGroupByFunctionFactory io.questdb.griffin.engine.functions.test.TestSumTDoubleGroupByFunctionFactory
io.questdb.griffin.engine.functions.test.TestSumStringGroupByFunctionFactory io.questdb.griffin.engine.functions.test.TestSumStringGroupByFunctionFactory
io.questdb.griffin.engine.functions.test.TestNPEFactory
# logical operations # logical operations
io.questdb.griffin.engine.functions.bool.OrFunctionFactory io.questdb.griffin.engine.functions.bool.OrFunctionFactory
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册