未验证 提交 07538073 编写于 作者: J Jaromir Hamala 提交者: GitHub

chore(core): protected tables inaccessible for regular users (#3695)

上级 ef652a43
...@@ -84,7 +84,7 @@ public class TableReaderReloadBenchmark { ...@@ -84,7 +84,7 @@ public class TableReaderReloadBenchmark {
@Setup(Level.Iteration) @Setup(Level.Iteration)
public void setup() throws NumericException { public void setup() throws NumericException {
TableToken tableToken = new TableToken("test", "test", 0, false); TableToken tableToken = new TableToken("test", "test", 0, false, false);
writer = new TableWriter(configuration, tableToken, Metrics.disabled()); writer = new TableWriter(configuration, tableToken, Metrics.disabled());
writer.truncate(); writer.truncate();
// create 10 partitions // create 10 partitions
......
...@@ -77,9 +77,9 @@ public class TableWriterBenchmark { ...@@ -77,9 +77,9 @@ public class TableWriterBenchmark {
LogFactory.haltInstance(); LogFactory.haltInstance();
TableToken tableToken1 = new TableToken("test1", "test1", 0, false); TableToken tableToken1 = new TableToken("test1", "test1", 0, false, false);
TableToken tableToken2 = new TableToken("test2", "test2", 0, false); TableToken tableToken2 = new TableToken("test2", "test2", 0, false, false);
TableToken tableToken3 = new TableToken("test3", "test3", 0, false); TableToken tableToken3 = new TableToken("test3", "test3", 0, false, false);
writer = new TableWriter(configuration, tableToken1, Metrics.disabled()); writer = new TableWriter(configuration, tableToken1, Metrics.disabled());
writer2 = new TableWriter(configuration, tableToken2, Metrics.disabled()); writer2 = new TableWriter(configuration, tableToken2, Metrics.disabled());
......
...@@ -28,14 +28,18 @@ import io.questdb.std.ConcurrentHashMap; ...@@ -28,14 +28,18 @@ import io.questdb.std.ConcurrentHashMap;
import io.questdb.std.Misc; import io.questdb.std.Misc;
import io.questdb.std.ObjHashSet; import io.questdb.std.ObjHashSet;
import java.util.function.Predicate;
public abstract class AbstractTableNameRegistry implements TableNameRegistry { public abstract class AbstractTableNameRegistry implements TableNameRegistry {
// drop marker must contain special symbols to avoid a table created by the same name // drop marker must contain special symbols to avoid a table created by the same name
protected final TableNameRegistryFileStore nameStore; protected final TableNameRegistryFileStore nameStore;
protected final Predicate<CharSequence> protectedTableResolver;
private ConcurrentHashMap<TableToken> nameTokenMap; private ConcurrentHashMap<TableToken> nameTokenMap;
private ConcurrentHashMap<ReverseTableMapItem> reverseNameTokenMap; private ConcurrentHashMap<ReverseTableMapItem> reverseNameTokenMap;
public AbstractTableNameRegistry(CairoConfiguration configuration) { public AbstractTableNameRegistry(CairoConfiguration configuration, Predicate<CharSequence> protectedTableResolver) {
this.nameStore = new TableNameRegistryFileStore(configuration); this.nameStore = new TableNameRegistryFileStore(configuration, protectedTableResolver);
this.protectedTableResolver = protectedTableResolver;
} }
@Override @Override
...@@ -99,7 +103,8 @@ public abstract class AbstractTableNameRegistry implements TableNameRegistry { ...@@ -99,7 +103,8 @@ public abstract class AbstractTableNameRegistry implements TableNameRegistry {
void setNameMaps( void setNameMaps(
ConcurrentHashMap<TableToken> nameTableTokenMap, ConcurrentHashMap<TableToken> nameTableTokenMap,
ConcurrentHashMap<ReverseTableMapItem> reverseTableNameTokenMap) { ConcurrentHashMap<ReverseTableMapItem> reverseTableNameTokenMap
) {
this.nameTokenMap = nameTableTokenMap; this.nameTokenMap = nameTableTokenMap;
this.reverseNameTokenMap = reverseTableNameTokenMap; this.reverseNameTokenMap = reverseTableNameTokenMap;
} }
......
...@@ -55,12 +55,14 @@ import java.io.Closeable; ...@@ -55,12 +55,14 @@ import java.io.Closeable;
import java.util.Map; import java.util.Map;
import java.util.ServiceLoader; import java.util.ServiceLoader;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Predicate;
import static io.questdb.cairo.sql.OperationFuture.QUERY_COMPLETE; import static io.questdb.cairo.sql.OperationFuture.QUERY_COMPLETE;
import static io.questdb.griffin.CompiledQuery.*; import static io.questdb.griffin.CompiledQuery.*;
public class CairoEngine implements Closeable, WriterSource { public class CairoEngine implements Closeable, WriterSource {
public static final String BUSY_READER = "busyReader"; public static final String BUSY_READER = "busyReader";
public static final Predicate<CharSequence> EMPTY_RESOLVER = (tableName) -> false;
private static final Log LOG = LogFactory.getLog(CairoEngine.class); private static final Log LOG = LogFactory.getLog(CairoEngine.class);
private final AtomicLong asyncCommandCorrelationId = new AtomicLong(); private final AtomicLong asyncCommandCorrelationId = new AtomicLong();
private final CairoConfiguration configuration; private final CairoConfiguration configuration;
...@@ -70,6 +72,7 @@ public class CairoEngine implements Closeable, WriterSource { ...@@ -70,6 +72,7 @@ public class CairoEngine implements Closeable, WriterSource {
private final MessageBusImpl messageBus; private final MessageBusImpl messageBus;
private final MetadataPool metadataPool; private final MetadataPool metadataPool;
private final Metrics metrics; private final Metrics metrics;
private final Predicate<CharSequence> protectedTableResolver;
private final ReaderPool readerPool; private final ReaderPool readerPool;
private final DatabaseSnapshotAgent snapshotAgent; private final DatabaseSnapshotAgent snapshotAgent;
private final SqlCompilerPool sqlCompilerPool; private final SqlCompilerPool sqlCompilerPool;
...@@ -97,6 +100,7 @@ public class CairoEngine implements Closeable, WriterSource { ...@@ -97,6 +100,7 @@ public class CairoEngine implements Closeable, WriterSource {
configuration, configuration,
ServiceLoader.load(FunctionFactory.class, FunctionFactory.class.getClassLoader()) ServiceLoader.load(FunctionFactory.class, FunctionFactory.class.getClassLoader())
); );
this.protectedTableResolver = newProtectedTableResolver(configuration);
this.configuration = configuration; this.configuration = configuration;
this.copyContext = new CopyContext(configuration); this.copyContext = new CopyContext(configuration);
this.tableSequencerAPI = new TableSequencerAPI(this, configuration); this.tableSequencerAPI = new TableSequencerAPI(this, configuration);
...@@ -135,7 +139,7 @@ public class CairoEngine implements Closeable, WriterSource { ...@@ -135,7 +139,7 @@ public class CairoEngine implements Closeable, WriterSource {
try { try {
tableNameRegistry = configuration.isReadOnlyInstance() ? tableNameRegistry = configuration.isReadOnlyInstance() ?
new TableNameRegistryRO(configuration) : new TableNameRegistryRW(configuration); new TableNameRegistryRO(configuration, protectedTableResolver) : new TableNameRegistryRW(configuration, protectedTableResolver);
tableNameRegistry.reloadTableNameCache(); tableNameRegistry.reloadTableNameCache();
} catch (Throwable e) { } catch (Throwable e) {
close(); close();
...@@ -516,6 +520,10 @@ public class CairoEngine implements Closeable, WriterSource { ...@@ -516,6 +520,10 @@ public class CairoEngine implements Closeable, WriterSource {
return this.writerPool.getPoolListener(); return this.writerPool.getPoolListener();
} }
public Predicate<CharSequence> getProtectedTableResolver() {
return protectedTableResolver;
}
public TableReader getReader(CharSequence tableName) { public TableReader getReader(CharSequence tableName) {
return getReader(verifyTableNameForRead(tableName)); return getReader(verifyTableNameForRead(tableName));
} }
...@@ -723,7 +731,7 @@ public class CairoEngine implements Closeable, WriterSource { ...@@ -723,7 +731,7 @@ public class CairoEngine implements Closeable, WriterSource {
public void load() { public void load() {
// Convert tables to WAL/non-WAL, if necessary. // Convert tables to WAL/non-WAL, if necessary.
final ObjList<TableToken> convertedTables = TableConverter.convertTables(configuration, tableSequencerAPI); final ObjList<TableToken> convertedTables = TableConverter.convertTables(configuration, tableSequencerAPI, protectedTableResolver);
tableNameRegistry.reloadTableNameCache(convertedTables); tableNameRegistry.reloadTableNameCache(convertedTables);
} }
...@@ -1185,6 +1193,10 @@ public class CairoEngine implements Closeable, WriterSource { ...@@ -1185,6 +1193,10 @@ public class CairoEngine implements Closeable, WriterSource {
return token; return token;
} }
protected Predicate<CharSequence> newProtectedTableResolver(CairoConfiguration configuration) {
return EMPTY_RESOLVER;
}
private class EngineMaintenanceJob extends SynchronizedJob { private class EngineMaintenanceJob extends SynchronizedJob {
private final long checkInterval; private final long checkInterval;
......
...@@ -35,13 +35,15 @@ import io.questdb.std.*; ...@@ -35,13 +35,15 @@ import io.questdb.std.*;
import io.questdb.std.str.Path; import io.questdb.std.str.Path;
import io.questdb.std.str.StringSink; import io.questdb.std.str.StringSink;
import java.util.function.Predicate;
import static io.questdb.cairo.TableUtils.*; import static io.questdb.cairo.TableUtils.*;
import static io.questdb.cairo.wal.WalUtils.CONVERT_FILE_NAME; import static io.questdb.cairo.wal.WalUtils.CONVERT_FILE_NAME;
public class TableConverter { public class TableConverter {
private static final Log LOG = LogFactory.getLog(TableConverter.class); private static final Log LOG = LogFactory.getLog(TableConverter.class);
public static ObjList<TableToken> convertTables(CairoConfiguration configuration, TableSequencerAPI tableSequencerAPI) { public static ObjList<TableToken> convertTables(CairoConfiguration configuration, TableSequencerAPI tableSequencerAPI, Predicate<CharSequence> protectedTableResolver) {
final ObjList<TableToken> convertedTables = new ObjList<>(); final ObjList<TableToken> convertedTables = new ObjList<>();
if (!configuration.isTableTypeConversionEnabled()) { if (!configuration.isTableTypeConversionEnabled()) {
LOG.info().$("Table type conversion is disabled").$(); LOG.info().$("Table type conversion is disabled").$();
...@@ -82,7 +84,8 @@ public class TableConverter { ...@@ -82,7 +84,8 @@ public class TableConverter {
} }
final int tableId = metaMem.getInt(TableUtils.META_OFFSET_TABLE_ID); final int tableId = metaMem.getInt(TableUtils.META_OFFSET_TABLE_ID);
final TableToken token = new TableToken(tableName, dirName, tableId, walEnabled); boolean isProtected = protectedTableResolver.test(tableName);
final TableToken token = new TableToken(tableName, dirName, tableId, walEnabled, isProtected);
if (txWriter == null) { if (txWriter == null) {
txWriter = new TxWriter(ff, configuration); txWriter = new TxWriter(ff, configuration);
......
...@@ -32,7 +32,7 @@ import org.jetbrains.annotations.TestOnly; ...@@ -32,7 +32,7 @@ import org.jetbrains.annotations.TestOnly;
import java.io.Closeable; import java.io.Closeable;
public interface TableNameRegistry extends Closeable { public interface TableNameRegistry extends Closeable {
TableToken LOCKED_TOKEN = new TableToken("__locked__", "__locked__", Integer.MAX_VALUE, false); TableToken LOCKED_TOKEN = new TableToken("__locked__", "__locked__", Integer.MAX_VALUE, false, false);
TableToken addTableAlias(String newName, TableToken tableToken); TableToken addTableAlias(String newName, TableToken tableToken);
......
...@@ -38,6 +38,7 @@ import org.jetbrains.annotations.TestOnly; ...@@ -38,6 +38,7 @@ import org.jetbrains.annotations.TestOnly;
import java.io.Closeable; import java.io.Closeable;
import java.util.Map; import java.util.Map;
import java.util.function.Predicate;
import static io.questdb.cairo.wal.WalUtils.TABLE_REGISTRY_NAME_FILE; import static io.questdb.cairo.wal.WalUtils.TABLE_REGISTRY_NAME_FILE;
import static io.questdb.std.Files.DT_FILE; import static io.questdb.std.Files.DT_FILE;
...@@ -49,13 +50,15 @@ public class TableNameRegistryFileStore implements Closeable { ...@@ -49,13 +50,15 @@ public class TableNameRegistryFileStore implements Closeable {
private final static long TABLE_NAME_ENTRY_RESERVED_LONGS = 8; private final static long TABLE_NAME_ENTRY_RESERVED_LONGS = 8;
private final CairoConfiguration configuration; private final CairoConfiguration configuration;
private final StringSink nameSink = new StringSink(); private final StringSink nameSink = new StringSink();
private final Predicate<CharSequence> protectedTableResolver;
private final IntHashSet tableIds = new IntHashSet(); private final IntHashSet tableIds = new IntHashSet();
private final MemoryMARW tableNameMemory = Vm.getCMARWInstance(); private final MemoryMARW tableNameMemory = Vm.getCMARWInstance();
private final MemoryCMR tableNameRoMemory = Vm.getCMRInstance(); private final MemoryCMR tableNameRoMemory = Vm.getCMRInstance();
private int lockFd = -1; private int lockFd = -1;
public TableNameRegistryFileStore(CairoConfiguration configuration) { public TableNameRegistryFileStore(CairoConfiguration configuration, Predicate<CharSequence> protectedTableResolver) {
this.configuration = configuration; this.configuration = configuration;
this.protectedTableResolver = protectedTableResolver;
} }
public static int findLastTablesFileVersion(FilesFacade ff, Path path, StringSink nameSink) { public static int findLastTablesFileVersion(FilesFacade ff, Path path, StringSink nameSink) {
...@@ -281,7 +284,8 @@ public class TableNameRegistryFileStore implements Closeable { ...@@ -281,7 +284,8 @@ public class TableNameRegistryFileStore implements Closeable {
continue; continue;
} }
TableToken token = new TableToken(tableName, dirName, tableId, isWal); boolean isProtected = protectedTableResolver.test(tableName);
TableToken token = new TableToken(tableName, dirName, tableId, isWal, isProtected);
nameTableTokenMap.put(tableName, token); nameTableTokenMap.put(tableName, token);
reverseTableNameTokenMap.put(dirName, ReverseTableMapItem.of(token)); reverseTableNameTokenMap.put(dirName, ReverseTableMapItem.of(token));
} }
...@@ -365,7 +369,8 @@ public class TableNameRegistryFileStore implements Closeable { ...@@ -365,7 +369,8 @@ public class TableNameRegistryFileStore implements Closeable {
continue; continue;
} }
final TableToken token = new TableToken(tableName, dirName, tableId, tableType == TableUtils.TABLE_TYPE_WAL); boolean isProtected = protectedTableResolver.test(tableName);
final TableToken token = new TableToken(tableName, dirName, tableId, tableType == TableUtils.TABLE_TYPE_WAL, isProtected);
nameTableTokenMap.put(tableName, token); nameTableTokenMap.put(tableName, token);
if (!Chars.startsWith(token.getDirName(), token.getTableName())) { if (!Chars.startsWith(token.getDirName(), token.getTableName())) {
// This table is renamed, log system to real table name mapping // This table is renamed, log system to real table name mapping
......
...@@ -29,6 +29,8 @@ import io.questdb.std.ObjList; ...@@ -29,6 +29,8 @@ import io.questdb.std.ObjList;
import io.questdb.std.datetime.millitime.MillisecondClock; import io.questdb.std.datetime.millitime.MillisecondClock;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.function.Predicate;
public class TableNameRegistryRO extends AbstractTableNameRegistry { public class TableNameRegistryRO extends AbstractTableNameRegistry {
private final long autoReloadTimeout; private final long autoReloadTimeout;
private final MillisecondClock clockMs; private final MillisecondClock clockMs;
...@@ -38,8 +40,8 @@ public class TableNameRegistryRO extends AbstractTableNameRegistry { ...@@ -38,8 +40,8 @@ public class TableNameRegistryRO extends AbstractTableNameRegistry {
private ConcurrentHashMap<ReverseTableMapItem> reverseTableNameTokenMap = new ConcurrentHashMap<>(); private ConcurrentHashMap<ReverseTableMapItem> reverseTableNameTokenMap = new ConcurrentHashMap<>();
private ConcurrentHashMap<ReverseTableMapItem> reverseTableNameTokenMap2 = new ConcurrentHashMap<>(); private ConcurrentHashMap<ReverseTableMapItem> reverseTableNameTokenMap2 = new ConcurrentHashMap<>();
public TableNameRegistryRO(CairoConfiguration configuration) { public TableNameRegistryRO(CairoConfiguration configuration, Predicate<CharSequence> protectedTableResolver) {
super(configuration); super(configuration, protectedTableResolver);
this.clockMs = configuration.getMillisecondClock(); this.clockMs = configuration.getMillisecondClock();
long timeout = configuration.getTableRegistryAutoReloadFrequency(); long timeout = configuration.getTableRegistryAutoReloadFrequency();
this.autoReloadTimeout = timeout > 0 ? timeout : Long.MAX_VALUE; this.autoReloadTimeout = timeout > 0 ? timeout : Long.MAX_VALUE;
......
...@@ -29,12 +29,14 @@ import io.questdb.std.ConcurrentHashMap; ...@@ -29,12 +29,14 @@ import io.questdb.std.ConcurrentHashMap;
import io.questdb.std.ObjList; import io.questdb.std.ObjList;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.function.Predicate;
public class TableNameRegistryRW extends AbstractTableNameRegistry { public class TableNameRegistryRW extends AbstractTableNameRegistry {
private final ConcurrentHashMap<TableToken> nameTableTokenMap = new ConcurrentHashMap<>(false); private final ConcurrentHashMap<TableToken> nameTableTokenMap = new ConcurrentHashMap<>(false);
private final ConcurrentHashMap<ReverseTableMapItem> reverseTableNameTokenMap = new ConcurrentHashMap<>(); private final ConcurrentHashMap<ReverseTableMapItem> reverseTableNameTokenMap = new ConcurrentHashMap<>();
public TableNameRegistryRW(CairoConfiguration configuration) { public TableNameRegistryRW(CairoConfiguration configuration, Predicate<CharSequence> protectedTableResolver) {
super(configuration); super(configuration, protectedTableResolver);
if (!this.nameStore.lock()) { if (!this.nameStore.lock()) {
if (!configuration.getAllowTableRegistrySharedWrite()) { if (!configuration.getAllowTableRegistrySharedWrite()) {
throw CairoException.critical(0).put("cannot lock table name registry file [path=").put(configuration.getRoot()).put(']'); throw CairoException.critical(0).put("cannot lock table name registry file [path=").put(configuration.getRoot()).put(']');
...@@ -69,7 +71,8 @@ public class TableNameRegistryRW extends AbstractTableNameRegistry { ...@@ -69,7 +71,8 @@ public class TableNameRegistryRW extends AbstractTableNameRegistry {
public TableToken lockTableName(String tableName, String dirName, int tableId, boolean isWal) { public TableToken lockTableName(String tableName, String dirName, int tableId, boolean isWal) {
final TableToken registeredRecord = nameTableTokenMap.putIfAbsent(tableName, LOCKED_TOKEN); final TableToken registeredRecord = nameTableTokenMap.putIfAbsent(tableName, LOCKED_TOKEN);
if (registeredRecord == null) { if (registeredRecord == null) {
return new TableToken(tableName, dirName, tableId, isWal); boolean isProtected = protectedTableResolver.test(tableName);
return new TableToken(tableName, dirName, tableId, isWal, isProtected);
} else { } else {
return null; return null;
} }
......
...@@ -33,20 +33,22 @@ import org.jetbrains.annotations.NotNull; ...@@ -33,20 +33,22 @@ import org.jetbrains.annotations.NotNull;
public class TableToken implements Sinkable { public class TableToken implements Sinkable {
@NotNull @NotNull
private final GcUtf8String dirName; private final GcUtf8String dirName;
private final boolean isProtected;
private final boolean isWal; private final boolean isWal;
private final int tableId; private final int tableId;
@NotNull @NotNull
private final String tableName; private final String tableName;
public TableToken(@NotNull String tableName, @NotNull String dirName, int tableId, boolean isWal) { public TableToken(@NotNull String tableName, @NotNull String dirName, int tableId, boolean isWal, boolean isProtected) {
this(tableName, new GcUtf8String(dirName), tableId, isWal); this(tableName, new GcUtf8String(dirName), tableId, isWal, isProtected);
} }
private TableToken(@NotNull String tableName, @NotNull GcUtf8String dirName, int tableId, boolean isWal) { private TableToken(@NotNull String tableName, @NotNull GcUtf8String dirName, int tableId, boolean isWal, boolean isProtected) {
this.tableName = tableName; this.tableName = tableName;
this.dirName = dirName; this.dirName = dirName;
this.tableId = tableId; this.tableId = tableId;
this.isWal = isWal; this.isWal = isWal;
this.isProtected = isProtected;
} }
@Override @Override
...@@ -58,6 +60,7 @@ public class TableToken implements Sinkable { ...@@ -58,6 +60,7 @@ public class TableToken implements Sinkable {
if (tableId != that.tableId) return false; if (tableId != that.tableId) return false;
if (isWal != that.isWal) return false; if (isWal != that.isWal) return false;
if (isProtected != that.isProtected) return false;
if (!tableName.equals(that.tableName)) return false; if (!tableName.equals(that.tableName)) return false;
return dirName.equals(that.dirName); return dirName.equals(that.dirName);
} }
...@@ -95,12 +98,16 @@ public class TableToken implements Sinkable { ...@@ -95,12 +98,16 @@ public class TableToken implements Sinkable {
return tableId; return tableId;
} }
public boolean isProtected() {
return isProtected;
}
public boolean isWal() { public boolean isWal() {
return isWal; return isWal;
} }
public TableToken renamed(String newName) { public TableToken renamed(String newName) {
return new TableToken(newName, dirName, tableId, isWal); return new TableToken(newName, dirName, tableId, isWal, isProtected);
} }
@Override @Override
......
...@@ -20,9 +20,9 @@ public final class SqlCompilerPool extends AbstractMultiTenantPool<SqlCompilerPo ...@@ -20,9 +20,9 @@ public final class SqlCompilerPool extends AbstractMultiTenantPool<SqlCompilerPo
// note: we should not use too many colours otherwise the pool might create more compiler instances // note: we should not use too many colours otherwise the pool might create more compiler instances
// then with no pooling at all. This is because we have to have a separate compiler for each colour. // then with no pooling at all. This is because we have to have a separate compiler for each colour.
private static final TableToken[] TOKENS = { private static final TableToken[] TOKENS = {
new TableToken("blue", "/compilers/blue/", 0, false), new TableToken("blue", "/compilers/blue/", 0, false, false),
new TableToken("red", "/compilers/red/", 0, false), new TableToken("red", "/compilers/red/", 0, false, false),
new TableToken("green", "/compilers/green/", 0, false) new TableToken("green", "/compilers/green/", 0, false, false)
}; };
private final CairoEngine engine; private final CairoEngine engine;
private final Rnd rnd = new Rnd(); private final Rnd rnd = new Rnd();
......
...@@ -480,7 +480,7 @@ public class CopyTask { ...@@ -480,7 +480,7 @@ public class CopyTask {
tableNameSink.clear(); tableNameSink.clear();
tableNameSink.put(tableStructure.getTableName()).put('_').put(index); tableNameSink.put(tableStructure.getTableName()).put('_').put(index);
String tableName = tableNameSink.toString(); String tableName = tableNameSink.toString();
TableToken tableToken = new TableToken(tableName, tableName, (int) cairoEngine.getTableIdGenerator().getNextId(), false); TableToken tableToken = new TableToken(tableName, tableName, (int) cairoEngine.getTableIdGenerator().getNextId(), false, false);
final int columnCount = metadata.getColumnCount(); final int columnCount = metadata.getColumnCount();
try ( try (
...@@ -862,7 +862,7 @@ public class CopyTask { ...@@ -862,7 +862,7 @@ public class CopyTask {
tableNameSink.clear(); tableNameSink.clear();
tableNameSink.put(targetTableStructure.getTableName()).put('_').put(index); tableNameSink.put(targetTableStructure.getTableName()).put('_').put(index);
String publicTableName = tableNameSink.toString(); String publicTableName = tableNameSink.toString();
TableToken tableToken = new TableToken(publicTableName, publicTableName, (int) engine.getTableIdGenerator().getNextId(), false); TableToken tableToken = new TableToken(publicTableName, publicTableName, (int) engine.getTableIdGenerator().getNextId(), false, false);
createTable(ff, configuration.getMkDirMode(), importRoot, tableToken.getDirName(), publicTableName, targetTableStructure, 0, AllowAllSecurityContext.INSTANCE); createTable(ff, configuration.getMkDirMode(), importRoot, tableToken.getDirName(), publicTableName, targetTableStructure, 0, AllowAllSecurityContext.INSTANCE);
try ( try (
......
...@@ -103,7 +103,7 @@ public class TestDataUnavailableFunctionFactory implements FunctionFactory { ...@@ -103,7 +103,7 @@ public class TestDataUnavailableFunctionFactory implements FunctionFactory {
if (eventCallback != null) { if (eventCallback != null) {
eventCallback.onSuspendEvent(event); eventCallback.onSuspendEvent(event);
} }
throw DataUnavailableException.instance(new TableToken("foo", "foo", 1, false), "2022-01-01", event); throw DataUnavailableException.instance(new TableToken("foo", "foo", 1, false, false), "2022-01-01", event);
} }
rows++; rows++;
record.of(rows); record.of(rows);
......
...@@ -295,8 +295,7 @@ public final class Chars { ...@@ -295,8 +295,7 @@ public final class Chars {
} }
/** /**
* Compares two char sequences on assumption and right value is always lower case. * Case-insensitive comparison of two char sequences.
* Method converts every char of right sequence before comparing to left sequence.
* *
* @param l left sequence * @param l left sequence
* @param r right sequence * @param r right sequence
...@@ -312,13 +311,7 @@ public final class Chars { ...@@ -312,13 +311,7 @@ public final class Chars {
return false; return false;
} }
for (int i = 0; i < ll; i++) { return equalsCharsIgnoreCase(l, r, ll);
if (Character.toLowerCase(l.charAt(i)) != Character.toLowerCase(r.charAt(i))) {
return false;
}
}
return true;
} }
public static boolean equalsIgnoreCaseNc(@NotNull CharSequence l, @Nullable CharSequence r) { public static boolean equalsIgnoreCaseNc(@NotNull CharSequence l, @Nullable CharSequence r) {
...@@ -769,6 +762,11 @@ public final class Chars { ...@@ -769,6 +762,11 @@ public final class Chars {
return _this.length() > 0 && _this.charAt(0) == c; return _this.length() > 0 && _this.charAt(0) == c;
} }
public static boolean startsWithIgnoreCase(CharSequence _this, CharSequence that) {
final int len = that.length();
return _this.length() >= len && equalsCharsIgnoreCase(_this, that, len);
}
public static String stringFromUtf8Bytes(long lo, long hi) { public static String stringFromUtf8Bytes(long lo, long hi) {
if (hi == lo) { if (hi == lo) {
return ""; return "";
...@@ -1312,6 +1310,15 @@ public final class Chars { ...@@ -1312,6 +1310,15 @@ public final class Chars {
return true; return true;
} }
private static boolean equalsCharsIgnoreCase(CharSequence l, CharSequence r, int len) {
for (int i = 0; i < len; i++) {
if (Character.toLowerCase(l.charAt(i)) != Character.toLowerCase(r.charAt(i))) {
return false;
}
}
return true;
}
private static int utf8Decode2Bytes(ByteSequence seq, int index, int b1, CharSinkBase sink) { private static int utf8Decode2Bytes(ByteSequence seq, int index, int b1, CharSinkBase sink) {
if (seq.length() - index < 2) { if (seq.length() - index < 2) {
return utf8error(); return utf8error();
......
...@@ -44,9 +44,9 @@ public class SecurityContextTest { ...@@ -44,9 +44,9 @@ public class SecurityContextTest {
private static final LongList permissions = new LongList(); private static final LongList permissions = new LongList();
private final static String tableName = "tab"; private final static String tableName = "tab";
private static final Object[] THREE_PARAM_ARGS = {permissions, tableName, columns}; private static final Object[] THREE_PARAM_ARGS = {permissions, tableName, columns};
private static final TableToken tableToken = new TableToken(tableName, tableName, 0, false); private static final TableToken userTableToken = new TableToken(tableName, tableName, 0, false, false);
private static final Object[] ONE_PARAM_ARGS = {tableToken}; private static final Object[] ONE_PARAM_ARGS = {userTableToken};
private static final Object[] TWO_PARAM_ARGS = {tableToken, columns}; private static final Object[] TWO_PARAM_ARGS = {userTableToken, columns};
@Test @Test
public void testAllowAllSecurityContext() throws InvocationTargetException, IllegalAccessException { public void testAllowAllSecurityContext() throws InvocationTargetException, IllegalAccessException {
......
...@@ -217,7 +217,7 @@ public class TableNameRegistryTest extends AbstractCairoTest { ...@@ -217,7 +217,7 @@ public class TableNameRegistryTest extends AbstractCairoTest {
for (int i = 0; i < threadCount; i++) { for (int i = 0; i < threadCount; i++) {
threads.add(new Thread(() -> { threads.add(new Thread(() -> {
try { try {
try (TableNameRegistryRO ro = new TableNameRegistryRO(configuration)) { try (TableNameRegistryRO ro = new TableNameRegistryRO(configuration, CairoEngine.EMPTY_RESOLVER)) {
startBarrier.await(); startBarrier.await();
while (!done.get()) { while (!done.get()) {
ro.reloadTableNameCache(); ro.reloadTableNameCache();
...@@ -245,7 +245,7 @@ public class TableNameRegistryTest extends AbstractCairoTest { ...@@ -245,7 +245,7 @@ public class TableNameRegistryTest extends AbstractCairoTest {
// Add / remove tables // Add / remove tables
engine.closeNameRegistry(); engine.closeNameRegistry();
Rnd rnd = TestUtils.generateRandom(LOG); Rnd rnd = TestUtils.generateRandom(LOG);
try (TableNameRegistryRW rw = new TableNameRegistryRW(configuration)) { try (TableNameRegistryRW rw = new TableNameRegistryRW(configuration, CairoEngine.EMPTY_RESOLVER)) {
rw.reloadTableNameCache(); rw.reloadTableNameCache();
startBarrier.await(); startBarrier.await();
int iteration = 0; int iteration = 0;
...@@ -529,7 +529,7 @@ public class TableNameRegistryTest extends AbstractCairoTest { ...@@ -529,7 +529,7 @@ public class TableNameRegistryTest extends AbstractCairoTest {
engine.releaseInactive(); engine.releaseInactive();
} }
final ObjList<TableToken> convertedTables = TableConverter.convertTables(configuration, engine.getTableSequencerAPI()); final ObjList<TableToken> convertedTables = TableConverter.convertTables(configuration, engine.getTableSequencerAPI(), engine.getProtectedTableResolver());
if (!releaseInactiveBeforeConversion) { if (!releaseInactiveBeforeConversion) {
engine.releaseInactive(); engine.releaseInactive();
......
...@@ -27,9 +27,6 @@ package io.questdb.test.cairo; ...@@ -27,9 +27,6 @@ package io.questdb.test.cairo;
import io.questdb.cairo.TableToken; import io.questdb.cairo.TableToken;
import io.questdb.log.Log; import io.questdb.log.Log;
import io.questdb.log.LogFactory; import io.questdb.log.LogFactory;
import io.questdb.std.str.DirectCharSink;
import io.questdb.std.str.StringSink;
import io.questdb.std.str.GcUtf8String;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
...@@ -38,7 +35,7 @@ public class TableTokenTest { ...@@ -38,7 +35,7 @@ public class TableTokenTest {
@Test @Test
public void testBasics() { public void testBasics() {
final TableToken t1 = new TableToken("table1", "dir1", 1, true); final TableToken t1 = new TableToken("table1", "dir1", 1, true, false);
Assert.assertEquals("table1", t1.getTableName()); Assert.assertEquals("table1", t1.getTableName());
Assert.assertEquals("dir1", t1.getDirName()); Assert.assertEquals("dir1", t1.getDirName());
final boolean dirNameIdentity = t1.getDirName() == t1.getDirNameUtf8().toString(); final boolean dirNameIdentity = t1.getDirName() == t1.getDirNameUtf8().toString();
...@@ -57,7 +54,7 @@ public class TableTokenTest { ...@@ -57,7 +54,7 @@ public class TableTokenTest {
Assert.assertTrue(t2.isWal()); Assert.assertTrue(t2.isWal());
Assert.assertNotEquals(t1, t2); Assert.assertNotEquals(t1, t2);
final TableToken t1b = new TableToken("table1", "dir1", 1, true); final TableToken t1b = new TableToken("table1", "dir1", 1, true, false);
Assert.assertEquals(t1, t1b); Assert.assertEquals(t1, t1b);
} }
...@@ -73,7 +70,7 @@ public class TableTokenTest { ...@@ -73,7 +70,7 @@ public class TableTokenTest {
}; };
for (String str : strings) { for (String str : strings) {
final TableToken tt1 = new TableToken(str, "dir1", 1, false); final TableToken tt1 = new TableToken(str, "dir1", 1, false, false);
LOG.xinfo().$("Testing logging a fancy pants table token: >>>").$(tt1).$("<<<").$(); LOG.xinfo().$("Testing logging a fancy pants table token: >>>").$(tt1).$("<<<").$();
} }
} }
......
...@@ -707,7 +707,7 @@ public class ReaderPoolTest extends AbstractCairoTest { ...@@ -707,7 +707,7 @@ public class ReaderPoolTest extends AbstractCairoTest {
CyclicBarrier barrier = new CyclicBarrier(2); CyclicBarrier barrier = new CyclicBarrier(2);
CountDownLatch stopLatch = new CountDownLatch(2); CountDownLatch stopLatch = new CountDownLatch(2);
TableToken xTableToken = new TableToken("x", "x", 123, false); TableToken xTableToken = new TableToken("x", "x", 123, false, false);
final Runnable runnable = () -> { final Runnable runnable = () -> {
try { try {
...@@ -909,7 +909,7 @@ public class ReaderPoolTest extends AbstractCairoTest { ...@@ -909,7 +909,7 @@ public class ReaderPoolTest extends AbstractCairoTest {
@Test @Test
public void testUnlockByAnotherThread() throws Exception { public void testUnlockByAnotherThread() throws Exception {
assertWithPool(pool -> { assertWithPool(pool -> {
TableToken tableToken = new TableToken("Ургант", "Ургант", 123, false); TableToken tableToken = new TableToken("Ургант", "Ургант", 123, false, false);
Assert.assertTrue(pool.lock(tableToken)); Assert.assertTrue(pool.lock(tableToken));
AtomicInteger errors = new AtomicInteger(); AtomicInteger errors = new AtomicInteger();
...@@ -952,7 +952,7 @@ public class ReaderPoolTest extends AbstractCairoTest { ...@@ -952,7 +952,7 @@ public class ReaderPoolTest extends AbstractCairoTest {
} }
}); });
TableToken tableToken = new TableToken("xyz", "xyz", 123, false); TableToken tableToken = new TableToken("xyz", "xyz", 123, false, false);
pool.unlock(tableToken); pool.unlock(tableToken);
Assert.assertEquals(1, counter.get()); Assert.assertEquals(1, counter.get());
}); });
......
...@@ -548,7 +548,7 @@ public class WriterPoolTest extends AbstractCairoTest { ...@@ -548,7 +548,7 @@ public class WriterPoolTest extends AbstractCairoTest {
final AtomicInteger writerCount = new AtomicInteger(); final AtomicInteger writerCount = new AtomicInteger();
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
TableToken tableName = new TableToken("table_" + i, "table_" + i, i, false); TableToken tableName = new TableToken("table_" + i, "table_" + i, i, false, false);
new Thread(() -> { new Thread(() -> {
try { try {
barrier.await(); barrier.await();
......
...@@ -7975,7 +7975,7 @@ public class IODispatcherTest extends AbstractTest { ...@@ -7975,7 +7975,7 @@ public class IODispatcherTest extends AbstractTest {
DefaultCairoConfiguration configuration = new DefaultTestCairoConfiguration(baseDir); DefaultCairoConfiguration configuration = new DefaultTestCairoConfiguration(baseDir);
String dirName = TableUtils.getTableDir(mangleTableDirNames, tableName, 1, false); String dirName = TableUtils.getTableDir(mangleTableDirNames, tableName, 1, false);
TableToken tableToken = new TableToken(tableName, dirName, 1, false); TableToken tableToken = new TableToken(tableName, dirName, 1, false, false);
try (TableReader reader = new TableReader(configuration, tableToken)) { try (TableReader reader = new TableReader(configuration, tableToken)) {
Assert.assertEquals(expectedO3MaxLag, reader.getO3MaxLag()); Assert.assertEquals(expectedO3MaxLag, reader.getO3MaxLag());
Assert.assertEquals(expectedMaxUncommittedRows, reader.getMaxUncommittedRows()); Assert.assertEquals(expectedMaxUncommittedRows, reader.getMaxUncommittedRows());
...@@ -7991,7 +7991,7 @@ public class IODispatcherTest extends AbstractTest { ...@@ -7991,7 +7991,7 @@ public class IODispatcherTest extends AbstractTest {
DefaultCairoConfiguration configuration = new DefaultTestCairoConfiguration(baseDir); DefaultCairoConfiguration configuration = new DefaultTestCairoConfiguration(baseDir);
String telemetry = TelemetryTask.TABLE_NAME; String telemetry = TelemetryTask.TABLE_NAME;
TableToken telemetryTableName = new TableToken(telemetry, telemetry, 0, false); TableToken telemetryTableName = new TableToken(telemetry, telemetry, 0, false, false);
try (TableReader reader = new TableReader(configuration, telemetryTableName)) { try (TableReader reader = new TableReader(configuration, telemetryTableName)) {
final StringSink sink = new StringSink(); final StringSink sink = new StringSink();
sink.clear(); sink.clear();
......
...@@ -417,12 +417,13 @@ public class ImportIODispatcherTest extends AbstractTest { ...@@ -417,12 +417,13 @@ public class ImportIODispatcherTest extends AbstractTest {
"+-----------------------------------------------------------------------------------------------------------------+\r\n" + "+-----------------------------------------------------------------------------------------------------------------+\r\n" +
"\r\n" + "\r\n" +
"00\r\n" + "00\r\n" +
"\r\n"); "\r\n"
);
if (!waitForData.await(TimeUnit.SECONDS.toNanos(30L))) { if (!waitForData.await(TimeUnit.SECONDS.toNanos(30L))) {
Assert.fail(); Assert.fail();
} }
TableToken tableToken = new TableToken("syms", "syms", 0, false); TableToken tableToken = new TableToken("syms", "syms", 0, false, false);
try (TableReader reader = new TableReader(engine.getConfiguration(), tableToken)) { try (TableReader reader = new TableReader(engine.getConfiguration(), tableToken)) {
TableReaderMetadata meta = reader.getMetadata(); TableReaderMetadata meta = reader.getMetadata();
Assert.assertEquals(5, meta.getColumnCount()); Assert.assertEquals(5, meta.getColumnCount());
...@@ -449,20 +450,26 @@ public class ImportIODispatcherTest extends AbstractTest { ...@@ -449,20 +450,26 @@ public class ImportIODispatcherTest extends AbstractTest {
.withHttpServerConfigBuilder(new HttpServerConfigurationBuilder()) .withHttpServerConfigBuilder(new HttpServerConfigurationBuilder())
.withTelemetry(false) .withTelemetry(false)
.run((engine) -> new SendAndReceiveRequestBuilder().executeMany(executor -> { .run((engine) -> new SendAndReceiveRequestBuilder().executeMany(executor -> {
executor.execute(ValidImportRequest1.replace("STRING", "SYMBOL"), executor.execute(
ValidImportResponse1.replace("STRING", "SYMBOL")); ValidImportRequest1.replace("STRING", "SYMBOL"),
ValidImportResponse1.replace("STRING", "SYMBOL")
);
executor.executeWithStandardHeaders("GET /query?query=select+*+from+trips HTTP/1.1\r\n", executor.executeWithStandardHeaders(
"GET /query?query=select+*+from+trips HTTP/1.1\r\n",
"051b\r\n" + "051b\r\n" +
"{\"query\":\"select * from trips\",\"columns\":[{\"name\":\"Col1\",\"type\":\"SYMBOL\"},{\"name\":\"Pickup_DateTime\",\"type\":\"TIMESTAMP\"},{\"name\":\"DropOff_datetime\",\"type\":\"SYMBOL\"}],\"dataset\":[[\"B00008\",\"2017-02-01T00:30:00.000000Z\",null],[\"B00008\",\"2017-02-01T00:40:00.000000Z\",null],[\"B00009\",\"2017-02-01T00:50:00.000000Z\",null],[\"B00013\",\"2017-02-01T00:51:00.000000Z\",null],[\"B00013\",\"2017-02-01T01:41:00.000000Z\",null],[\"B00013\",\"2017-02-01T02:00:00.000000Z\",null],[\"B00013\",\"2017-02-01T03:53:00.000000Z\",null],[\"B00013\",\"2017-02-01T04:44:00.000000Z\",null],[\"B00013\",\"2017-02-01T05:05:00.000000Z\",null],[\"B00013\",\"2017-02-01T06:54:00.000000Z\",null],[\"B00014\",\"2017-02-01T07:45:00.000000Z\",null],[\"B00014\",\"2017-02-01T08:45:00.000000Z\",null],[\"B00014\",\"2017-02-01T09:46:00.000000Z\",null],[\"B00014\",\"2017-02-01T10:54:00.000000Z\",null],[\"B00014\",\"2017-02-01T11:45:00.000000Z\",null],[\"B00014\",\"2017-02-01T11:45:00.000000Z\",null],[\"B00014\",\"2017-02-01T11:45:00.000000Z\",null],[\"B00014\",\"2017-02-01T12:26:00.000000Z\",null],[\"B00014\",\"2017-02-01T12:55:00.000000Z\",null],[\"B00014\",\"2017-02-01T13:47:00.000000Z\",null],[\"B00014\",\"2017-02-01T14:05:00.000000Z\",null],[\"B00014\",\"2017-02-01T14:58:00.000000Z\",null],[\"B00014\",\"2017-02-01T15:33:00.000000Z\",null],[\"B00014\",\"2017-02-01T15:45:00.000000Z\",null]],\"timestamp\":-1,\"count\":24}\r\n" + "{\"query\":\"select * from trips\",\"columns\":[{\"name\":\"Col1\",\"type\":\"SYMBOL\"},{\"name\":\"Pickup_DateTime\",\"type\":\"TIMESTAMP\"},{\"name\":\"DropOff_datetime\",\"type\":\"SYMBOL\"}],\"dataset\":[[\"B00008\",\"2017-02-01T00:30:00.000000Z\",null],[\"B00008\",\"2017-02-01T00:40:00.000000Z\",null],[\"B00009\",\"2017-02-01T00:50:00.000000Z\",null],[\"B00013\",\"2017-02-01T00:51:00.000000Z\",null],[\"B00013\",\"2017-02-01T01:41:00.000000Z\",null],[\"B00013\",\"2017-02-01T02:00:00.000000Z\",null],[\"B00013\",\"2017-02-01T03:53:00.000000Z\",null],[\"B00013\",\"2017-02-01T04:44:00.000000Z\",null],[\"B00013\",\"2017-02-01T05:05:00.000000Z\",null],[\"B00013\",\"2017-02-01T06:54:00.000000Z\",null],[\"B00014\",\"2017-02-01T07:45:00.000000Z\",null],[\"B00014\",\"2017-02-01T08:45:00.000000Z\",null],[\"B00014\",\"2017-02-01T09:46:00.000000Z\",null],[\"B00014\",\"2017-02-01T10:54:00.000000Z\",null],[\"B00014\",\"2017-02-01T11:45:00.000000Z\",null],[\"B00014\",\"2017-02-01T11:45:00.000000Z\",null],[\"B00014\",\"2017-02-01T11:45:00.000000Z\",null],[\"B00014\",\"2017-02-01T12:26:00.000000Z\",null],[\"B00014\",\"2017-02-01T12:55:00.000000Z\",null],[\"B00014\",\"2017-02-01T13:47:00.000000Z\",null],[\"B00014\",\"2017-02-01T14:05:00.000000Z\",null],[\"B00014\",\"2017-02-01T14:58:00.000000Z\",null],[\"B00014\",\"2017-02-01T15:33:00.000000Z\",null],[\"B00014\",\"2017-02-01T15:45:00.000000Z\",null]],\"timestamp\":-1,\"count\":24}\r\n" +
"00\r\n" + "00\r\n" +
"\r\n"); "\r\n"
);
executor.executeWithStandardHeaders("GET /query?query=drop+table+trips HTTP/1.1\r\n", executor.executeWithStandardHeaders(
"GET /query?query=drop+table+trips HTTP/1.1\r\n",
"0c\r\n" + "0c\r\n" +
"{\"ddl\":\"OK\"}\r\n" + "{\"ddl\":\"OK\"}\r\n" +
"00\r\n" + "00\r\n" +
"\r\n"); "\r\n"
);
String request2 = ValidImportRequest2 String request2 = ValidImportRequest2
.replace("POST /upload?name=trips HTTP", "POST /upload?name=trips&timestamp=Pickup_DateTime&overwrite=true HTTP"); .replace("POST /upload?name=trips HTTP", "POST /upload?name=trips&timestamp=Pickup_DateTime&overwrite=true HTTP");
...@@ -517,11 +524,13 @@ public class ImportIODispatcherTest extends AbstractTest { ...@@ -517,11 +524,13 @@ public class ImportIODispatcherTest extends AbstractTest {
"00\r\n" + "00\r\n" +
"\r\n" "\r\n"
); );
executor.executeWithStandardHeaders("GET /query?query=drop+table+trips HTTP/1.1\r\n", executor.executeWithStandardHeaders(
"GET /query?query=drop+table+trips HTTP/1.1\r\n",
"0c\r\n" + "0c\r\n" +
"{\"ddl\":\"OK\"}\r\n" + "{\"ddl\":\"OK\"}\r\n" +
"00\r\n" + "00\r\n" +
"\r\n"); "\r\n"
);
String request2 = ValidImportRequest2 String request2 = ValidImportRequest2
.replace("POST /upload?name=trips HTTP", "POST /upload?name=trips&timestamp=Pickup_DateTime&overwrite=true HTTP"); .replace("POST /upload?name=trips HTTP", "POST /upload?name=trips&timestamp=Pickup_DateTime&overwrite=true HTTP");
...@@ -715,12 +724,13 @@ public class ImportIODispatcherTest extends AbstractTest { ...@@ -715,12 +724,13 @@ public class ImportIODispatcherTest extends AbstractTest {
"+-----------------------------------------------------------------------------------------------------------------+\r\n" + "+-----------------------------------------------------------------------------------------------------------------+\r\n" +
"\r\n" + "\r\n" +
"00\r\n" + "00\r\n" +
"\r\n"); "\r\n"
);
if (!waitForData.await(TimeUnit.SECONDS.toNanos(30L))) { if (!waitForData.await(TimeUnit.SECONDS.toNanos(30L))) {
Assert.fail(); Assert.fail();
} }
TableToken tableToken = new TableToken("syms", "syms", 0, false); TableToken tableToken = new TableToken("syms", "syms", 0, false, false);
try (TableReader reader = new TableReader(engine.getConfiguration(), tableToken)) { try (TableReader reader = new TableReader(engine.getConfiguration(), tableToken)) {
TableReaderMetadata meta = reader.getMetadata(); TableReaderMetadata meta = reader.getMetadata();
Assert.assertEquals(5, meta.getColumnCount()); Assert.assertEquals(5, meta.getColumnCount());
...@@ -773,12 +783,14 @@ public class ImportIODispatcherTest extends AbstractTest { ...@@ -773,12 +783,14 @@ public class ImportIODispatcherTest extends AbstractTest {
.replace("POST /upload?name=trips HTTP", "POST /upload?name=trips&timestamp=Pickup_DateTime HTTP"); .replace("POST /upload?name=trips HTTP", "POST /upload?name=trips&timestamp=Pickup_DateTime HTTP");
String response = WarningValidImportResponse1 String response = WarningValidImportResponse1
.replace("\r\n" + .replace(
"\r\n" +
"| Partition by | NONE | | | From Table |\r\n" + "| Partition by | NONE | | | From Table |\r\n" +
"| Timestamp | NONE | | | From Table |", "| Timestamp | NONE | | | From Table |",
"\r\n" + "\r\n" +
"| Partition by | DAY | | | |\r\n" + "| Partition by | DAY | | | |\r\n" +
"| Timestamp | Pickup_DateTime | | | |"); "| Timestamp | Pickup_DateTime | | | |"
);
new SendAndReceiveRequestBuilder().execute(request, response); new SendAndReceiveRequestBuilder().execute(request, response);
drainWalQueue(engine); drainWalQueue(engine);
...@@ -827,7 +839,8 @@ public class ImportIODispatcherTest extends AbstractTest { ...@@ -827,7 +839,8 @@ public class ImportIODispatcherTest extends AbstractTest {
"0c\r\n" + "0c\r\n" +
"{\"ddl\":\"OK\"}\r\n" + "{\"ddl\":\"OK\"}\r\n" +
"00\r\n" + "00\r\n" +
"\r\n"); "\r\n"
);
String request = requestTemplate String request = requestTemplate
.replace("POST /upload?name=trips HTTP", "POST /upload?name=trips&fmt=json&partitionBy=DAY&timestamp=Pickup_DateTime&overwrite=true HTTP"); .replace("POST /upload?name=trips HTTP", "POST /upload?name=trips&fmt=json&partitionBy=DAY&timestamp=Pickup_DateTime&overwrite=true HTTP");
...@@ -855,7 +868,8 @@ public class ImportIODispatcherTest extends AbstractTest { ...@@ -855,7 +868,8 @@ public class ImportIODispatcherTest extends AbstractTest {
"0c\r\n" + "0c\r\n" +
"{\"ddl\":\"OK\"}\r\n" + "{\"ddl\":\"OK\"}\r\n" +
"00\r\n" + "00\r\n" +
"\r\n"); "\r\n"
);
String request = requestTemplate String request = requestTemplate
.replace("POST /upload?name=trips HTTP", "POST /upload?name=trips&partitionBy=DAY&timestamp=Pickup_DateTime HTTP"); .replace("POST /upload?name=trips HTTP", "POST /upload?name=trips&partitionBy=DAY&timestamp=Pickup_DateTime HTTP");
...@@ -883,7 +897,8 @@ public class ImportIODispatcherTest extends AbstractTest { ...@@ -883,7 +897,8 @@ public class ImportIODispatcherTest extends AbstractTest {
"0c\r\n" + "0c\r\n" +
"{\"ddl\":\"OK\"}\r\n" + "{\"ddl\":\"OK\"}\r\n" +
"00\r\n" + "00\r\n" +
"\r\n"); "\r\n"
);
String request = requestTemplate String request = requestTemplate
.replace("POST /upload?name=trips HTTP", "POST /upload?name=trips&fmt=json&partitionBy=DAY&timestamp=Pickup_DateTime HTTP"); .replace("POST /upload?name=trips HTTP", "POST /upload?name=trips&fmt=json&partitionBy=DAY&timestamp=Pickup_DateTime HTTP");
...@@ -935,19 +950,23 @@ public class ImportIODispatcherTest extends AbstractTest { ...@@ -935,19 +950,23 @@ public class ImportIODispatcherTest extends AbstractTest {
engine.ddl("create table xyz as (select x, timestamp_sequence(0, " + Timestamps.DAY_MICROS + ") ts from long_sequence(1)) timestamp(ts) Partition by DAY ", sqlExecutionContext); engine.ddl("create table xyz as (select x, timestamp_sequence(0, " + Timestamps.DAY_MICROS + ") ts from long_sequence(1)) timestamp(ts) Partition by DAY ", sqlExecutionContext);
// Cache query plan // Cache query plan
new SendAndReceiveRequestBuilder().executeWithStandardHeaders("GET /query?query=select+count(*)+from+xyz+where+x+%3E+0; HTTP/1.1\r\n", new SendAndReceiveRequestBuilder().executeWithStandardHeaders(
"GET /query?query=select+count(*)+from+xyz+where+x+%3E+0; HTTP/1.1\r\n",
"85\r\n" + "85\r\n" +
"{\"query\":\"select count(*) from xyz where x > 0;\",\"columns\":[{\"name\":\"count\",\"type\":\"LONG\"}],\"dataset\":[[1]],\"timestamp\":-1,\"count\":1}\r\n" + "{\"query\":\"select count(*) from xyz where x > 0;\",\"columns\":[{\"name\":\"count\",\"type\":\"LONG\"}],\"dataset\":[[1]],\"timestamp\":-1,\"count\":1}\r\n" +
"00\r\n" + "00\r\n" +
"\r\n"); "\r\n"
);
// Add new commit // Add new commit
engine.insert("insert into xyz select x, timestamp_sequence(" + Timestamps.DAY_MICROS + ", 1) ts from long_sequence(10) ", sqlExecutionContext); engine.insert("insert into xyz select x, timestamp_sequence(" + Timestamps.DAY_MICROS + ", 1) ts from long_sequence(10) ", sqlExecutionContext);
// Here fail expected // Here fail expected
new SendAndReceiveRequestBuilder().withCompareLength(20).executeWithStandardHeaders("GET /query?query=select+count(*)+from+xyz+where+x+%3E+0; HTTP/1.1\r\n" + SendAndReceiveRequestBuilder.RequestHeaders, new SendAndReceiveRequestBuilder().withCompareLength(20).executeWithStandardHeaders(
"GET /query?query=select+count(*)+from+xyz+where+x+%3E+0; HTTP/1.1\r\n" + SendAndReceiveRequestBuilder.RequestHeaders,
"8e\r\n" + "8e\r\n" +
"{\"query\":\"select count(*) from xyz where x > 0;\",\"error\":\"File not found: "); "{\"query\":\"select count(*) from xyz where x > 0;\",\"error\":\"File not found: "
);
// Check that txn_scoreboard is fully unlocked, e.g. no reader scoreboard leaks after the failure // Check that txn_scoreboard is fully unlocked, e.g. no reader scoreboard leaks after the failure
CairoConfiguration configuration = engine.getConfiguration(); CairoConfiguration configuration = engine.getConfiguration();
...@@ -1012,7 +1031,8 @@ public class ImportIODispatcherTest extends AbstractTest { ...@@ -1012,7 +1031,8 @@ public class ImportIODispatcherTest extends AbstractTest {
new SendAndReceiveRequestBuilder() new SendAndReceiveRequestBuilder()
.withExpectSendDisconnect(true) .withExpectSendDisconnect(true)
.execute(request, .execute(
request,
"HTTP/1.1 200 OK\r\n" + "HTTP/1.1 200 OK\r\n" +
"Server: questDB/1.0\r\n" + "Server: questDB/1.0\r\n" +
"Date: Thu, 1 Jan 1970 00:00:00 GMT\r\n" + "Date: Thu, 1 Jan 1970 00:00:00 GMT\r\n" +
...@@ -1022,7 +1042,8 @@ public class ImportIODispatcherTest extends AbstractTest { ...@@ -1022,7 +1042,8 @@ public class ImportIODispatcherTest extends AbstractTest {
"12\r\n" + "12\r\n" +
"not a timestamp ''\r\n" + "not a timestamp ''\r\n" +
"00\r\n" + "00\r\n" +
"\r\n"); "\r\n"
);
engine.insert("insert into trips values (" + engine.insert("insert into trips values (" +
"'2021-07-20T00:01:00', 'ABC', 'DEF'" + "'2021-07-20T00:01:00', 'ABC', 'DEF'" +
...@@ -1065,7 +1086,8 @@ public class ImportIODispatcherTest extends AbstractTest { ...@@ -1065,7 +1086,8 @@ public class ImportIODispatcherTest extends AbstractTest {
"0c\r\n" + "0c\r\n" +
"{\"ddl\":\"OK\"}\r\n" + "{\"ddl\":\"OK\"}\r\n" +
"00\r\n" + "00\r\n" +
"\r\n"); "\r\n"
);
new Thread(() -> { new Thread(() -> {
try { try {
...@@ -1095,7 +1117,8 @@ public class ImportIODispatcherTest extends AbstractTest { ...@@ -1095,7 +1117,8 @@ public class ImportIODispatcherTest extends AbstractTest {
"';\",\"columns\":[{\"name\":\"Col1\",\"type\":\"SYMBOL\"}]," + "';\",\"columns\":[{\"name\":\"Col1\",\"type\":\"SYMBOL\"}]," +
"\"dataset\":[[\"SYM-" + row + "\"]],\"timestamp\":-1,\"count\":1}\r\n" "\"dataset\":[[\"SYM-" + row + "\"]],\"timestamp\":-1,\"count\":1}\r\n"
+ "00\r\n" + "00\r\n"
+ "\r\n"); + "\r\n"
);
} }
}); });
...@@ -1113,11 +1136,13 @@ public class ImportIODispatcherTest extends AbstractTest { ...@@ -1113,11 +1136,13 @@ public class ImportIODispatcherTest extends AbstractTest {
boolean finished = countDownLatch.await(Math.max(10 * importRowCount, 2000) * totalImports, TimeUnit.MILLISECONDS); boolean finished = countDownLatch.await(Math.max(10 * importRowCount, 2000) * totalImports, TimeUnit.MILLISECONDS);
Assert.assertTrue( Assert.assertTrue(
"Import is not finished in reasonable time, check server errors", "Import is not finished in reasonable time, check server errors",
finished); finished
);
Assert.assertEquals( Assert.assertEquals(
"Expected successful import count does not match actual imports", "Expected successful import count does not match actual imports",
totalImports, totalImports,
success.get()); success.get()
);
}); });
} }
...@@ -1148,7 +1173,8 @@ public class ImportIODispatcherTest extends AbstractTest { ...@@ -1148,7 +1173,8 @@ public class ImportIODispatcherTest extends AbstractTest {
"0c\r\n" + "0c\r\n" +
"{\"ddl\":\"OK\"}\r\n" + "{\"ddl\":\"OK\"}\r\n" +
"00\r\n" + "00\r\n" +
"\r\n"); "\r\n"
);
new Thread(() -> { new Thread(() -> {
try { try {
...@@ -1180,11 +1206,13 @@ public class ImportIODispatcherTest extends AbstractTest { ...@@ -1180,11 +1206,13 @@ public class ImportIODispatcherTest extends AbstractTest {
boolean finished = countDownLatch.await(200 * totalImports, TimeUnit.MILLISECONDS); boolean finished = countDownLatch.await(200 * totalImports, TimeUnit.MILLISECONDS);
Assert.assertTrue( Assert.assertTrue(
"Import is not finished in reasonable time, check server errors", "Import is not finished in reasonable time, check server errors",
finished); finished
);
Assert.assertEquals( Assert.assertEquals(
"Expected successful import count does not match actual imports", "Expected successful import count does not match actual imports",
totalImports, totalImports,
success.get()); success.get()
);
}); });
} }
} }
...@@ -145,12 +145,12 @@ public class ColumnPurgeJobTest extends AbstractCairoTest { ...@@ -145,12 +145,12 @@ public class ColumnPurgeJobTest extends AbstractCairoTest {
assertMemoryLeak(() -> { assertMemoryLeak(() -> {
currentMicros = 0; currentMicros = 0;
try (ColumnPurgeJob purgeJob = createPurgeJob()) { try (ColumnPurgeJob purgeJob = createPurgeJob()) {
TableToken tn1 = new TableToken("tbl_name", "tbl_name", 123, false); TableToken tn1 = new TableToken("tbl_name", "tbl_name", 123, false, false);
ColumnPurgeTask task = createTask(tn1, "col", 1, ColumnType.INT, 43, 11, "2022-03-29", -1); ColumnPurgeTask task = createTask(tn1, "col", 1, ColumnType.INT, 43, 11, "2022-03-29", -1);
task.appendColumnInfo(-1, IntervalUtils.parseFloorPartialTimestamp("2022-04-05"), 2); task.appendColumnInfo(-1, IntervalUtils.parseFloorPartialTimestamp("2022-04-05"), 2);
appendTaskToQueue(task); appendTaskToQueue(task);
TableToken tn2 = new TableToken("tbl_name2", "tbl_name2", 123, false); TableToken tn2 = new TableToken("tbl_name2", "tbl_name2", 123, false, false);
ColumnPurgeTask task2 = createTask(tn2, "col2", 2, ColumnType.SYMBOL, 33, -1, "2022-02-13", 3); ColumnPurgeTask task2 = createTask(tn2, "col2", 2, ColumnType.SYMBOL, 33, -1, "2022-02-13", 3);
appendTaskToQueue(task2); appendTaskToQueue(task2);
...@@ -803,13 +803,13 @@ public class ColumnPurgeJobTest extends AbstractCairoTest { ...@@ -803,13 +803,13 @@ public class ColumnPurgeJobTest extends AbstractCairoTest {
assertMemoryLeak(() -> { assertMemoryLeak(() -> {
currentMicros = 0; currentMicros = 0;
try (ColumnPurgeJob purgeJob = createPurgeJob()) { try (ColumnPurgeJob purgeJob = createPurgeJob()) {
TableToken tn1 = new TableToken("tbl_name", "tbl_name", 123, false); TableToken tn1 = new TableToken("tbl_name", "tbl_name", 123, false, false);
ColumnPurgeTask task = createTask(tn1, "col", 1, ColumnType.INT, 43, 11, "2022-03-29", -1); ColumnPurgeTask task = createTask(tn1, "col", 1, ColumnType.INT, 43, 11, "2022-03-29", -1);
task.appendColumnInfo(-1, IntervalUtils.parseFloorPartialTimestamp("2022-04-05"), 2); task.appendColumnInfo(-1, IntervalUtils.parseFloorPartialTimestamp("2022-04-05"), 2);
appendTaskToQueue(task); appendTaskToQueue(task);
TableToken tn2 = new TableToken("tbl_name2", "tbl_name2", 123, false); TableToken tn2 = new TableToken("tbl_name2", "tbl_name2", 123, false, false);
ColumnPurgeTask task2 = createTask(tn2, "col2", 2, ColumnType.SYMBOL, 33, -1, "2022-02-13", 3); ColumnPurgeTask task2 = createTask(tn2, "col2", 2, ColumnType.SYMBOL, 33, -1, "2022-02-13", 3);
appendTaskToQueue(task2); appendTaskToQueue(task2);
...@@ -890,6 +890,14 @@ public class ColumnPurgeJobTest extends AbstractCairoTest { ...@@ -890,6 +890,14 @@ public class ColumnPurgeJobTest extends AbstractCairoTest {
return tsk; return tsk;
} }
private void runPurgeJob(ColumnPurgeJob purgeJob) {
engine.releaseInactive();
currentMicros += 10L * iteration++;
purgeJob.run(0);
currentMicros += 10L * iteration++;
purgeJob.run(0);
}
private void update(String updateSql) throws SqlException { private void update(String updateSql) throws SqlException {
ddl(updateSql); ddl(updateSql);
// try (SqlCompiler compiler = engine.getSqlCompiler()) { // try (SqlCompiler compiler = engine.getSqlCompiler()) {
...@@ -900,12 +908,4 @@ public class ColumnPurgeJobTest extends AbstractCairoTest { ...@@ -900,12 +908,4 @@ public class ColumnPurgeJobTest extends AbstractCairoTest {
// } // }
// } // }
} }
private void runPurgeJob(ColumnPurgeJob purgeJob) {
engine.releaseInactive();
currentMicros += 10L * iteration++;
purgeJob.run(0);
currentMicros += 10L * iteration++;
purgeJob.run(0);
}
} }
...@@ -7898,7 +7898,7 @@ public class SqlParserTest extends AbstractSqlParserTest { ...@@ -7898,7 +7898,7 @@ public class SqlParserTest extends AbstractSqlParserTest {
public void testTableNameLocked() throws Exception { public void testTableNameLocked() throws Exception {
assertMemoryLeak(() -> { assertMemoryLeak(() -> {
String dirName = "tab" + TableUtils.SYSTEM_TABLE_NAME_SUFFIX; String dirName = "tab" + TableUtils.SYSTEM_TABLE_NAME_SUFFIX;
TableToken tableToken = new TableToken("tab", dirName, 1 + getSystemTablesCount(), false); TableToken tableToken = new TableToken("tab", dirName, 1 + getSystemTablesCount(), false, false);
CharSequence lockedReason = engine.lock(tableToken, "testing"); CharSequence lockedReason = engine.lock(tableToken, "testing");
Assert.assertNull(lockedReason); Assert.assertNull(lockedReason);
try { try {
......
...@@ -327,7 +327,7 @@ public class WalPurgeJobTest extends AbstractCairoTest { ...@@ -327,7 +327,7 @@ public class WalPurgeJobTest extends AbstractCairoTest {
*/ */
TestDeleter deleter = new TestDeleter(); TestDeleter deleter = new TestDeleter();
WalPurgeJob.Logic logic = new WalPurgeJob.Logic(deleter); WalPurgeJob.Logic logic = new WalPurgeJob.Logic(deleter);
TableToken tableToken = new TableToken("test", "test~1", 42, true); TableToken tableToken = new TableToken("test", "test~1", 42, true, false);
logic.reset(tableToken); logic.reset(tableToken);
logic.trackDiscoveredSegment(1, 1, false, false); logic.trackDiscoveredSegment(1, 1, false, false);
logic.trackDiscoveredSegment(1, 2, false, false); logic.trackDiscoveredSegment(1, 2, false, false);
...@@ -378,7 +378,7 @@ public class WalPurgeJobTest extends AbstractCairoTest { ...@@ -378,7 +378,7 @@ public class WalPurgeJobTest extends AbstractCairoTest {
*/ */
TestDeleter deleter = new TestDeleter(); TestDeleter deleter = new TestDeleter();
WalPurgeJob.Logic logic = new WalPurgeJob.Logic(deleter); WalPurgeJob.Logic logic = new WalPurgeJob.Logic(deleter);
TableToken tableToken = new TableToken("test", "test~1", 42, true); TableToken tableToken = new TableToken("test", "test~1", 42, true, false);
logic.reset(tableToken); logic.reset(tableToken);
logic.trackDiscoveredSegment(1, 1, false, false); logic.trackDiscoveredSegment(1, 1, false, false);
logic.trackDiscoveredSegment(1, 2, false, true); logic.trackDiscoveredSegment(1, 2, false, true);
......
...@@ -684,7 +684,7 @@ public class WalTableFailureTest extends AbstractCairoTest { ...@@ -684,7 +684,7 @@ public class WalTableFailureTest extends AbstractCairoTest {
public void testNonWalTableTransactionNotificationIsIgnored() throws Exception { public void testNonWalTableTransactionNotificationIsIgnored() throws Exception {
assertMemoryLeak(() -> { assertMemoryLeak(() -> {
String tableName = testName.getMethodName(); String tableName = testName.getMethodName();
TableToken ignored = new TableToken(tableName, tableName, 123, false); TableToken ignored = new TableToken(tableName, tableName, 123, false, false);
createStandardWalTable(tableName); createStandardWalTable(tableName);
drainWalQueue(); drainWalQueue();
...@@ -925,9 +925,11 @@ public class WalTableFailureTest extends AbstractCairoTest { ...@@ -925,9 +925,11 @@ public class WalTableFailureTest extends AbstractCairoTest {
compile("alter table " + tableToken.getTableName() + " add column jjj int, column2 long"); compile("alter table " + tableToken.getTableName() + " add column jjj int, column2 long");
Assert.fail(); Assert.fail();
} catch (CairoException ex) { } catch (CairoException ex) {
TestUtils.assertContains(ex.getFlyweightMessage(), TestUtils.assertContains(
ex.getFlyweightMessage(),
"statements containing multiple transactions, such as 'alter table add column col1, col2'" + "statements containing multiple transactions, such as 'alter table add column col1, col2'" +
" are currently not supported for WAL tables"); " are currently not supported for WAL tables"
);
} }
insert("insert into " + tableToken.getTableName() + insert("insert into " + tableToken.getTableName() +
...@@ -1041,8 +1043,10 @@ public class WalTableFailureTest extends AbstractCairoTest { ...@@ -1041,8 +1043,10 @@ public class WalTableFailureTest extends AbstractCairoTest {
engine.getTableSequencerAPI().suspendTable(tableToken); engine.getTableSequencerAPI().suspendTable(tableToken);
Assert.assertTrue(engine.getTableSequencerAPI().isSuspended(tableToken)); Assert.assertTrue(engine.getTableSequencerAPI().isSuspended(tableToken));
assertAlterTableTypeFail("alter table " + tableToken.getTableName() + "ererer resume wal from txn 2", assertAlterTableTypeFail(
"table does not exist [table=" + tableToken.getTableName() + "ererer]"); "alter table " + tableToken.getTableName() + "ererer resume wal from txn 2",
"table does not exist [table=" + tableToken.getTableName() + "ererer]"
);
}); });
} }
......
...@@ -100,9 +100,9 @@ public class WalTableSqlTest extends AbstractCairoTest { ...@@ -100,9 +100,9 @@ public class WalTableSqlTest extends AbstractCairoTest {
drainWalQueue(); drainWalQueue();
assertSql( assertSql(
"x\tsym\tts\tsym2\n" + "x\tsym\tts\tsym2\n" +
"101\ta1a1\t2022-02-24T01:00:00.000000Z\ta2a2\n" + "101\ta1a1\t2022-02-24T01:00:00.000000Z\ta2a2\n" +
"103\tdfd\t2022-02-24T01:00:00.000000Z\tasdd\n" + "103\tdfd\t2022-02-24T01:00:00.000000Z\tasdd\n" +
"102\tbbb\t2022-02-24T02:00:00.000000Z\tccc\n", "102\tbbb\t2022-02-24T02:00:00.000000Z\tccc\n",
tableName tableName
); );
}); });
...@@ -114,12 +114,12 @@ public class WalTableSqlTest extends AbstractCairoTest { ...@@ -114,12 +114,12 @@ public class WalTableSqlTest extends AbstractCairoTest {
String tableName = testName.getMethodName(); String tableName = testName.getMethodName();
ddl( ddl(
"create table " + tableName + " (" + "create table " + tableName + " (" +
"x long," + "x long," +
"sym symbol," + "sym symbol," +
"str string," + "str string," +
"ts timestamp," + "ts timestamp," +
"sym2 symbol" + "sym2 symbol" +
") timestamp(ts) partition by DAY WAL" ") timestamp(ts) partition by DAY WAL"
); );
try (SqlCompiler compiler = engine.getSqlCompiler()) { try (SqlCompiler compiler = engine.getSqlCompiler()) {
...@@ -319,7 +319,7 @@ public class WalTableSqlTest extends AbstractCairoTest { ...@@ -319,7 +319,7 @@ public class WalTableSqlTest extends AbstractCairoTest {
ddl("alter table " + tableName + " set type bypass wal", sqlExecutionContext); ddl("alter table " + tableName + " set type bypass wal", sqlExecutionContext);
engine.releaseInactive(); engine.releaseInactive();
ObjList<TableToken> convertedTables = TableConverter.convertTables(configuration, engine.getTableSequencerAPI()); ObjList<TableToken> convertedTables = TableConverter.convertTables(configuration, engine.getTableSequencerAPI(), engine.getProtectedTableResolver());
engine.reloadTableNames(convertedTables); engine.reloadTableNames(convertedTables);
try (TxWriter tw = new TxWriter(engine.getConfiguration().getFilesFacade(), engine.getConfiguration())) { try (TxWriter tw = new TxWriter(engine.getConfiguration().getFilesFacade(), engine.getConfiguration())) {
...@@ -340,7 +340,7 @@ public class WalTableSqlTest extends AbstractCairoTest { ...@@ -340,7 +340,7 @@ public class WalTableSqlTest extends AbstractCairoTest {
ddl("alter table " + tableName + " set type wal", sqlExecutionContext); ddl("alter table " + tableName + " set type wal", sqlExecutionContext);
engine.releaseInactive(); engine.releaseInactive();
ObjList<TableToken> convertedTables2 = TableConverter.convertTables(configuration, engine.getTableSequencerAPI()); ObjList<TableToken> convertedTables2 = TableConverter.convertTables(configuration, engine.getTableSequencerAPI(), engine.getProtectedTableResolver());
engine.reloadTableNames(convertedTables2); engine.reloadTableNames(convertedTables2);
try (TxWriter tw = new TxWriter(engine.getConfiguration().getFilesFacade(), engine.getConfiguration())) { try (TxWriter tw = new TxWriter(engine.getConfiguration().getFilesFacade(), engine.getConfiguration())) {
...@@ -368,7 +368,7 @@ public class WalTableSqlTest extends AbstractCairoTest { ...@@ -368,7 +368,7 @@ public class WalTableSqlTest extends AbstractCairoTest {
ddl("alter table " + tableName + " add col1 int"); ddl("alter table " + tableName + " add col1 int");
ddl("alter table " + tableName + " set type wal", sqlExecutionContext); ddl("alter table " + tableName + " set type wal", sqlExecutionContext);
engine.releaseInactive(); engine.releaseInactive();
ObjList<TableToken> convertedTables = TableConverter.convertTables(configuration, engine.getTableSequencerAPI()); ObjList<TableToken> convertedTables = TableConverter.convertTables(configuration, engine.getTableSequencerAPI(), engine.getProtectedTableResolver());
engine.reloadTableNames(convertedTables); engine.reloadTableNames(convertedTables);
ddl("alter table " + tableName + " add col2 int"); ddl("alter table " + tableName + " add col2 int");
...@@ -384,17 +384,18 @@ public class WalTableSqlTest extends AbstractCairoTest { ...@@ -384,17 +384,18 @@ public class WalTableSqlTest extends AbstractCairoTest {
ddl("alter table " + tableName + " set type bypass wal"); ddl("alter table " + tableName + " set type bypass wal");
engine.releaseInactive(); engine.releaseInactive();
convertedTables = TableConverter.convertTables(configuration, engine.getTableSequencerAPI()); convertedTables = TableConverter.convertTables(configuration, engine.getTableSequencerAPI(), engine.getProtectedTableResolver());
engine.reloadTableNames(convertedTables); engine.reloadTableNames(convertedTables);
ddl("alter table " + tableName + " drop column col2"); ddl("alter table " + tableName + " drop column col2");
ddl("alter table " + tableName + " add col3 int"); ddl("alter table " + tableName + " add col3 int");
insert("insert into " + tableName + "(ts, col1, col3) values('2022-02-24T01', 3, 4)"); insert("insert into " + tableName + "(ts, col1, col3) values('2022-02-24T01', 3, 4)");
assertSql("ts\tcol1\tcol3\n" + assertSql(
"2022-02-24T00:00:00.000000Z\tNaN\tNaN\n" + "ts\tcol1\tcol3\n" +
"2022-02-24T01:00:00.000000Z\t1\tNaN\n" + "2022-02-24T00:00:00.000000Z\tNaN\tNaN\n" +
"2022-02-24T01:00:00.000000Z\t3\t4\n", "2022-02-24T01:00:00.000000Z\t1\tNaN\n" +
"2022-02-24T01:00:00.000000Z\t3\t4\n",
"select ts, col1, col3 from " + tableName "select ts, col1, col3 from " + tableName
); );
}); });
......
...@@ -396,6 +396,24 @@ public class CharsTest { ...@@ -396,6 +396,24 @@ public class CharsTest {
TestUtils.assertEquals("xyz.txt", extractor.of("xyz.txt")); TestUtils.assertEquals("xyz.txt", extractor.of("xyz.txt"));
} }
@Test
public void testStartsWithIgnoreCase() {
Assert.assertTrue(Chars.startsWithIgnoreCase("", ""));
String[] positive = {"", "a", "ab", "abc"};
for (String s : positive) {
Assert.assertTrue(Chars.startsWithIgnoreCase("abc", s));
Assert.assertTrue(Chars.startsWithIgnoreCase("ABC", s));
Assert.assertTrue(Chars.startsWithIgnoreCase("abc", s.toUpperCase()));
Assert.assertTrue(Chars.startsWithIgnoreCase("ABC", s.toUpperCase()));
}
Assert.assertFalse(Chars.startsWithIgnoreCase("", "abcd"));
Assert.assertFalse(Chars.startsWithIgnoreCase("abc", "abcd"));
Assert.assertFalse(Chars.startsWithIgnoreCase("abc", "ABCD"));
Assert.assertFalse(Chars.startsWithIgnoreCase("ABC", "abcd"));
Assert.assertFalse(Chars.startsWithIgnoreCase("ABC", "ABCD"));
}
@Test @Test
public void testUtf8CharDecode() { public void testUtf8CharDecode() {
long p = Unsafe.malloc(8, MemoryTag.NATIVE_DEFAULT); long p = Unsafe.malloc(8, MemoryTag.NATIVE_DEFAULT);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册