Last active
July 7, 2023 18:19
-
-
Save utdrmac/168c757144562408976854c50724fe75 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* To compile and install, execute the following commands. This will create a | |
* build location for MySQL and this plugin. | |
* | |
** Get Percona MySQL source code: | |
* cd ~ | |
* wget https://downloads.percona.com/downloads/Percona-Server-8.0/Percona-Server-8.0.32-24/source/tarball/percona-server-8.0.32-24.tar.gz | |
* tar -xvzf percona-server-8.0.32-24.tar.gz | |
* | |
** Create plugin dir, clone C++ ULID library | |
* mkdir ~/percona-server-8.0.32-24/plugin/ulid/ | |
* cd $_ | |
* <This source file, and CMakeLists.txt should be in this path> | |
* git clone https://github.com/ChrisBove/ulid (C++ library) | |
* | |
** Create build location | |
* mkdir /tmp/BUILD_PS | |
* cd $_ | |
* cmake ~/percona-server-8.0.32-24/ -DWITH_BOOST=/tmp/boost -DDOWNLOAD_BOOST=1 -DWITH_AUTHENTICATION_LDAP=OFF | |
* | |
* There may be other libraries missing. Install them as per the output of cmake. | |
* | |
** Build plugin, install, load | |
* cd /tmp/BUILD_PS/plugins/ulid | |
* make | |
* cp /tmp/BUILD_PS/plugin_output_directory/ulid_udf.so /usr/lib/mysql/plugins | |
* mysql -e "CREATE FUNCTION ulid RETURNS STRING SONAME "ulid.so";" | |
* | |
** Test | |
* mysql> SELECT ULID([ms]); | |
* mysql> CREATE TABLE t (id BINARY(16) PRIMARY KEY, name VARCHAR(10) NOT NULL); | |
* mysql> INSERT INTO t VALUES (ULID(), "Alice"), (ULID(), "Bob"), (ULID(), "Charlie"); | |
* | |
*/ | |
#include <stdlib.h> | |
#include <ctype.h> | |
#include <mysql/plugin.h> | |
#define _MSC_VER 0 // Silence a VS Code warning in ulid.hh | |
#define ULID_BINARY_LENGTH 16 | |
#include "ulid/src/ulid.hh" | |
namespace ulid_udf { | |
/** | |
* https://dev.mysql.com/doc/extending-mysql/8.0/en/adding-loadable-function.html | |
* | |
* When an SQL statement invokes XXX(), MySQL calls the initialization function xxx_init() | |
* to let it perform any required setup, such as argument checking or memory allocation. | |
* | |
* If xxx_init() returns an error, MySQL aborts the SQL statement with an error message | |
* and does not call the main or deinitialization functions. Otherwise, MySQL calls the | |
* main function xxx() once for each row. | |
* | |
* After all rows have been processed, MySQL calls the deinitialization function xxx_deinit() | |
* so that it can perform any required cleanup. | |
*/ | |
/* | |
* Init | |
*/ | |
extern "C" bool ulid_init(UDF_INIT *initid, UDF_ARGS *args, char *message) { | |
if (args->arg_count > 1) { | |
strcpy(message, "ULID takes 0 or 1 arguments"); | |
return true; | |
} | |
if (args->arg_count == 1 && args->arg_type[0] != INT_RESULT) { | |
strcpy(message, "Argument 1 must be an integer representing milliseconds"); | |
return true; | |
} | |
initid->max_length = ULID_BINARY_LENGTH; | |
return false; | |
} | |
/* | |
* Main - returns binary ULID | |
*/ | |
extern "C" char *ulid(UDF_INIT *initid [[maybe_unused]], UDF_ARGS *args, char *result, | |
unsigned long *length, unsigned char *is_null, | |
unsigned char *error) { | |
*is_null = 0; | |
ulid::ULID my_ulid = 0; | |
if (args->arg_count == 0) { | |
// Create a ULID using the current time (std::chrono) in nanoseconds | |
ulid::EncodeTimeSystemClockNow(my_ulid); | |
} | |
else if (args->arg_count == 1) { | |
// milliseconds | |
long long ms_seed; | |
ms_seed = *((long long*) args->args[0]); | |
// Encode the provided timestamp | |
std::chrono::system_clock::time_point tp{std::chrono::milliseconds{ms_seed}}; | |
ulid::EncodeTime(tp, my_ulid); | |
} | |
else { | |
*error = 1; | |
return result; | |
} | |
// Add randomness | |
ulid::EncodeEntropyRand(my_ulid); | |
// Marshal ulid to binary array | |
uint8_t dst[16]; | |
ulid::MarshalBinaryTo(my_ulid, dst); | |
// Copy binary array to mysql result pointer and confirm length | |
memcpy(result, dst, ULID_BINARY_LENGTH); | |
*length = ULID_BINARY_LENGTH; | |
return result; | |
} | |
/** | |
* De-init - cleanup memory allocated during init | |
*/ | |
extern "C" void ulid_deinit(UDF_INIT *initid) {} | |
} // namespace ulid_udf |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment