Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(sql): implement UUID column type #2769

Merged
merged 148 commits into from
Jan 20, 2023
Merged

feat(sql): implement UUID column type #2769

merged 148 commits into from
Jan 20, 2023

Conversation

jerrinot
Copy link
Contributor

@jerrinot jerrinot commented Nov 14, 2022

Motivation
Storing and filtering UUID values is a common QuestDB use-case. Right now QuestDB does not support UUID natively and users typically resort to storing them as Strings. This works, but it's inefficient: UUID in a string column occupies 76 bytes even though it contains just 128 bits (=16 bytes) of information. Also, filtering is slower than it could be - to check a UUID is really matching a predicate, we have to read all these 76 bytes and compare them with a predicate value.

This PR adds a new column type optimized for storing UUID values. They occupy 16 bytes as they should and as a result filtering is also more efficient.

Interface and backward compatibility
This PR adds support to the PGWire protocol, which supports the UUID type too. Example in Java:

UID uuid = UUID.randomUUID();
PreparedStatement ps = connection.prepareStatement("INSERT INTO my_table VALUES (?)");
ps.setObject(1, uuid);

Moreover, a well-formed UUID string can still be inserted into a UUID column - QuestDB will convert it internally. This makes the transition from String to UUID columns smooth as many applications can get benefit from this functionality by just changing a column type from String to UUID.
Example

CREATE TABLE my_table (
    id UUID
);
[...]
INSERT INTO my_table VALUES ('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11');
[...]
SELECT * FROM my_table WHERE id = 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11';

This also works with the ILP ingestion QuestDB ILP clients can
send UUIDs as strings to be converted to UUIDs by the server. Yet we plan to add a new type into ILP to optimize it further.

@jerrinot jerrinot added Java Improvements that update Java code Core Related to storage, data type, etc. labels Nov 14, 2022
@bluestreak01 bluestreak01 changed the title feat(core): introduce UUID column type feat(core): implement UUID column type Jan 17, 2023
@bluestreak01 bluestreak01 changed the title feat(core): implement UUID column type feat(sql): implement UUID column type Jan 17, 2023
there are still cleanups needed, but tests are green locally.
Pushing to run tests on other architecture and to give reviewers
a chance to see how this version looks like. Personally I'm not crazy about it,
the stateful nature of wrappers makes things more complex and difficult
to reason about.
# Conflicts:
#	core/src/main/java/io/questdb/cairo/TableUtils.java
#	core/src/main/java/io/questdb/cairo/map/CompactMapValue.java
#	core/src/main/java/io/questdb/cairo/map/FastMap.java
#	core/src/main/java/io/questdb/cairo/map/FastMapValue.java
#	core/src/main/java/io/questdb/cairo/wal/WalWriter.java
#	core/src/main/java/io/questdb/cairo/wal/WriterRowUtils.java
#	core/src/main/java/io/questdb/griffin/engine/functions/bind/StrBindVariable.java
#	core/src/main/java/io/questdb/griffin/engine/functions/cast/CastLong256ToStrFunctionFactory.java
#	core/src/main/java/io/questdb/std/Hash.java
#	core/src/test/java/io/questdb/cairo/map/FastMapTest.java
#	core/src/test/java/io/questdb/cairo/wal/WalWriterTest.java
set operations never generate casts from UUID to other types
the whole UUID impl assume Long128 and UUID storage is the same.
hence no reason to keep Uuid.BYTES separated
@ideoma
Copy link
Collaborator

ideoma commented Jan 20, 2023

[PR Coverage check]

😍 pass : 918 / 1020 (90.00%)

file detail

path covered line new line coverage
🔵 io/questdb/griffin/engine/functions/FloatFunction.java 0 2 00.00%
🔵 io/questdb/griffin/engine/functions/DateFunction.java 0 2 00.00%
🔵 io/questdb/griffin/engine/functions/ByteFunction.java 0 2 00.00%
🔵 io/questdb/griffin/engine/functions/Long256Function.java 0 2 00.00%
🔵 io/questdb/griffin/engine/functions/BinFunction.java 0 2 00.00%
🔵 io/questdb/griffin/engine/functions/UntypedFunction.java 0 2 00.00%
🔵 io/questdb/griffin/engine/functions/StrFunction.java 0 2 00.00%
🔵 io/questdb/griffin/engine/functions/BooleanFunction.java 0 2 00.00%
🔵 io/questdb/griffin/engine/functions/CharFunction.java 0 2 00.00%
🔵 io/questdb/std/Long128.java 0 1 00.00%
🔵 io/questdb/cairo/vm/NullMemoryMR.java 0 2 00.00%
🔵 io/questdb/griffin/engine/functions/CursorFunction.java 0 2 00.00%
🔵 io/questdb/griffin/engine/functions/DoubleFunction.java 0 2 00.00%
🔵 io/questdb/griffin/engine/functions/SymbolFunction.java 0 2 00.00%
🔵 io/questdb/griffin/engine/functions/LongFunction.java 0 2 00.00%
🔵 io/questdb/cairo/vm/api/NullMemory.java 0 1 00.00%
🔵 io/questdb/griffin/engine/functions/RecordFunction.java 0 2 00.00%
🔵 io/questdb/griffin/engine/functions/ShortFunction.java 0 2 00.00%
🔵 io/questdb/griffin/engine/functions/IntFunction.java 0 2 00.00%
🔵 io/questdb/griffin/engine/functions/TimestampFunction.java 0 2 00.00%
🔵 io/questdb/griffin/engine/functions/AbstractGeoHashFunction.java 0 2 00.00%
🔵 io/questdb/griffin/engine/functions/UuidFunction.java 2 28 07.14%
🔵 io/questdb/griffin/engine/functions/constants/UuidTypeConstant.java 2 4 50.00%
🔵 io/questdb/std/str/StringSink.java 3 6 50.00%
🔵 io/questdb/cairo/sql/PageAddressCacheRecord.java 4 6 66.67%
🔵 io/questdb/griffin/engine/functions/cast/CastStrToUuidFunctionFactory.java 27 33 81.82%
🔵 io/questdb/cairo/TableWriter.java 7 8 87.50%
🔵 io/questdb/griffin/engine/functions/groupby/CountDistinctUuidGroupByFunction.java 38 43 88.37%
🔵 io/questdb/griffin/FunctionParser.java 24 27 88.89%
🔵 io/questdb/cutlass/line/tcp/LineTcpEventBuffer.java 10 11 90.91%
🔵 io/questdb/griffin/engine/functions/conditional/CoalesceFunctionFactory.java 42 46 91.30%
🔵 io/questdb/cutlass/pgwire/PGConnectionContext.java 25 27 92.59%
🔵 io/questdb/griffin/engine/functions/bind/BindVariableServiceImpl.java 27 29 93.10%
🔵 io/questdb/griffin/engine/functions/columns/UuidColumn.java 15 16 93.75%
🔵 io/questdb/griffin/RecordToRowCopierUtils.java 26 27 96.30%
🔵 io/questdb/griffin/engine/functions/eq/UuidEqUtils.java 60 62 96.77%
🔵 io/questdb/std/LongLongHashSet.java 84 85 98.82%
🔵 io/questdb/griffin/engine/functions/groupby/LastUuidGroupByFunction.java 5 5 100.00%
🔵 io/questdb/cairo/vm/api/MemoryCARW.java 4 4 100.00%
🔵 io/questdb/cutlass/line/tcp/LineTcpMeasurementScheduler.java 2 2 100.00%
🔵 io/questdb/cutlass/line/tcp/DefaultColumnTypes.java 1 1 100.00%
🔵 io/questdb/cairo/wal/WalWriterEvents.java 2 2 100.00%
🔵 io/questdb/cairo/wal/WalDataRecord.java 6 6 100.00%
🔵 io/questdb/griffin/engine/groupby/SimpleMapValue.java 6 6 100.00%
🔵 io/questdb/cairo/wal/WalWriter.java 6 6 100.00%
🔵 io/questdb/griffin/engine/functions/groupby/LastUuidGroupByFunctionFactory.java 4 4 100.00%
🔵 io/questdb/cairo/TableUtils.java 1 1 100.00%
🔵 io/questdb/griffin/engine/table/AsyncFilterAtom.java 2 2 100.00%
🔵 io/questdb/std/Hash.java 5 5 100.00%
🔵 io/questdb/griffin/engine/functions/bool/InUuidFunctionFactory.java 42 42 100.00%
🔵 io/questdb/griffin/engine/orderby/LimitedSizeLongTreeChain.java 1 1 100.00%
🔵 io/questdb/griffin/engine/functions/conditional/CaseCommon.java 29 29 100.00%
🔵 io/questdb/griffin/engine/functions/bind/IndexedParameterLinkFunction.java 2 2 100.00%
🔵 io/questdb/griffin/engine/functions/eq/EqUuidFunctionFactory.java 39 39 100.00%
🔵 io/questdb/griffin/engine/functions/eq/EqUuidStrFunctionFactory.java 6 6 100.00%
🔵 io/questdb/cairo/RecordChain.java 2 2 100.00%
🔵 io/questdb/cairo/map/CompactMapRecord.java 2 2 100.00%
🔵 io/questdb/griffin/engine/functions/conditional/UuidCaseFunction.java 7 7 100.00%
🔵 io/questdb/griffin/engine/functions/long128/LongsToLong128FunctionFactory.java 8 8 100.00%
🔵 io/questdb/cairo/ColumnType.java 4 4 100.00%
🔵 io/questdb/cairo/RecordSinkFactory.java 13 13 100.00%
🔵 io/questdb/griffin/FunctionFactoryDescriptor.java 2 2 100.00%
🔵 io/questdb/griffin/engine/union/UnionCastRecord.java 6 6 100.00%
🔵 io/questdb/griffin/ExpressionParser.java 2 2 100.00%
🔵 io/questdb/griffin/engine/functions/str/ConcatFunctionFactory.java 5 5 100.00%
🔵 io/questdb/griffin/engine/groupby/SplitVirtualRecord.java 2 2 100.00%
🔵 io/questdb/cairo/TableReaderSelectedColumnRecord.java 4 4 100.00%
🔵 io/questdb/griffin/engine/union/UnionRecord.java 6 6 100.00%
🔵 io/questdb/griffin/engine/functions/constants/Constants.java 2 2 100.00%
🔵 io/questdb/griffin/engine/functions/bind/StrBindVariable.java 4 4 100.00%
🔵 io/questdb/griffin/engine/functions/constants/UuidConstant.java 11 11 100.00%
🔵 io/questdb/cairo/TableReaderRecord.java 8 8 100.00%
🔵 io/questdb/griffin/engine/functions/catalogue/TypeOfFunctionFactory.java 1 1 100.00%
🔵 io/questdb/griffin/engine/orderby/LongTreeChain.java 1 1 100.00%
🔵 io/questdb/std/Uuid.java 44 44 100.00%
🔵 io/questdb/griffin/JsonPlanSink.java 6 6 100.00%
🔵 io/questdb/griffin/engine/functions/bind/NamedParameterLinkFunction.java 2 2 100.00%
🔵 io/questdb/cutlass/text/types/TypeManager.java 2 2 100.00%
🔵 io/questdb/cutlass/text/CsvFileIndexer.java 1 1 100.00%
🔵 io/questdb/griffin/engine/groupby/GroupByUtils.java 2 2 100.00%
🔵 io/questdb/griffin/engine/functions/eq/EqStrUuidFunctionFactory.java 6 6 100.00%
🔵 io/questdb/griffin/engine/functions/constants/Long128Constant.java 3 3 100.00%
🔵 io/questdb/griffin/engine/functions/bind/UuidBindVariable.java 8 8 100.00%
🔵 io/questdb/std/BytecodeAssembler.java 1 1 100.00%
🔵 io/questdb/cairo/vm/MemoryPARWImpl.java 7 7 100.00%
🔵 io/questdb/griffin/engine/orderby/RecordComparatorCompiler.java 4 4 100.00%
🔵 io/questdb/griffin/engine/functions/cast/CastCharToTimestampFunctionFactory.java 7 7 100.00%
🔵 io/questdb/griffin/engine/functions/cast/CastUuidToStrFunctionFactory.java 23 23 100.00%
🔵 io/questdb/cairo/map/CompactMap.java 2 2 100.00%
🔵 io/questdb/griffin/engine/join/LongChain.java 1 1 100.00%
🔵 io/questdb/griffin/TextPlanSink.java 2 2 100.00%
🔵 io/questdb/griffin/SqlCodeGenerator.java 6 6 100.00%
🔵 io/questdb/cutlass/text/types/UuidAdapter.java 11 11 100.00%
🔵 io/questdb/griffin/engine/functions/eq/EqLong128FunctionFactory.java 2 2 100.00%
🔵 io/questdb/griffin/engine/functions/groupby/FirstUuidGroupByFunctionFactory.java 4 4 100.00%
🔵 io/questdb/std/Numbers.java 30 30 100.00%
🔵 io/questdb/griffin/engine/functions/constants/NullConstant.java 2 2 100.00%
🔵 io/questdb/griffin/engine/functions/rnd/RndUuidFunctionFactory.java 14 14 100.00%
🔵 io/questdb/cutlass/pgwire/PGOids.java 5 5 100.00%
🔵 io/questdb/cutlass/http/processors/JsonQueryProcessorState.java 11 11 100.00%
🔵 io/questdb/cairo/wal/WalEventCursor.java 2 2 100.00%
🔵 io/questdb/cairo/wal/OperationCompiler.java 4 4 100.00%
🔵 io/questdb/cutlass/line/tcp/LineTcpMeasurementEvent.java 7 7 100.00%
🔵 io/questdb/cutlass/http/processors/TextQueryProcessor.java 6 6 100.00%
🔵 io/questdb/griffin/engine/functions/groupby/CountDistinctUuidGroupByFunctionFactory.java 4 4 100.00%
🔵 io/questdb/cairo/map/CompactMapValue.java 6 6 100.00%
🔵 io/questdb/griffin/SqlUtil.java 12 12 100.00%
🔵 io/questdb/cairo/map/FastMapValue.java 6 6 100.00%
🔵 io/questdb/griffin/engine/groupby/SampleByFillNullRecordCursorFactory.java 1 1 100.00%
🔵 io/questdb/griffin/engine/functions/groupby/FirstUuidGroupByFunction.java 15 15 100.00%

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Core Related to storage, data type, etc. Java Improvements that update Java code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants