未验证 提交 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 {
return indexValueBlockSize;
}
@Override
public boolean enableTestFactories() {
return false;
}
@Override
public int getDoubleToStrCastScale() {
return doubleToStrCastScale;
......
......@@ -161,4 +161,6 @@ public interface CairoConfiguration {
int getGroupByPoolCapacity();
int getGroupByMapCapacity();
boolean enableTestFactories();
}
......@@ -24,7 +24,9 @@
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) {
super(cause);
}
......@@ -32,4 +34,9 @@ public class CairoError extends Error {
public CairoError(String message) {
super(message);
}
@Override
public CharSequence getFlyweightMessage() {
return getMessage();
}
}
......@@ -24,12 +24,13 @@
package io.questdb.cairo;
import io.questdb.std.FlyweightMessageContainer;
import io.questdb.std.Sinkable;
import io.questdb.std.ThreadLocal;
import io.questdb.std.str.CharSink;
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);
protected final StringSink message = new StringSink();
private int errno;
......@@ -63,6 +64,7 @@ public class CairoException extends RuntimeException implements Sinkable {
return this;
}
@Override
public CharSequence getFlyweightMessage() {
return message;
}
......
......@@ -52,6 +52,11 @@ public class DefaultCairoConfiguration implements CairoConfiguration {
return 16;
}
@Override
public boolean enableTestFactories() {
return true;
}
@Override
public int getCreateAsSelectRetryCount() {
return 5;
......
......@@ -28,14 +28,7 @@ import io.questdb.cairo.CairoSecurityContext;
import io.questdb.cairo.security.CairoSecurityContextImpl;
import io.questdb.log.Log;
import io.questdb.log.LogFactory;
import io.questdb.network.IOContext;
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.network.*;
import io.questdb.std.Chars;
import io.questdb.std.Mutable;
import io.questdb.std.ObjectPool;
......@@ -177,7 +170,7 @@ public class HttpConnectionContext implements IOContext, Locality, Mutable {
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).$(']').$();
processor.onRequestComplete(this);
}
......
......@@ -24,12 +24,13 @@
package io.questdb.cutlass.http;
import io.questdb.std.FlyweightMessageContainer;
import io.questdb.std.Sinkable;
import io.questdb.std.ThreadLocal;
import io.questdb.std.str.CharSink;
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 final StringSink message = new StringSink();
......@@ -41,7 +42,7 @@ public class HttpException extends RuntimeException implements Sinkable {
}
public CharSequence getFlyweightMessage() {
return tlException.get().getFlyweightMessage();
return message;
}
@Override
......
......@@ -31,7 +31,7 @@ import io.questdb.network.ServerDisconnectException;
public interface HttpRequestProcessor {
void onHeadersReady(HttpConnectionContext context);
void onRequestComplete(HttpConnectionContext context) throws PeerDisconnectedException, PeerIsSlowToReadException;
void onRequestComplete(HttpConnectionContext context) throws PeerDisconnectedException, PeerIsSlowToReadException, ServerDisconnectException;
default void resumeRecv(HttpConnectionContext context) {
}
......
......@@ -24,10 +24,6 @@
package io.questdb.cutlass.http.processors;
import java.io.Closeable;
import org.jetbrains.annotations.Nullable;
import io.questdb.MessageBus;
import io.questdb.cairo.CairoEngine;
import io.questdb.cairo.CairoError;
......@@ -36,11 +32,7 @@ import io.questdb.cairo.sql.InsertMethod;
import io.questdb.cairo.sql.InsertStatement;
import io.questdb.cairo.sql.ReaderOutOfDateException;
import io.questdb.cairo.sql.RecordCursorFactory;
import io.questdb.cutlass.http.HttpChunkedResponseSocket;
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.http.*;
import io.questdb.cutlass.text.Utf8Exception;
import io.questdb.griffin.CompiledQuery;
import io.questdb.griffin.SqlCompiler;
......@@ -48,17 +40,12 @@ import io.questdb.griffin.SqlException;
import io.questdb.griffin.SqlExecutionContextImpl;
import io.questdb.log.Log;
import io.questdb.log.LogFactory;
import io.questdb.network.IOOperation;
import io.questdb.network.NoSpaceLeftInResponseBufferException;
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.network.*;
import io.questdb.std.*;
import io.questdb.std.str.DirectByteCharSequence;
import org.jetbrains.annotations.Nullable;
import java.io.Closeable;
public class JsonQueryProcessor implements HttpRequestProcessor, Closeable {
private static final LocalValue<JsonQueryProcessorState> LV = new LocalValue<>();
......@@ -102,7 +89,7 @@ public class JsonQueryProcessor implements HttpRequestProcessor, Closeable {
Misc.free(compiler);
}
public void execute0(JsonQueryProcessorState state) throws PeerDisconnectedException, PeerIsSlowToReadException {
public void execute0(JsonQueryProcessorState state) throws PeerDisconnectedException, PeerIsSlowToReadException, ServerDisconnectException {
state.startExecutionTimer();
final HttpConnectionContext context = state.getHttpConnectionContext();
// 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 {
} catch (SqlException e) {
syntaxError(context.getChunkedResponseSocket(), e, state, configuration.getKeepAliveHeader());
readyForNextRequest(context);
} catch (CairoException | CairoError e) {
internalError(context.getChunkedResponseSocket(), e, state);
} catch (CairoError | CairoException e) {
internalError(context.getChunkedResponseSocket(), e.getFlyweightMessage(), e, state);
readyForNextRequest(context);
} catch (Throwable e) {
LOG.error().$("Uh-oh. Error!").$(e).$();
throw ServerDisconnectException.INSTANCE;
}
}
......@@ -142,7 +132,7 @@ public class JsonQueryProcessor implements HttpRequestProcessor, Closeable {
@Override
public void onRequestComplete(
HttpConnectionContext context
) throws PeerDisconnectedException, PeerIsSlowToReadException {
) throws PeerDisconnectedException, PeerIsSlowToReadException, ServerDisconnectException {
JsonQueryProcessorState state = LV.get(context);
if (state == null) {
LV.set(context, state = new JsonQueryProcessorState(
......@@ -360,11 +350,12 @@ public class JsonQueryProcessor implements HttpRequestProcessor, Closeable {
private void internalError(
HttpChunkedResponseSocket socket,
CharSequence message,
Throwable e,
JsonQueryProcessorState state
) throws PeerDisconnectedException, PeerIsSlowToReadException {
state.error().$("Server error executing query ").utf8(state.getQuery()).$(e).$();
sendException(socket, 0, e.getMessage(), 500, state.getQuery(), configuration.getKeepAliveHeader());
state.error().$("internal error [q=`").utf8(state.getQuery()).$("`, ex=").$(e).$();
sendException(socket, 0, message, 500, state.getQuery(), configuration.getKeepAliveHeader());
}
private boolean parseUrl(
......
......@@ -24,9 +24,7 @@
package io.questdb.cutlass.http.processors;
import io.questdb.cairo.CairoEngine;
import io.questdb.cairo.ColumnType;
import io.questdb.cairo.PartitionBy;
import io.questdb.cairo.*;
import io.questdb.cairo.sql.RecordMetadata;
import io.questdb.cutlass.http.*;
import io.questdb.cutlass.text.Atomicity;
......@@ -35,10 +33,7 @@ import io.questdb.cutlass.text.TextLoader;
import io.questdb.log.Log;
import io.questdb.log.LogFactory;
import io.questdb.network.*;
import io.questdb.std.CharSequenceIntHashMap;
import io.questdb.std.Chars;
import io.questdb.std.LongList;
import io.questdb.std.Misc;
import io.questdb.std.*;
import io.questdb.std.str.CharSink;
import java.io.Closeable;
......@@ -264,7 +259,7 @@ public class TextImportProcessor implements HttpRequestProcessor, HttpMultipartC
transientState.analysed = true;
transientState.textLoader.setState(TextLoader.LOAD_DATA);
}
} catch (TextException e) {
} catch (TextException | CairoException | CairoError e) {
handleTextException(e);
}
}
......@@ -338,7 +333,7 @@ public class TextImportProcessor implements HttpRequestProcessor, HttpMultipartC
if (transientState.messagePart == MESSAGE_DATA) {
sendResponse(transientContext);
}
} catch (TextException e) {
} catch (TextException | CairoException | CairoError e) {
handleTextException(e);
}
}
......@@ -398,7 +393,7 @@ public class TextImportProcessor implements HttpRequestProcessor, HttpMultipartC
state.clear();
}
private void handleTextException(TextException e)
private void handleTextException(FlyweightMessageContainer e)
throws PeerDisconnectedException, PeerIsSlowToReadException, ServerDisconnectException {
sendError(transientContext, e.getFlyweightMessage(), Chars.equalsNc("json", transientContext.getRequestHeader().getUrlParam("fmt")));
throw ServerDisconnectException.INSTANCE;
......
......@@ -24,12 +24,13 @@
package io.questdb.cutlass.json;
import io.questdb.std.FlyweightMessageContainer;
import io.questdb.std.Sinkable;
import io.questdb.std.ThreadLocal;
import io.questdb.std.str.CharSink;
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 final StringSink message = new StringSink();
private int position;
......@@ -45,6 +46,7 @@ public class JsonException extends Exception implements Sinkable {
return ex;
}
@Override
public CharSequence getFlyweightMessage() {
return message;
}
......
......@@ -24,13 +24,14 @@
package io.questdb.cutlass.text;
import io.questdb.std.FlyweightMessageContainer;
import io.questdb.std.Numbers;
import io.questdb.std.Sinkable;
import io.questdb.std.ThreadLocal;
import io.questdb.std.str.CharSink;
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 final StringSink message = new StringSink();
......@@ -42,6 +43,7 @@ public class TextException extends Exception implements Sinkable {
return te;
}
@Override
public CharSequence getFlyweightMessage() {
return message;
}
......
......@@ -81,7 +81,7 @@ public class FunctionParser implements PostOrderTreeTraversalAlgo.Visitor {
public FunctionParser(CairoConfiguration configuration, Iterable<FunctionFactory> functionFactories) {
this.configuration = configuration;
loadFunctionFactories(functionFactories);
loadFunctionFactories(functionFactories, configuration.enableTestFactories());
}
public static int getArgType(char c) {
......@@ -204,14 +204,14 @@ public class FunctionParser implements PostOrderTreeTraversalAlgo.Visitor {
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);
ex.put(message);
ex.put("unexpected argument for function: ");
ex.put(node.token);
ex.put(". expected args: ");
ex.put('(');
if (expected != null) {
for (int i = 0, n = count; i < n; i++) {
for (int i = 0; i < count; i++) {
if (i > 0) {
ex.put(',');
}
......@@ -670,9 +670,9 @@ public class FunctionParser implements PostOrderTreeTraversalAlgo.Visitor {
if (candidateSignature != null) {
final int sigArgOffset = candidateSignature.indexOf('(') + 1;
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 {
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 {
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) {
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 int openBraceIndex;
try {
openBraceIndex = validateSignatureAndGetNameSeparator(sig);
} catch (SqlException e) {
LOG.error().$((Sinkable) e).$(" [signature=").$(factory.getSignature()).$(",class=").$(factory.getClass().getName()).$(']').$();
continue;
}
final String name = sig.substring(0, openBraceIndex);
addFactoryToList(factories, name, factory);
// Add != counterparts to equality function factories
if (factory instanceof AbstractBooleanFunctionFactory) {
switch (name) {
case "=":
addFactory(booleanFactories, "!=", factory);
break;
case "<":
// `a < b` == `a >= b`
addFactory(booleanFactories, ">=", factory);
if (sig.charAt(2) == sig.charAt(3)) {
// `a < b` == `b > a`
addFactory(commutativeBooleanFactories, ">", factory);
// `a < b` == `b > a` == `b <= a`
addFactory(booleanFactories, "<=", factory);
addFactory(commutativeBooleanFactories, "<=", factory);
}
break;
final String name = sig.substring(0, openBraceIndex);
addFactoryToList(factories, name, factory);
// Add != counterparts to equality function factories
if (factory instanceof AbstractBooleanFunctionFactory) {
switch (name) {
case "=":
addFactory(booleanFactories, "!=", factory);
break;
case "<":
// `a < b` == `a >= b`
addFactory(booleanFactories, ">=", factory);
if (sig.charAt(2) == sig.charAt(3)) {
// `a < b` == `b > a`
addFactory(commutativeBooleanFactories, ">", factory);
// `a < b` == `b > a` == `b <= a`
addFactory(booleanFactories, "<=", factory);
addFactory(commutativeBooleanFactories, "<=", factory);
}
break;
}
} else if (factory.isGroupBy()) {
groupByFunctionNames.add(name);
}
} else if (factory.isGroupBy()) {
groupByFunctionNames.add(name);
}
}
}
......
......@@ -25,12 +25,13 @@
package io.questdb.griffin;
import io.questdb.cairo.ColumnType;
import io.questdb.std.FlyweightMessageContainer;
import io.questdb.std.Sinkable;
import io.questdb.std.ThreadLocal;
import io.questdb.std.str.CharSink;
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 final StringSink message = new StringSink();
private int position;
......@@ -75,6 +76,7 @@ public class SqlException extends Exception implements Sinkable {
.put(", to=").put(toName).put(']');
}
@Override
public CharSequence getFlyweightMessage() {
return message;
}
......
......@@ -24,12 +24,13 @@
package io.questdb.griffin.engine.functions.bind;
import io.questdb.std.FlyweightMessageContainer;
import io.questdb.std.Sinkable;
import io.questdb.std.ThreadLocal;
import io.questdb.std.str.CharSink;
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 final StringSink message = new StringSink();
......@@ -43,6 +44,7 @@ public class BindException extends RuntimeException implements Sinkable {
return ex;
}
@Override
public CharSequence getFlyweightMessage() {
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 {
private static final int N_TYPE_COL = 1;
static {
final GenericRecordMetadata metadata = new GenericRecordMetadata();
metadata.add(new TableColumnMetadata("columnName", ColumnType.STRING));
metadata.add(new TableColumnMetadata("columnType", ColumnType.STRING));
metadata.add(new TableColumnMetadata("column", ColumnType.STRING));
metadata.add(new TableColumnMetadata("type", ColumnType.STRING));
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 {
// test functions
io.questdb.griffin.engine.functions.test.TestMatchFunctionFactory,
TestSumXDoubleGroupByFunctionFactory,
io.questdb.griffin.engine.functions.test.TestNPEFactory,
io.questdb.griffin.engine.functions.test.TestSumTDoubleGroupByFunctionFactory,
io.questdb.griffin.engine.functions.test.TestSumStringGroupByFunctionFactory,
io.questdb.griffin.engine.functions.bool.OrFunctionFactory,
......
......@@ -52,7 +52,7 @@ public class ShowTablesTest extends AbstractGriffinTest {
public void testShowColumnsWithSimpleTable() throws Exception {
assertMemoryLeak(() -> {
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 {
public void testShowColumnsWithFunction() throws Exception {
assertMemoryLeak(() -> {
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 @@
#
################################################################################
################################################################################
# ___ _ ____ ____
# / _ \ _ _ ___ ___| |_| _ \| __ )
# | | | | | | |/ _ \/ __| __| | | | _ \
# | |_| | |_| | __/\__ \ |_| |_| | |_) |
# \__\_\\__,_|\___||___/\__|____/|____/
#
# 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.TestSumXDoubleGroupByFunctionFactory
io.questdb.griffin.engine.functions.test.TestSumTDoubleGroupByFunctionFactory
io.questdb.griffin.engine.functions.test.TestSumStringGroupByFunctionFactory
io.questdb.griffin.engine.functions.test.TestNPEFactory
# logical operations
io.questdb.griffin.engine.functions.bool.OrFunctionFactory
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册