*** /dev/null Fri Nov 22 15:16:09 2024
--- - Fri Nov 22 15:16:19 2024
***************
*** 0 ****
--- 1,409 ----
+ /*
+ ** OSSP uuid - Universally Unique Identifier
+ ** Copyright (c) 2004-2005 Ralf S. Engelschall <rse@engelschall.com>
+ ** Copyright (c) 2004-2005 The OSSP Project <http://www.ossp.org/>
+ **
+ ** This file is part of OSSP uuid, a library for the generation
+ ** of UUIDs which can found at http://www.ossp.org/pkg/lib/uuid/
+ **
+ ** Permission to use, copy, modify, and distribute this software for
+ ** any purpose with or without fee is hereby granted, provided that
+ ** the above copyright notice and this permission notice appear in all
+ ** copies.
+ **
+ ** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ ** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ ** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
+ ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ ** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ ** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ ** SUCH DAMAGE.
+ **
+ ** uuid.c: PostgreSQL Binding (C part)
+ */
+
+ /* PostgreSQL (part 1/2) headers */
+ #include "postgres.h"
+
+ /* system headers */
+ #include <string.h>
+
+ /* PostgreSQL (part 2/2) headers */
+ #include "fmgr.h"
+ #include "lib/stringinfo.h"
+
+ /* own headers */
+ #include "uuid.h"
+
+ /* internal UUID datum data structure */
+ typedef struct {
+ char uuid_bin[UUID_LEN_BIN];
+ } uuid_datum_t;
+
+ /* forward declarations */
+ Datum pg_uuid_in (PG_FUNCTION_ARGS);
+ Datum pg_uuid_out (PG_FUNCTION_ARGS);
+ Datum pg_uuid_recv (PG_FUNCTION_ARGS);
+ Datum pg_uuid_send (PG_FUNCTION_ARGS);
+ Datum pg_uuid_make (PG_FUNCTION_ARGS);
+ Datum pg_uuid_eq (PG_FUNCTION_ARGS);
+ Datum pg_uuid_ne (PG_FUNCTION_ARGS);
+
+ /* API function: uuid_in */
+ PG_FUNCTION_INFO_V1(pg_uuid_in);
+ Datum pg_uuid_in(PG_FUNCTION_ARGS)
+ {
+ char *uuid_str;
+ uuid_datum_t *uuid_datum;
+ uuid_rc_t rc;
+ uuid_t *uuid;
+ void *vp;
+ size_t len;
+
+ /* sanity check input argument */
+ if ((uuid_str = PG_GETARG_CSTRING(0)) == NULL) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("invalid UUID string")));
+ PG_RETURN_NULL();
+ }
+ if ((len = strlen(uuid_str)) != UUID_LEN_STR) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("invalid UUID string length %d (expected %d)", len, UUID_LEN_STR)));
+ PG_RETURN_NULL();
+ }
+
+ /* import as string representation */
+ if ((rc = uuid_create(&uuid)) != UUID_RC_OK) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("failed to create UUID object: %s", uuid_error(rc))));
+ PG_RETURN_NULL();
+ }
+ if ((rc = uuid_import(uuid, UUID_FMT_STR, uuid_str, len)) != UUID_RC_OK) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("failed to import UUID string representation: %s", uuid_error(rc))));
+ uuid_destroy(uuid);
+ PG_RETURN_NULL();
+ }
+
+ /* export as binary representation */
+ if ((uuid_datum = (uuid_datum_t *)palloc(sizeof(uuid_datum_t))) == NULL) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("failed to allocate UUID datum")));
+ uuid_destroy(uuid);
+ PG_RETURN_NULL();
+ }
+ vp = &(uuid_datum->uuid_bin);
+ len = sizeof(uuid_datum->uuid_bin);
+ if ((rc = uuid_export(uuid, UUID_FMT_BIN, &vp, &len)) != UUID_RC_OK) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("failed to export UUID binary representation: %s", uuid_error(rc))));
+ uuid_destroy(uuid);
+ pfree(uuid_datum);
+ PG_RETURN_NULL();
+ }
+ uuid_destroy(uuid);
+
+ /* return UUID datum */
+ PG_RETURN_POINTER(uuid_datum);
+ }
+
+ /* API function: uuid_out */
+ PG_FUNCTION_INFO_V1(pg_uuid_out);
+ Datum pg_uuid_out(PG_FUNCTION_ARGS)
+ {
+ uuid_datum_t *uuid_datum;
+ uuid_rc_t rc;
+ uuid_t *uuid;
+ char *uuid_str;
+ void *vp;
+ size_t len;
+
+ /* sanity check input argument */
+ if ((uuid_datum = (uuid_datum_t *)PG_GETARG_POINTER(0)) == NULL) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("invalid UUID datum")));
+ PG_RETURN_NULL();
+ }
+
+ /* import as binary representation */
+ if ((rc = uuid_create(&uuid)) != UUID_RC_OK) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("failed to create UUID object: %s", uuid_error(rc))));
+ PG_RETURN_NULL();
+ }
+ if ((rc = uuid_import(uuid, UUID_FMT_BIN, uuid_datum->uuid_bin, sizeof(uuid_datum->uuid_bin))) != UUID_RC_OK) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("failed to import UUID binary representation: %s", uuid_error(rc))));
+ uuid_destroy(uuid);
+ PG_RETURN_NULL();
+ }
+
+ /* export as string representation */
+ len = UUID_LEN_STR+1;
+ if ((vp = uuid_str = (char *)palloc(len)) == NULL) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("failed to allocate UUID string")));
+ uuid_destroy(uuid);
+ PG_RETURN_NULL();
+ }
+ if ((rc = uuid_export(uuid, UUID_FMT_STR, &vp, &len)) != UUID_RC_OK) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("failed to export UUID string representation: %s", uuid_error(rc))));
+ uuid_destroy(uuid);
+ pfree(uuid_datum);
+ PG_RETURN_NULL();
+ }
+ uuid_destroy(uuid);
+
+ /* return UUID string */
+ PG_RETURN_CSTRING(uuid_str);
+ }
+
+ /* API function: uuid_recv */
+ PG_FUNCTION_INFO_V1(pg_uuid_recv);
+ Datum pg_uuid_recv(PG_FUNCTION_ARGS)
+ {
+ StringInfo uuid_internal;
+ uuid_datum_t *uuid_datum;
+
+ /* sanity check input argument */
+ if ((uuid_internal = (StringInfo)PG_GETARG_POINTER(0)) == NULL) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("invalid UUID StringInfo object")));
+ PG_RETURN_NULL();
+ }
+ if (uuid_internal->len != UUID_LEN_BIN) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("invalid UUID binary length %d (expected %d)", uuid_internal->len, UUID_LEN_BIN)));
+ PG_RETURN_NULL();
+ }
+
+ /* import as binary representation */
+ if ((uuid_datum = (uuid_datum_t *)palloc(sizeof(uuid_datum_t))) == NULL) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("failed to allocate UUID datum")));
+ PG_RETURN_NULL();
+ }
+ memcpy(uuid_datum->uuid_bin, uuid_internal->data, uuid_internal->len);
+
+ /* return UUID datum */
+ PG_RETURN_POINTER(uuid_datum);
+ }
+
+ /* API function: uuid_send */
+ PG_FUNCTION_INFO_V1(pg_uuid_send);
+ Datum pg_uuid_send(PG_FUNCTION_ARGS)
+ {
+ uuid_datum_t *uuid_datum;
+ bytea *uuid_bytea;
+
+ /* sanity check input argument */
+ if ((uuid_datum = (uuid_datum_t *)PG_GETARG_POINTER(0)) == NULL) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("invalid UUID datum")));
+ PG_RETURN_NULL();
+ }
+
+ /* export as binary representation */
+ if ((uuid_bytea = (bytea *)palloc(VARHDRSZ + UUID_LEN_BIN)) == NULL) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("failed to allocate UUID bytea")));
+ PG_RETURN_NULL();
+ }
+ uuid_bytea->vl_len = VARHDRSZ + UUID_LEN_BIN;
+ memcpy(uuid_bytea->vl_dat, uuid_datum->uuid_bin, UUID_LEN_BIN);
+
+ /* return UUID bytea */
+ PG_RETURN_BYTEA_P(uuid_bytea);
+ }
+
+ /* API function: uuid_make */
+ PG_FUNCTION_INFO_V1(pg_uuid_make);
+ Datum pg_uuid_make(PG_FUNCTION_ARGS)
+ {
+ uuid_t *uuid;
+ uuid_t *uuid_ns;
+ uuid_rc_t rc;
+ int version;
+ unsigned int mode;
+ uuid_datum_t *uuid_datum;
+ char *str_ns;
+ char *str_name;
+ void *vp;
+ size_t len;
+
+ /* sanity check input argument */
+ version = (int)PG_GETARG_INT32(0);
+ switch (version) {
+ case 1: mode = UUID_MAKE_V1; break;
+ case 3: mode = UUID_MAKE_V3; break;
+ case 4: mode = UUID_MAKE_V4; break;
+ case 5: mode = UUID_MAKE_V5; break;
+ default: {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("invalid UUID version %d (expected 1, 3, 4 or 5)", version)));
+ PG_RETURN_NULL();
+ }
+ }
+ if ( ((mode & (UUID_MAKE_V1|UUID_MAKE_V4)) && PG_NARGS() != 1)
+ || ((mode & (UUID_MAKE_V3|UUID_MAKE_V5)) && PG_NARGS() != 3)) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("invalid number (%d) of arguments", PG_NARGS())));
+ PG_RETURN_NULL();
+ }
+
+ /* make a new UUID */
+ if ((rc = uuid_create(&uuid)) != UUID_RC_OK) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("failed to create UUID object: %s", uuid_error(rc))));
+ PG_RETURN_NULL();
+ }
+ if (version == 3 || version == 5) {
+ if ((str_ns = PG_GETARG_CSTRING(1)) == NULL) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("invalid namespace UUID string")));
+ PG_RETURN_NULL();
+ }
+ if ((str_name = PG_GETARG_CSTRING(2)) == NULL) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("invalid name string")));
+ PG_RETURN_NULL();
+ }
+ if ((rc = uuid_create(&uuid_ns)) != UUID_RC_OK) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("failed to create UUID namespace object: %s", uuid_error(rc))));
+ PG_RETURN_NULL();
+ }
+ if ((rc = uuid_load(uuid_ns, str_ns)) != UUID_RC_OK) {
+ if ((rc = uuid_import(uuid_ns, UUID_FMT_STR, str_ns, strlen(str_ns))) != UUID_RC_OK) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("failed to import UUID namespace: %s", uuid_error(rc))));
+ PG_RETURN_NULL();
+ }
+ }
+ if ((rc = uuid_make(uuid, mode, uuid_ns, str_name)) != UUID_RC_OK) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("failed to make v%d UUID: %s", version, uuid_error(rc))));
+ uuid_destroy(uuid);
+ PG_RETURN_NULL();
+ }
+ uuid_destroy(uuid_ns);
+ }
+ else {
+ if ((rc = uuid_make(uuid, mode)) != UUID_RC_OK) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("failed to make v%d UUID: %s", version, uuid_error(rc))));
+ uuid_destroy(uuid);
+ PG_RETURN_NULL();
+ }
+ }
+
+ /* export as binary representation */
+ if ((uuid_datum = (uuid_datum_t *)palloc(sizeof(uuid_datum_t))) == NULL) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("failed to allocate UUID datum")));
+ uuid_destroy(uuid);
+ PG_RETURN_NULL();
+ }
+ vp = &(uuid_datum->uuid_bin);
+ len = sizeof(uuid_datum->uuid_bin);
+ if ((rc = uuid_export(uuid, UUID_FMT_BIN, &vp, &len)) != UUID_RC_OK) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("failed to export UUID binary representation: %s", uuid_error(rc))));
+ uuid_destroy(uuid);
+ pfree(uuid_datum);
+ PG_RETURN_NULL();
+ }
+ uuid_destroy(uuid);
+ PG_RETURN_POINTER(uuid_datum);
+ }
+
+ /* INTERNAL function: _uuid_cmp */
+ static int _uuid_cmp(PG_FUNCTION_ARGS)
+ {
+ uuid_datum_t *uuid_datum1;
+ uuid_datum_t *uuid_datum2;
+ uuid_t *uuid1;
+ uuid_t *uuid2;
+ uuid_rc_t rc;
+ int result;
+
+ /* sanity check input argument */
+ if ((uuid_datum1 = (uuid_datum_t *)PG_GETARG_POINTER(0)) == NULL) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("invalid first UUID datum argument")));
+ PG_RETURN_NULL();
+ }
+ if ((uuid_datum2 = (uuid_datum_t *)PG_GETARG_POINTER(1)) == NULL) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("invalid second UUID datum argument")));
+ PG_RETURN_NULL();
+ }
+
+ /* load both UUIDs */
+ if ((rc = uuid_create(&uuid1)) != UUID_RC_OK) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("failed to create UUID object: %s", uuid_error(rc))));
+ PG_RETURN_NULL();
+ }
+ if ((rc = uuid_create(&uuid2)) != UUID_RC_OK) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("failed to create UUID object: %s", uuid_error(rc))));
+ uuid_destroy(uuid1);
+ PG_RETURN_NULL();
+ }
+ if ((rc = uuid_import(uuid1, UUID_FMT_BIN, uuid_datum1->uuid_bin, sizeof(uuid_datum1->uuid_bin))) != UUID_RC_OK) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("failed to import UUID: %s", uuid_error(rc))));
+ uuid_destroy(uuid1);
+ uuid_destroy(uuid2);
+ PG_RETURN_NULL();
+ }
+ if ((rc = uuid_import(uuid2, UUID_FMT_BIN, uuid_datum2->uuid_bin, sizeof(uuid_datum2->uuid_bin))) != UUID_RC_OK) {
+ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("failed to import UUID: %s", uuid_error(rc))));
+ uuid_destroy(uuid1);
+ uuid_destroy(uuid2);
+ PG_RETURN_NULL();
+ }
+
+ /* compare UUIDs */
+ if ((rc = uuid_compare(uuid1, uuid2, &result)) != UUID_RC_OK) {
+ uuid_destroy(uuid1);
+ uuid_destroy(uuid2);
+ PG_RETURN_NULL();
+ }
+
+ /* cleanup */
+ uuid_destroy(uuid1);
+ uuid_destroy(uuid2);
+
+ /* return result */
+ return result;
+ }
+
+ /* API function: uuid_eq */
+ PG_FUNCTION_INFO_V1(pg_uuid_eq);
+ Datum pg_uuid_eq(PG_FUNCTION_ARGS)
+ {
+ int rc;
+
+ rc = _uuid_cmp(fcinfo);
+ PG_RETURN_BOOL(rc == 0);
+ }
+
+ /* API function: uuid_ne */
+ PG_FUNCTION_INFO_V1(pg_uuid_ne);
+ Datum pg_uuid_ne(PG_FUNCTION_ARGS)
+ {
+ int rc;
+
+ rc = _uuid_cmp(fcinfo);
+ PG_RETURN_BOOL(rc != 0);
+ }
+
|