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

Add generateULID function #44662

Merged
merged 9 commits into from
Feb 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,9 @@
[submodule "contrib/libdivide"]
path = contrib/libdivide
url = https://github.com/ridiculousfish/libdivide
[submodule "contrib/ulid-c"]
path = contrib/ulid-c
url = https://github.com/ClickHouse/ulid-c.git
[submodule "contrib/aws-crt-cpp"]
path = contrib/aws-crt-cpp
url = https://github.com/ClickHouse/aws-crt-cpp
Expand Down
2 changes: 2 additions & 0 deletions contrib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ add_contrib (xxHash-cmake xxHash)

add_contrib (google-benchmark-cmake google-benchmark)

add_contrib (ulid-c-cmake ulid-c)

# Put all targets defined here and in subdirectories under "contrib/<immediate-subdir>" folders in GUI-based IDEs.
# Some of third-party projects may override CMAKE_FOLDER or FOLDER property of their targets, so they would not appear
# in "contrib/..." as originally planned, so we workaround this by fixing FOLDER properties of all targets manually,
Expand Down
1 change: 1 addition & 0 deletions contrib/ulid-c
Submodule ulid-c added at c433b6
16 changes: 16 additions & 0 deletions contrib/ulid-c-cmake/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
option (ENABLE_ULID "Enable ulid" ${ENABLE_LIBRARIES})

if (NOT ENABLE_ULID)
message(STATUS "Not using ulid")
return()
endif()

set (LIBRARY_DIR "${ClickHouse_SOURCE_DIR}/contrib/ulid-c")

set (SRCS
"${LIBRARY_DIR}/src/ulid.c"
)

add_library(_ulid ${SRCS})
target_include_directories(_ulid SYSTEM PUBLIC "${LIBRARY_DIR}/include")
add_library(ch_contrib::ulid ALIAS _ulid)
53 changes: 53 additions & 0 deletions docs/en/sql-reference/functions/ulid-functions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
slug: /en/sql-reference/functions/ulid-functions
sidebar_position: 54
sidebar_label: ULID
---

# Functions for Working with ULID

## generateULID

Generates the [ULID](https://github.com/ulid/spec).

**Syntax**

``` sql
generateULID([x])
```

**Arguments**

- `x` — [Expression](../../sql-reference/syntax.md#syntax-expressions) resulting in any of the [supported data types](../../sql-reference/data-types/index.md#data_types). The resulting value is discarded, but the expression itself if used for bypassing [common subexpression elimination](../../sql-reference/functions/index.md#common-subexpression-elimination) if the function is called multiple times in one query. Optional parameter.

**Returned value**

The [FixedString](../data-types/fixedstring.md) type value.

**Usage example**

``` sql
SELECT generateULID()
```

``` text
┌─generateULID()─────────────┐
│ 01GNB2S2FGN2P93QPXDNB4EN2R │
└────────────────────────────┘
```

**Usage example if it is needed to generate multiple values in one row**

```sql
SELECT generateULID(1), generateULID(2)
```

``` text
┌─generateULID(1)────────────┬─generateULID(2)────────────┐
│ 01GNB2SGG4RHKVNT9ZGA4FFMNP │ 01GNB2SGG4V0HMQVH4VBVPSSRB │
└────────────────────────────┴────────────────────────────┘
```

## See Also

- [UUID](../../sql-reference/functions/uuid-functions.md)
4 changes: 4 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,10 @@ if (ENABLE_NLP)
dbms_target_link_libraries (PUBLIC ch_contrib::nlp_data)
endif()

if (TARGET ch_contrib::ulid)
dbms_target_link_libraries (PUBLIC ch_contrib::ulid)
endif()

if (TARGET ch_contrib::bzip2)
target_link_libraries (clickhouse_common_io PRIVATE ch_contrib::bzip2)
endif()
Expand Down
1 change: 1 addition & 0 deletions src/Common/config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,4 @@
#cmakedefine01 USE_BLAKE3
#cmakedefine01 USE_SKIM
#cmakedefine01 USE_OPENSSL_INTREE
#cmakedefine01 USE_ULID
94 changes: 94 additions & 0 deletions src/Functions/generateULID.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#include "config.h"

#if USE_ULID

#include <Columns/ColumnFixedString.h>
#include <DataTypes/DataTypeFixedString.h>
#include <Functions/FunctionFactory.h>
#include <Functions/FunctionHelpers.h>
#include <Functions/IFunction.h>
#include <Interpreters/Context.h>

#include <ulid.h>


namespace DB
{

namespace ErrorCodes
{
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
}

class FunctionGenerateULID : public IFunction
{
public:
static constexpr size_t ULID_LENGTH = 26;

static constexpr auto name = "generateULID";

static FunctionPtr create(ContextPtr /*context*/)
{
return std::make_shared<FunctionGenerateULID>();
}

String getName() const override { return name; }

size_t getNumberOfArguments() const override { return 0; }

bool isVariadic() const override { return true; }
bool isDeterministic() const override { return false; }
bool isDeterministicInScopeOfQuery() const override { return false; }
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }

DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
{
if (arguments.size() > 1)
throw Exception(
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH,
"Number of arguments for function {} doesn't match: passed {}, should be 0 or 1.",
getName(), arguments.size());

return std::make_shared<DataTypeFixedString>(ULID_LENGTH);
}

bool useDefaultImplementationForConstants() const override { return true; }

ColumnPtr executeImpl(const ColumnsWithTypeAndName & /*arguments*/, const DataTypePtr &, size_t input_rows_count) const override
{
auto col_res = ColumnFixedString::create(ULID_LENGTH);
auto & vec_res = col_res->getChars();

vec_res.resize(input_rows_count * ULID_LENGTH);

ulid_generator generator;
ulid_generator_init(&generator, 0);

for (size_t offset = 0, size = vec_res.size(); offset < size; offset += ULID_LENGTH)
ulid_generate(&generator, reinterpret_cast<char *>(&vec_res[offset]));

return col_res;
}
};


REGISTER_FUNCTION(GenerateULID)
{
factory.registerFunction<FunctionGenerateULID>(
{
R"(
Generates a Universally Unique Lexicographically Sortable Identifier (ULID).
This function takes an optional argument, the value of which is discarded to generate different values in case the function is called multiple times.
The function returns a value of type FixedString(26).
)",
Documentation::Examples{
{"ulid", "SELECT generateULID()"},
{"multiple", "SELECT generateULID(1), generateULID(2)"}},
Documentation::Categories{"ULID"}
},
FunctionFactory::CaseSensitive);
}

}

#endif
3 changes: 3 additions & 0 deletions src/configure_config.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ endif()
if (ENABLE_NLP)
set(USE_NLP 1)
endif()
if (TARGET ch_contrib::ulid)
set(USE_ULID 1)
endif()
if (TARGET ch_contrib::llvm)
set(USE_EMBEDDED_COMPILER 1)
endif()
Expand Down
1 change: 1 addition & 0 deletions tests/queries/0_stateless/02515_generate_ulid.reference
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1 FixedString(26)
3 changes: 3 additions & 0 deletions tests/queries/0_stateless/02515_generate_ulid.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-- Tags: no-fasttest

SELECT generateULID(1) != generateULID(2), toTypeName(generateULID());