对于bin、tools部分代码的注释 #33
|
|
@ -23,6 +23,8 @@ declare binarylib_dir='None'
|
|||
declare make_check='off'
|
||||
declare separate_symbol='on'
|
||||
|
||||
# function name: print_help
|
||||
# Note: this function is used to show the command if you forget
|
||||
function print_help()
|
||||
{
|
||||
echo "Usage: $0 [OPTION]
|
||||
|
|
@ -38,6 +40,8 @@ function print_help()
|
|||
"
|
||||
}
|
||||
|
||||
# function name: print_version
|
||||
# Note: this function is used to show the version the user is using
|
||||
function print_version()
|
||||
{
|
||||
echo $(cat ${SCRIPT_DIR}/gaussdb.ver | grep 'VERSION' | awk -F "=" '{print $2}')
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* contrib/adminpack/adminpack--1.0.sql */
|
||||
|
||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
-- check if the script runs in psql, or remind user to use "CREATE EXTENSION adminpack" to run
|
||||
\echo Use "CREATE EXTENSION adminpack" to load this file. \quit
|
||||
|
||||
/* ***********************************************
|
||||
|
|
@ -8,27 +8,31 @@
|
|||
* *********************************************** */
|
||||
|
||||
/* generic file access functions */
|
||||
|
||||
-- check the file whether is coverd
|
||||
CREATE FUNCTION pg_catalog.pg_file_write(text, text, bool)
|
||||
RETURNS bigint
|
||||
AS 'MODULE_PATHNAME', 'pg_file_write'
|
||||
LANGUAGE C VOLATILE STRICT;
|
||||
|
||||
-- change the name of file
|
||||
CREATE FUNCTION pg_catalog.pg_file_rename(text, text, text)
|
||||
RETURNS bool
|
||||
AS 'MODULE_PATHNAME', 'pg_file_rename'
|
||||
LANGUAGE C VOLATILE;
|
||||
|
||||
-- an overloaded version of the definition function
|
||||
CREATE FUNCTION pg_catalog.pg_file_rename(text, text)
|
||||
RETURNS bool
|
||||
AS 'SELECT pg_catalog.pg_file_rename($1, $2, NULL::pg_catalog.text);'
|
||||
LANGUAGE SQL VOLATILE STRICT;
|
||||
|
||||
-- delete the file
|
||||
CREATE FUNCTION pg_catalog.pg_file_unlink(text)
|
||||
RETURNS bool
|
||||
AS 'MODULE_PATHNAME', 'pg_file_unlink'
|
||||
LANGUAGE C VOLATILE STRICT;
|
||||
|
||||
-- list files in the log directory.
|
||||
CREATE FUNCTION pg_catalog.pg_logdir_ls()
|
||||
RETURNS setof record
|
||||
AS 'MODULE_PATHNAME', 'pg_logdir_ls'
|
||||
|
|
@ -37,16 +41,19 @@ LANGUAGE C VOLATILE STRICT;
|
|||
|
||||
/* Renaming of existing backend functions for pgAdmin compatibility */
|
||||
|
||||
-- read the contents of the file
|
||||
CREATE FUNCTION pg_catalog.pg_file_read(text, bigint, bigint)
|
||||
RETURNS text
|
||||
AS 'pg_read_file'
|
||||
LANGUAGE INTERNAL VOLATILE STRICT;
|
||||
|
||||
-- get the size of the file
|
||||
CREATE FUNCTION pg_catalog.pg_file_length(text)
|
||||
RETURNS bigint
|
||||
AS 'SELECT size FROM pg_catalog.pg_stat_file($1)'
|
||||
LANGUAGE SQL VOLATILE STRICT;
|
||||
|
||||
-- manually starting log file rotation.
|
||||
CREATE FUNCTION pg_catalog.pg_logfile_rotate()
|
||||
RETURNS int4
|
||||
AS 'pg_rotate_logfile'
|
||||
|
|
|
|||
|
|
@ -51,8 +51,8 @@ PG_FUNCTION_INFO_V1(pg_file_unlink);
|
|||
PG_FUNCTION_INFO_V1(pg_logdir_ls);
|
||||
|
||||
typedef struct {
|
||||
char* location;
|
||||
DIR* dirdesc;
|
||||
char *location;
|
||||
DIR *dirdesc;
|
||||
} directory_fctx;
|
||||
|
||||
/*-----------------------
|
||||
|
|
@ -65,30 +65,30 @@ typedef struct {
|
|||
* Filename may be absolute or relative to the t_thrd.proc_cxt.DataDir, but we only allow
|
||||
* absolute paths that match t_thrd.proc_cxt.DataDir or u_sess->attr.attr_common.Log_directory.
|
||||
*/
|
||||
static char* convert_and_check_filename(text* arg, bool logAllowed)
|
||||
static char *convert_and_check_filename(text *arg, bool logAllowed)
|
||||
{
|
||||
char* filename = text_to_cstring(arg);
|
||||
char *filename = text_to_cstring(arg);
|
||||
|
||||
canonicalize_path(filename); /* filename can change length here */
|
||||
canonicalize_path(filename); /* May change the length of 'filename' */
|
||||
|
||||
if (is_absolute_path(filename)) {
|
||||
/* Disallow '/a/b/data/..' */
|
||||
if (path_contains_parent_reference(filename))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
(errmsg("reference to parent directory (\"..\") not allowed"))));
|
||||
ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
(errmsg("reference to parent directory (\"..\") not allowed"))));
|
||||
|
||||
/*
|
||||
* Allow absolute paths if within t_thrd.proc_cxt.DataDir or u_sess->attr.attr_common.Log_directory, even
|
||||
* though u_sess->attr.attr_common.Log_directory might be outside t_thrd.proc_cxt.DataDir.
|
||||
* Allow absolute paths if they are within t_thrd.proc_cxt.DataDir or u_sess->attr.attr_common.Log_directory.
|
||||
* However, if 'logAllowed' is false, absolute paths outside u_sess->attr.attr_common.Log_directory are
|
||||
* disallowed.
|
||||
*/
|
||||
if (!path_is_prefix_of_path(t_thrd.proc_cxt.DataDir, filename) &&
|
||||
(!logAllowed || !is_absolute_path(u_sess->attr.attr_common.Log_directory) ||
|
||||
!path_is_prefix_of_path(u_sess->attr.attr_common.Log_directory, filename)))
|
||||
!path_is_prefix_of_path(u_sess->attr.attr_common.Log_directory, filename)))
|
||||
ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("absolute path not allowed"))));
|
||||
} else if (!path_is_relative_and_below_cwd(filename))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("path must be in or below the current directory"))));
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("path must be in or below the current directory"))));
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
|
@ -99,8 +99,9 @@ static char* convert_and_check_filename(text* arg, bool logAllowed)
|
|||
static void requireSuperuser(void)
|
||||
{
|
||||
if (!superuser())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("only system admin may access generic file functions"))));
|
||||
// print the ERROR_REPORT
|
||||
ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
(errmsg("only system admin may access generic file functions"))));
|
||||
}
|
||||
|
||||
/* ------------------------------------
|
||||
|
|
@ -109,56 +110,67 @@ static void requireSuperuser(void)
|
|||
|
||||
Datum pg_file_write(PG_FUNCTION_ARGS)
|
||||
{
|
||||
FILE* f = NULL;
|
||||
char* filename = NULL;
|
||||
text* data = NULL;
|
||||
int64 count = 0;
|
||||
FILE *f = NULL; // File pointer for file operations
|
||||
char *filename = NULL; // File name
|
||||
text *data = NULL; // Data content
|
||||
int64 count = 0; // Number of bytes written
|
||||
|
||||
requireSuperuser();
|
||||
requireSuperuser(); // Check if the current user is a superuser, and raise an error if not
|
||||
|
||||
filename = convert_and_check_filename(PG_GETARG_TEXT_P(0), false);
|
||||
data = PG_GETARG_TEXT_P(1);
|
||||
filename = convert_and_check_filename(PG_GETARG_TEXT_P(0), false); // Get and validate the file name
|
||||
data = PG_GETARG_TEXT_P(1); // Get the data to be written
|
||||
|
||||
if (!PG_GETARG_BOOL(2)) {
|
||||
struct stat fst;
|
||||
|
||||
// Check if the file already exists, and raise an error if it does
|
||||
if (stat(filename, &fst) >= 0)
|
||||
ereport(ERROR, (ERRCODE_DUPLICATE_FILE, errmsg("file \"%s\" exists", filename)));
|
||||
|
||||
// Open the file in write mode
|
||||
f = fopen(filename, "wb");
|
||||
} else
|
||||
} else {
|
||||
// Open the file in append mode
|
||||
f = fopen(filename, "ab");
|
||||
}
|
||||
|
||||
// Check if the file opening is successful, and raise an error if not
|
||||
if (!f)
|
||||
ereport(ERROR, (errcode_for_file_access(), errmsg("could not open file \"%s\" for writing: %m", filename)));
|
||||
|
||||
// If the data content is not empty, write the data to the file
|
||||
if (VARSIZE(data) != 0) {
|
||||
// Write the data content to the file and record the number of bytes written
|
||||
count = fwrite(VARDATA(data), 1, VARSIZE(data) - VARHDRSZ, f);
|
||||
|
||||
// Check if the write operation is successful, and raise an error if not
|
||||
if (count != VARSIZE(data) - VARHDRSZ)
|
||||
ereport(ERROR, (errcode_for_file_access(), errmsg("could not write file \"%s\": %m", filename)));
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
fclose(f); // Close the file
|
||||
|
||||
// Return the number of bytes successfully written
|
||||
PG_RETURN_INT64(count);
|
||||
}
|
||||
|
||||
Datum pg_file_rename(PG_FUNCTION_ARGS)
|
||||
{
|
||||
char *fn1, *fn2, *fn3;
|
||||
int rc;
|
||||
char *fn1, *fn2, *fn3; // File name variables
|
||||
int rc; // Return code for access operation
|
||||
|
||||
requireSuperuser();
|
||||
requireSuperuser(); // Check if the current user is a superuser, and raise an error if not
|
||||
|
||||
if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
|
||||
PG_RETURN_NULL();
|
||||
|
||||
fn1 = convert_and_check_filename(PG_GETARG_TEXT_P(0), false);
|
||||
fn2 = convert_and_check_filename(PG_GETARG_TEXT_P(1), false);
|
||||
fn1 = convert_and_check_filename(PG_GETARG_TEXT_P(0), false); // Get and validate the source file name
|
||||
fn2 = convert_and_check_filename(PG_GETARG_TEXT_P(1), false); // Get and validate the destination file name
|
||||
|
||||
if (PG_ARGISNULL(2))
|
||||
fn3 = 0;
|
||||
else
|
||||
fn3 = convert_and_check_filename(PG_GETARG_TEXT_P(2), false);
|
||||
fn3 = convert_and_check_filename(PG_GETARG_TEXT_P(2), false); // Get and validate the backup file name
|
||||
|
||||
if (access(fn1, W_OK) < 0) {
|
||||
ereport(WARNING, (errcode_for_file_access(), errmsg("file \"%s\" is not accessible: %m", fn1)));
|
||||
|
|
@ -172,7 +184,7 @@ Datum pg_file_rename(PG_FUNCTION_ARGS)
|
|||
PG_RETURN_BOOL(false);
|
||||
}
|
||||
|
||||
rc = access(fn3 ? fn3 : fn2, 2);
|
||||
rc = access(fn3 ? fn3 : fn2, 2); // Check if the target file exists
|
||||
if (rc >= 0 || errno != ENOENT) {
|
||||
ereport(ERROR, (ERRCODE_DUPLICATE_FILE, errmsg("cannot rename to target file \"%s\"", fn3 ? fn3 : fn2)));
|
||||
}
|
||||
|
|
@ -185,8 +197,8 @@ Datum pg_file_rename(PG_FUNCTION_ARGS)
|
|||
ereport(WARNING, (errcode_for_file_access(), errmsg("could not rename \"%s\" to \"%s\": %m", fn1, fn2)));
|
||||
|
||||
if (rename(fn3, fn2) != 0) {
|
||||
ereport(
|
||||
ERROR, (errcode_for_file_access(), errmsg("could not rename \"%s\" back to \"%s\": %m", fn3, fn2)));
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(), errmsg("could not rename \"%s\" back to \"%s\": %m", fn3, fn2)));
|
||||
} else {
|
||||
ereport(ERROR, (ERRCODE_UNDEFINED_FILE, errmsg("renaming \"%s\" to \"%s\" was reverted", fn2, fn3)));
|
||||
}
|
||||
|
|
@ -200,111 +212,116 @@ Datum pg_file_rename(PG_FUNCTION_ARGS)
|
|||
|
||||
Datum pg_file_unlink(PG_FUNCTION_ARGS)
|
||||
{
|
||||
char* filename = NULL;
|
||||
char *filename = NULL; // File name variable
|
||||
|
||||
requireSuperuser();
|
||||
requireSuperuser(); // Check if the current user is a superuser, and raise an error if not
|
||||
|
||||
filename = convert_and_check_filename(PG_GETARG_TEXT_P(0), false);
|
||||
filename = convert_and_check_filename(PG_GETARG_TEXT_P(0), false); // Get and validate the file name
|
||||
|
||||
if (access(filename, W_OK) < 0) {
|
||||
if (errno == ENOENT)
|
||||
PG_RETURN_BOOL(false);
|
||||
PG_RETURN_BOOL(false); // Return false if the file does not exist
|
||||
else
|
||||
ereport(ERROR, (errcode_for_file_access(), errmsg("file \"%s\" is not accessible: %m", filename)));
|
||||
// Raise an error if the file is not accessible
|
||||
}
|
||||
|
||||
if (unlink(filename) < 0) {
|
||||
ereport(WARNING, (errcode_for_file_access(), errmsg("could not unlink file \"%s\": %m", filename)));
|
||||
// Raise a warning with an error code if the file unlinking fails
|
||||
|
||||
PG_RETURN_BOOL(false);
|
||||
PG_RETURN_BOOL(false); // Return false indicating the unlinking operation failed
|
||||
}
|
||||
PG_RETURN_BOOL(true);
|
||||
|
||||
PG_RETURN_BOOL(true); // Return true to indicate a successful unlinking operation
|
||||
}
|
||||
|
||||
Datum pg_logdir_ls(PG_FUNCTION_ARGS)
|
||||
{
|
||||
FuncCallContext* funcctx = NULL;
|
||||
struct dirent* de;
|
||||
directory_fctx* fctx = NULL;
|
||||
FuncCallContext *funcctx = NULL; // Function call context
|
||||
struct dirent *de; // Directory entry
|
||||
directory_fctx *fctx = NULL; // Directory context
|
||||
|
||||
if (!superuser())
|
||||
ereport(
|
||||
ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("only system admin can list the log directory"))));
|
||||
|
||||
ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("only system admin can list the log directory"))));
|
||||
|
||||
if (strcmp(u_sess->attr.attr_common.Log_filename, "postgresql-%Y-%m-%d_%H%M%S.log") != 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
(errmsg("the log_filename parameter must equal 'postgresql-%%Y-%%m-%%d_%%H%%M%%S.log'"))));
|
||||
|
||||
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
(errmsg("the log_filename parameter must equal 'postgresql-%%Y-%%m-%%d_%%H%%M%%S.log'"))));
|
||||
|
||||
if (SRF_IS_FIRSTCALL()) {
|
||||
MemoryContext oldcontext;
|
||||
TupleDesc tupdesc;
|
||||
|
||||
|
||||
/* Initialize function call context and memory */
|
||||
funcctx = SRF_FIRSTCALL_INIT();
|
||||
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
||||
|
||||
fctx = (directory_fctx*)palloc(sizeof(directory_fctx));
|
||||
|
||||
|
||||
fctx = (directory_fctx *)palloc(sizeof(directory_fctx));
|
||||
|
||||
/* Create tuple descriptor */
|
||||
tupdesc = CreateTemplateTupleDesc(2, false);
|
||||
TupleDescInitEntry(tupdesc, (AttrNumber)1, "starttime", TIMESTAMPOID, -1, 0);
|
||||
TupleDescInitEntry(tupdesc, (AttrNumber)2, "filename", TEXTOID, -1, 0);
|
||||
|
||||
|
||||
funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
|
||||
|
||||
|
||||
fctx->location = pstrdup(u_sess->attr.attr_common.Log_directory);
|
||||
fctx->dirdesc = AllocateDir(fctx->location);
|
||||
|
||||
|
||||
if (!fctx->dirdesc)
|
||||
ereport(ERROR, (errcode_for_file_access(), errmsg("could not read directory \"%s\": %m", fctx->location)));
|
||||
|
||||
|
||||
funcctx->user_fctx = fctx;
|
||||
(void)MemoryContextSwitchTo(oldcontext);
|
||||
}
|
||||
|
||||
|
||||
/* Set up the function call context and directory context */
|
||||
funcctx = SRF_PERCALL_SETUP();
|
||||
fctx = (directory_fctx*)funcctx->user_fctx;
|
||||
|
||||
fctx = (directory_fctx *)funcctx->user_fctx;
|
||||
|
||||
/* Loop through directory entries */
|
||||
while ((de = ReadDir(fctx->dirdesc, fctx->location)) != NULL) {
|
||||
char* values[2];
|
||||
char *values[2];
|
||||
HeapTuple tuple;
|
||||
char timestampbuf[32];
|
||||
char* field[MAXDATEFIELDS];
|
||||
char *field[MAXDATEFIELDS];
|
||||
char lowstr[MAXDATELEN + 1];
|
||||
int dtype;
|
||||
int nf, ftype[MAXDATEFIELDS];
|
||||
fsec_t fsec;
|
||||
int tz = 0;
|
||||
struct pg_tm date;
|
||||
|
||||
|
||||
/*
|
||||
* Default format: postgresql-YYYY-MM-DD_HHMMSS.log
|
||||
*/
|
||||
if (strlen(de->d_name) != 32 || strncmp(de->d_name, "postgresql-", 11) != 0 || de->d_name[21] != '_' ||
|
||||
strcmp(de->d_name + 28, ".log") != 0)
|
||||
if (strlen(de->d_name) != 32 || strncmp(de->d_name, "postgresql-", 11) != 0 ||
|
||||
de->d_name[21] != '_' || strcmp(de->d_name + 28, ".log") != 0)
|
||||
continue;
|
||||
|
||||
/* extract timestamp portion of filename */
|
||||
|
||||
/* Extract timestamp portion of filename */
|
||||
strcpy(timestampbuf, de->d_name + 11);
|
||||
timestampbuf[17] = '\0';
|
||||
|
||||
/* parse and decode expected timestamp to verify it's OK format */
|
||||
|
||||
/* Parse and decode expected timestamp to verify it's a valid format */
|
||||
if (ParseDateTime(timestampbuf, lowstr, MAXDATELEN, field, ftype, MAXDATEFIELDS, &nf))
|
||||
continue;
|
||||
|
||||
|
||||
if (DecodeDateTime(field, ftype, nf, &dtype, &date, &fsec, &tz))
|
||||
continue;
|
||||
|
||||
/* Seems the timestamp is OK; prepare and return tuple */
|
||||
|
||||
|
||||
/* Timestamp is valid; prepare and return tuple */
|
||||
values[0] = timestampbuf;
|
||||
values[1] = (char*)palloc(strlen(fctx->location) + strlen(de->d_name) + 2);
|
||||
values[1] = (char *)palloc(strlen(fctx->location) + strlen(de->d_name) + 2);
|
||||
sprintf(values[1], "%s/%s", fctx->location, de->d_name);
|
||||
|
||||
|
||||
tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
|
||||
|
||||
|
||||
SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
|
||||
}
|
||||
|
||||
|
||||
/* Clean up and return */
|
||||
FreeDir(fctx->dirdesc);
|
||||
SRF_RETURN_DONE(funcctx);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ void _PG_init(void)
|
|||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
// Define common Boolean variables
|
||||
DefineCustomBoolVariable("auto_explain.log_analyze",
|
||||
"Use EXPLAIN ANALYZE for plan logging.",
|
||||
NULL,
|
||||
|
|
@ -84,6 +84,7 @@ void _PG_init(void)
|
|||
NULL,
|
||||
NULL);
|
||||
|
||||
// Define common Boolean variables of auto_explain.log_verbose
|
||||
DefineCustomBoolVariable("auto_explain.log_verbose",
|
||||
"Use EXPLAIN VERBOSE for plan logging.",
|
||||
NULL,
|
||||
|
|
@ -95,6 +96,7 @@ void _PG_init(void)
|
|||
NULL,
|
||||
NULL);
|
||||
|
||||
// Define common Boolean variables of auto_explain.log_buffers
|
||||
DefineCustomBoolVariable("auto_explain.log_buffers",
|
||||
"Log buffers usage.",
|
||||
NULL,
|
||||
|
|
|
|||
|
|
@ -87,10 +87,13 @@ static GBT_VARKEY* gbt_bit_l2n(GBT_VARKEY* leaf)
|
|||
static const gbtree_vinfo tinfo = {
|
||||
gbt_t_bit, 0, TRUE, gbt_bitgt, gbt_bitge, gbt_biteq, gbt_bitle, gbt_bitlt, gbt_bitcmp, gbt_bit_l2n};
|
||||
|
||||
/**************************************************
|
||||
* Bit ops
|
||||
**************************************************/
|
||||
|
||||
/*
|
||||
* This function compresses a GIST entry using variable-length bitstrings.
|
||||
* The input is a pointer to a GISTENTRY struct.
|
||||
* The output is a pointer to the compressed data, which is obtained by calling
|
||||
* the gbt_var_compress function with the GISTENTRY pointer and a pointer to
|
||||
* the tinfo struct.
|
||||
*/
|
||||
Datum gbt_bit_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
|
|
@ -98,6 +101,20 @@ Datum gbt_bit_compress(PG_FUNCTION_ARGS)
|
|||
PG_RETURN_POINTER(gbt_var_compress(entry, &tinfo));
|
||||
}
|
||||
|
||||
/*
|
||||
* This function checks if a GIST entry is consistent with a query using
|
||||
* variable-length bitstrings. The input is a pointer to a GISTENTRY struct,
|
||||
* a pointer to the query data, and a strategy number. The output is a boolean
|
||||
* value indicating whether the entry is consistent with the query.
|
||||
*
|
||||
* The function also sets a flag indicating whether a recheck is needed, but
|
||||
* this flag is always set to false for all cases served by this function.
|
||||
*
|
||||
* If the entry is a leaf node, the function calls gbt_var_consistent with
|
||||
* the readable key of the entry and the query data. Otherwise, the function
|
||||
* transforms the query data using gbt_bit_xfrm and calls gbt_var_consistent
|
||||
* with the readable key of the entry and the transformed query data.
|
||||
*/
|
||||
Datum gbt_bit_consistent(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
|
|
@ -122,6 +139,15 @@ Datum gbt_bit_consistent(PG_FUNCTION_ARGS)
|
|||
PG_RETURN_BOOL(retval);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function performs a union of a set of GIST entries using
|
||||
* variable-length bitstrings. The input is a pointer to a GistEntryVector
|
||||
* struct and a pointer to an integer that will hold the size of the resulting
|
||||
* union. The output is a pointer to the union of the entries.
|
||||
*
|
||||
* The function calls gbt_var_union with the GistEntryVector, the collation,
|
||||
* and a pointer to the tinfo struct.
|
||||
*/
|
||||
Datum gbt_bit_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector* entryvec = (GistEntryVector*)PG_GETARG_POINTER(0);
|
||||
|
|
@ -130,6 +156,16 @@ Datum gbt_bit_union(PG_FUNCTION_ARGS)
|
|||
PG_RETURN_POINTER(gbt_var_union(entryvec, size, PG_GET_COLLATION(), &tinfo));
|
||||
}
|
||||
|
||||
/*
|
||||
* This function performs a picksplit operation on a set of GIST entries using
|
||||
* variable-length bitstrings. The input is a pointer to a GistEntryVector
|
||||
* struct and a pointer to a GIST_SPLITVEC struct that will hold the results
|
||||
* of the picksplit operation. The output is a pointer to the GIST_SPLITVEC
|
||||
* struct.
|
||||
*
|
||||
* The function calls gbt_var_picksplit with the GistEntryVector, the GIST_SPLITVEC
|
||||
* struct, the collation, and a pointer to the tinfo struct.
|
||||
*/
|
||||
Datum gbt_bit_picksplit(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector* entryvec = (GistEntryVector*)PG_GETARG_POINTER(0);
|
||||
|
|
@ -139,6 +175,16 @@ Datum gbt_bit_picksplit(PG_FUNCTION_ARGS)
|
|||
PG_RETURN_POINTER(v);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function checks if two variable-length bitstrings are the same. The input
|
||||
* is two Datums representing the bitstrings and a pointer to a boolean variable
|
||||
* that will hold the result of the comparison. The output is a pointer to the
|
||||
* boolean variable.
|
||||
*
|
||||
* The function calls gbt_var_same with the two Datums, the collation, and a
|
||||
* pointer to the tinfo struct. The result of the comparison is stored in the
|
||||
* boolean variable pointed to by the input argument.
|
||||
*/
|
||||
Datum gbt_bit_same(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum d1 = PG_GETARG_DATUM(0);
|
||||
|
|
|
|||
|
|
@ -1,43 +1,43 @@
|
|||
/*
|
||||
* contrib/btree_gist/btree_gist.c
|
||||
*/
|
||||
#include "postgres.h"
|
||||
#include "knl/knl_variable.h"
|
||||
|
||||
#include "btree_gist.h"
|
||||
|
||||
PG_MODULE_MAGIC;
|
||||
|
||||
PG_FUNCTION_INFO_V1(gbt_decompress);
|
||||
PG_FUNCTION_INFO_V1(gbtreekey_in);
|
||||
PG_FUNCTION_INFO_V1(gbtreekey_out);
|
||||
|
||||
extern "C" Datum gbt_decompress(PG_FUNCTION_ARGS);
|
||||
|
||||
/**************************************************
|
||||
* In/Out for keys
|
||||
**************************************************/
|
||||
|
||||
Datum gbtreekey_in(PG_FUNCTION_ARGS)
|
||||
{
|
||||
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("<datatype>key_in() not implemented")));
|
||||
|
||||
PG_RETURN_POINTER(NULL);
|
||||
}
|
||||
|
||||
#include "btree_utils_var.h"
|
||||
#include "utils/builtins.h"
|
||||
Datum gbtreekey_out(PG_FUNCTION_ARGS)
|
||||
{
|
||||
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("<datatype>key_out() not implemented")));
|
||||
PG_RETURN_POINTER(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
** GiST DeCompress methods
|
||||
** do not do anything.
|
||||
*/
|
||||
Datum gbt_decompress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_POINTER(PG_GETARG_POINTER(0));
|
||||
}
|
||||
/*
|
||||
* contrib/btree_gist/btree_gist.c
|
||||
*/
|
||||
#include "postgres.h" // Include the PostgreSQL database header file
|
||||
#include "knl/knl_variable.h" // Include the knl_variable.h header file, which may contain internal variable definitions
|
||||
|
||||
#include "btree_gist.h" // Include the btree_gist.h header file, which defines the data structures and function prototypes required for B-tree GiST indexing
|
||||
|
||||
PG_MODULE_MAGIC; // Macro definition to identify this as a PostgreSQL module
|
||||
|
||||
PG_FUNCTION_INFO_V1(gbt_decompress); // Macro definition to declare a PostgreSQL function, gbt_decompress, with version 1 information
|
||||
PG_FUNCTION_INFO_V1(gbtreekey_in); // Macro definition to declare a PostgreSQL function, gbtreekey_in, with version 1 information
|
||||
PG_FUNCTION_INFO_V1(gbtreekey_out); // Macro definition to declare a PostgreSQL function, gbtreekey_out, with version 1 information
|
||||
|
||||
extern "C" Datum gbt_decompress(PG_FUNCTION_ARGS); // Define a C function named gbt_decompress that returns a Datum type and accepts PG_FUNCTION_ARGS parameters
|
||||
|
||||
/**************************************************
|
||||
* In/Out for keys
|
||||
**************************************************/
|
||||
|
||||
Datum gbtreekey_in(PG_FUNCTION_ARGS) // Define a function named gbtreekey_in that returns a Datum type and accepts PG_FUNCTION_ARGS parameters
|
||||
{
|
||||
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("<datatype>key_in() not implemented"))); // If the function is called, output an error message indicating that the feature is not supported
|
||||
|
||||
PG_RETURN_POINTER(NULL); // Return a null pointer, indicating that there is no return value
|
||||
}
|
||||
|
||||
#include "btree_utils_var.h" // Include the btree_utils_var.h header file, which may contain auxiliary functions and variables related to B-trees
|
||||
#include "utils/builtins.h" // Include the builtins.h header file, which may contain definitions related to built-in functions
|
||||
Datum gbtreekey_out(PG_FUNCTION_ARGS) // Define the gbtreekey_out function, which converts internal keys to output form and returns a Datum type result
|
||||
{
|
||||
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("<datatype>key_out() not implemented"))); // If the function is called, output an error message indicating that the feature is not supported
|
||||
PG_RETURN_POINTER(NULL); // Return a null pointer, indicating that there is no return value
|
||||
}
|
||||
|
||||
/*
|
||||
** GiST DeCompress methods
|
||||
** do not do anything.
|
||||
*/
|
||||
Datum gbt_decompress(PG_FUNCTION_ARGS) // Define the gbt_decompress function, which decompresses GiST keys and returns a Datum type result
|
||||
{
|
||||
PG_RETURN_POINTER(PG_GETARG_POINTER(0)); // Directly return the pointer to the input argument as the result, without performing any decompression operations
|
||||
}
|
||||
|
|
@ -138,6 +138,17 @@ Datum gbt_inet_picksplit(PG_FUNCTION_ARGS)
|
|||
gbt_num_picksplit((GistEntryVector*)PG_GETARG_POINTER(0), (GIST_SPLITVEC*)PG_GETARG_POINTER(1), &tinfo));
|
||||
}
|
||||
|
||||
/*
|
||||
function name: gbt_inet_same
|
||||
description:
|
||||
This function checks whether two inet keys are equal. The input is two
|
||||
inetKEY pointers representing the keys to compare, and a pointer to a boolean
|
||||
to hold the result. The output is a pointer to the boolean result.
|
||||
The function calls gbt_num_same with the two keys and a pointer to the tinfo
|
||||
struct. The result of the comparison is stored in the result pointer and
|
||||
returned.
|
||||
|
||||
*/
|
||||
Datum gbt_inet_same(PG_FUNCTION_ARGS)
|
||||
{
|
||||
inetKEY* b1 = (inetKEY*)PG_GETARG_POINTER(0);
|
||||
|
|
|
|||
|
|
@ -132,6 +132,21 @@ Datum gbt_int2_consistent(PG_FUNCTION_ARGS)
|
|||
PG_RETURN_BOOL(gbt_num_consistent(&key, (void*)&query, &strategy, GIST_LEAF(entry), &tinfo));
|
||||
}
|
||||
|
||||
/*
|
||||
function name: gbt_int2_distance
|
||||
description:
|
||||
This function calculates the distance between an int2 key and a query value.
|
||||
The input is a GISTENTRY pointer representing the key, and an int16 value
|
||||
representing the query. The output is a float8 value representing the
|
||||
distance between the key and the query.
|
||||
|
||||
The function extracts the lower and upper bounds of the int2 key and stores
|
||||
them in a GBT_NUMKEY_R struct. It then calls gbt_num_distance with the key,
|
||||
the query value, a boolean indicating whether the key is a leaf node, and a
|
||||
pointer to the tinfo struct. The result of the distance calculation is
|
||||
returned as a float8 value.
|
||||
|
||||
*/
|
||||
Datum gbt_int2_distance(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
|
|
@ -172,6 +187,18 @@ Datum gbt_int2_picksplit(PG_FUNCTION_ARGS)
|
|||
gbt_num_picksplit((GistEntryVector*)PG_GETARG_POINTER(0), (GIST_SPLITVEC*)PG_GETARG_POINTER(1), &tinfo));
|
||||
}
|
||||
|
||||
/*
|
||||
function name: gbt_int2_same
|
||||
description:
|
||||
This function checks whether two int2 keys are the same.
|
||||
The input is two pointers to int16KEY structs representing the keys,
|
||||
and a pointer to a boolean variable to store the result.
|
||||
The output is a pointer to the boolean variable.
|
||||
|
||||
The function calls gbt_num_same with the two keys, and a pointer to the tinfo
|
||||
struct. The result of the comparison is stored in the boolean variable
|
||||
pointed to by the result argument, and a pointer to this variable is returned.
|
||||
*/
|
||||
Datum gbt_int2_same(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int16KEY* b1 = (int16KEY*)PG_GETARG_POINTER(0);
|
||||
|
|
|
|||
|
|
@ -15,169 +15,211 @@ typedef struct int32key {
|
|||
/*
|
||||
** int32 ops
|
||||
*/
|
||||
PG_FUNCTION_INFO_V1(gbt_int4_compress);
|
||||
PG_FUNCTION_INFO_V1(gbt_int4_union);
|
||||
PG_FUNCTION_INFO_V1(gbt_int4_picksplit);
|
||||
PG_FUNCTION_INFO_V1(gbt_int4_consistent);
|
||||
PG_FUNCTION_INFO_V1(gbt_int4_distance);
|
||||
PG_FUNCTION_INFO_V1(gbt_int4_penalty);
|
||||
PG_FUNCTION_INFO_V1(gbt_int4_same);
|
||||
|
||||
extern "C" Datum gbt_int4_compress(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gbt_int4_union(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gbt_int4_picksplit(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gbt_int4_consistent(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gbt_int4_distance(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gbt_int4_penalty(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gbt_int4_same(PG_FUNCTION_ARGS);
|
||||
|
||||
static bool gbt_int4gt(const void* a, const void* b)
|
||||
{
|
||||
return (*((const int32*)a) > *((const int32*)b));
|
||||
}
|
||||
static bool gbt_int4ge(const void* a, const void* b)
|
||||
{
|
||||
return (*((const int32*)a) >= *((const int32*)b));
|
||||
}
|
||||
static bool gbt_int4eq(const void* a, const void* b)
|
||||
{
|
||||
return (*((const int32*)a) == *((const int32*)b));
|
||||
}
|
||||
static bool gbt_int4le(const void* a, const void* b)
|
||||
{
|
||||
return (*((const int32*)a) <= *((const int32*)b));
|
||||
}
|
||||
static bool gbt_int4lt(const void* a, const void* b)
|
||||
{
|
||||
return (*((const int32*)a) < *((const int32*)b));
|
||||
// Define a set of function info macros for the different GiST functions.
|
||||
PG_FUNCTION_INFO_V1(gbt_int4_compress); // Compress function for GiST index.
|
||||
PG_FUNCTION_INFO_V1(gbt_int4_union); // Union function for GiST index.
|
||||
PG_FUNCTION_INFO_V1(gbt_int4_picksplit); // Picksplit function for GiST index.
|
||||
PG_FUNCTION_INFO_V1(gbt_int4_consistent);// Consistent function for GiST index.
|
||||
PG_FUNCTION_INFO_V1(gbt_int4_distance); // Distance function for GiST index.
|
||||
PG_FUNCTION_INFO_V1(gbt_int4_penalty); // Penalty function for GiST index.
|
||||
PG_FUNCTION_INFO_V1(gbt_int4_same); // Same function for GiST index.
|
||||
|
||||
// Declare the different GiST functions.
|
||||
extern "C" Datum gbt_int4_compress(PG_FUNCTION_ARGS); // Compress function.
|
||||
extern "C" Datum gbt_int4_union(PG_FUNCTION_ARGS); // Union function.
|
||||
extern "C" Datum gbt_int4_picksplit(PG_FUNCTION_ARGS); // Picksplit function.
|
||||
extern "C" Datum gbt_int4_consistent(PG_FUNCTION_ARGS);// Consistent function.
|
||||
extern "C" Datum gbt_int4_distance(PG_FUNCTION_ARGS); // Distance function.
|
||||
extern "C" Datum gbt_int4_penalty(PG_FUNCTION_ARGS); // Penalty function.
|
||||
extern "C" Datum gbt_int4_same(PG_FUNCTION_ARGS); // Same function.
|
||||
|
||||
// Define a set of comparison functions for integers.
|
||||
static bool gbt_int4gt(const void* a, const void* b) // Greater than comparison.
|
||||
{
|
||||
return (*((const int32*)a) > *((const int32*)b));
|
||||
}
|
||||
static bool gbt_int4ge(const void* a, const void* b) // Greater than or equal to comparison.
|
||||
{
|
||||
return (*((const int32*)a) >= *((const int32*)b));
|
||||
}
|
||||
static bool gbt_int4eq(const void* a, const void* b) // Equal to comparison.
|
||||
{
|
||||
return (*((const int32*)a) == *((const int32*)b));
|
||||
}
|
||||
static bool gbt_int4le(const void* a, const void* b) // Less than or equal to comparison.
|
||||
{
|
||||
return (*((const int32*)a) <= *((const int32*)b));
|
||||
}
|
||||
static bool gbt_int4lt(const void* a, const void* b) // Less than comparison.
|
||||
{
|
||||
return (*((const int32*)a) < *((const int32*)b));
|
||||
}
|
||||
|
||||
static int gbt_int4key_cmp(const void* a, const void* b)
|
||||
{
|
||||
int32KEY* ia = (int32KEY*)(((const Nsrt*)a)->t);
|
||||
int32KEY* ib = (int32KEY*)(((const Nsrt*)b)->t);
|
||||
|
||||
if (ia->lower == ib->lower) {
|
||||
if (ia->upper == ib->upper)
|
||||
return 0;
|
||||
|
||||
return (ia->upper > ib->upper) ? 1 : -1;
|
||||
}
|
||||
|
||||
return (ia->lower > ib->lower) ? 1 : -1;
|
||||
// Define a function that compares two integer keys.
|
||||
static int gbt_int4key_cmp(const void* a, const void* b)
|
||||
{
|
||||
// Cast the input pointers to their actual types.
|
||||
int32KEY* ia = (int32KEY*)(((const Nsrt*)a)->t);
|
||||
int32KEY* ib = (int32KEY*)(((const Nsrt*)b)->t);
|
||||
|
||||
// Compare the lower bounds first. If they are equal...
|
||||
if (ia->lower == ib->lower) {
|
||||
// Compare the upper bounds. If they are equal...
|
||||
if (ia->upper == ib->upper)
|
||||
return 0; // Return 0 if both are equal.
|
||||
|
||||
// Return 1 or -1 depending on which upper bound is greater.
|
||||
return (ia->upper > ib->upper) ? 1 : -1;
|
||||
}
|
||||
|
||||
// Return 1 or -1 depending on which lower bound is greater.
|
||||
return (ia->lower > ib->lower) ? 1 : -1;
|
||||
}
|
||||
|
||||
// Define a function that calculates the distance between two integer keys.
|
||||
static float8 gbt_int4_dist(const void* a, const void* b)
|
||||
{
|
||||
// Use a macro to calculate the distance between the two integers.
|
||||
return GET_FLOAT_DISTANCE(int4, a, b);
|
||||
}
|
||||
|
||||
// Define a structure with information about the integer keys.
|
||||
static const gbtree_ninfo tinfo = {gbt_t_int4,
|
||||
sizeof(int32),
|
||||
gbt_int4gt,
|
||||
gbt_int4ge,
|
||||
gbt_int4eq,
|
||||
gbt_int4le,
|
||||
gbt_int4lt,
|
||||
gbt_int4key_cmp,
|
||||
gbt_int4_dist};
|
||||
|
||||
// Declare the function that will calculate the distance between two integers.
|
||||
PG_FUNCTION_INFO_V1(int4_dist);
|
||||
extern "C" Datum int4_dist(PG_FUNCTION_ARGS);
|
||||
Datum int4_dist(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Get the two integer arguments.
|
||||
int4 a = PG_GETARG_INT32(0);
|
||||
int4 b = PG_GETARG_INT32(1);
|
||||
int4 r;
|
||||
int4 ra;
|
||||
|
||||
// Calculate the difference between the two integers.
|
||||
r = a - b;
|
||||
ra = Abs(r); // Calculate the absolute value of the difference.
|
||||
|
||||
/* Check for overflow. */
|
||||
if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a)))
|
||||
ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); // Report an error if there is an overflow.
|
||||
|
||||
// Return the absolute value of the difference.
|
||||
PG_RETURN_INT32(ra);
|
||||
}
|
||||
|
||||
static float8 gbt_int4_dist(const void* a, const void* b)
|
||||
{
|
||||
return GET_FLOAT_DISTANCE(int4, a, b);
|
||||
}
|
||||
|
||||
static const gbtree_ninfo tinfo = {gbt_t_int4,
|
||||
sizeof(int32),
|
||||
gbt_int4gt,
|
||||
gbt_int4ge,
|
||||
gbt_int4eq,
|
||||
gbt_int4le,
|
||||
gbt_int4lt,
|
||||
gbt_int4key_cmp,
|
||||
gbt_int4_dist};
|
||||
|
||||
PG_FUNCTION_INFO_V1(int4_dist);
|
||||
extern "C" Datum int4_dist(PG_FUNCTION_ARGS);
|
||||
Datum int4_dist(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int4 a = PG_GETARG_INT32(0);
|
||||
int4 b = PG_GETARG_INT32(1);
|
||||
int4 r;
|
||||
int4 ra;
|
||||
|
||||
r = a - b;
|
||||
ra = Abs(r);
|
||||
|
||||
/* Overflow check. */
|
||||
if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a)))
|
||||
ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range")));
|
||||
|
||||
PG_RETURN_INT32(ra);
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* int32 ops
|
||||
**************************************************/
|
||||
|
||||
Datum gbt_int4_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
GISTENTRY* retval = NULL;
|
||||
|
||||
PG_RETURN_POINTER(gbt_num_compress(retval, entry, &tinfo));
|
||||
// Define a function that compresses a GiST entry.
|
||||
Datum gbt_int4_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Get the GiST entry from the function arguments.
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
GISTENTRY* retval = NULL;
|
||||
|
||||
// Compress the GiST entry and return the result.
|
||||
PG_RETURN_POINTER(gbt_num_compress(retval, entry, &tinfo));
|
||||
}
|
||||
|
||||
// Define a function that checks if a GiST entry is consistent with a query value.
|
||||
Datum gbt_int4_consistent(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Get the GiST entry, query value, strategy number, and output buffer from the function arguments.
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
int32 query = PG_GETARG_INT32(1);
|
||||
StrategyNumber strategy = (StrategyNumber)PG_GETARG_UINT16(2);
|
||||
|
||||
bool* recheck = (bool*)PG_GETARG_POINTER(4);
|
||||
int32KEY* kkk = (int32KEY*)DatumGetPointer(entry->key);
|
||||
GBT_NUMKEY_R key;
|
||||
|
||||
// Set the recheck flag to false, indicating that all cases served by this function are exact.
|
||||
/* All cases served by this function are exact */
|
||||
*recheck = false;
|
||||
|
||||
key.lower = (GBT_NUMKEY*)&kkk->lower;
|
||||
key.upper = (GBT_NUMKEY*)&kkk->upper;
|
||||
|
||||
// Check if the GiST entry is consistent with the query value and return the result.
|
||||
PG_RETURN_BOOL(gbt_num_consistent(&key, (void*)&query, &strategy, GIST_LEAF(entry), &tinfo));
|
||||
}
|
||||
|
||||
Datum gbt_int4_consistent(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
int32 query = PG_GETARG_INT32(1);
|
||||
StrategyNumber strategy = (StrategyNumber)PG_GETARG_UINT16(2);
|
||||
|
||||
bool* recheck = (bool*)PG_GETARG_POINTER(4);
|
||||
int32KEY* kkk = (int32KEY*)DatumGetPointer(entry->key);
|
||||
GBT_NUMKEY_R key;
|
||||
|
||||
/* All cases served by this function are exact */
|
||||
*recheck = false;
|
||||
|
||||
key.lower = (GBT_NUMKEY*)&kkk->lower;
|
||||
key.upper = (GBT_NUMKEY*)&kkk->upper;
|
||||
|
||||
PG_RETURN_BOOL(gbt_num_consistent(&key, (void*)&query, &strategy, GIST_LEAF(entry), &tinfo));
|
||||
}
|
||||
|
||||
Datum gbt_int4_distance(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
int32 query = PG_GETARG_INT32(1);
|
||||
|
||||
int32KEY* kkk = (int32KEY*)DatumGetPointer(entry->key);
|
||||
GBT_NUMKEY_R key;
|
||||
|
||||
key.lower = (GBT_NUMKEY*)&kkk->lower;
|
||||
key.upper = (GBT_NUMKEY*)&kkk->upper;
|
||||
|
||||
PG_RETURN_FLOAT8(gbt_num_distance(&key, (void*)&query, GIST_LEAF(entry), &tinfo));
|
||||
}
|
||||
|
||||
Datum gbt_int4_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector* entryvec = (GistEntryVector*)PG_GETARG_POINTER(0);
|
||||
void* out = palloc(sizeof(int32KEY));
|
||||
|
||||
*(int*)PG_GETARG_POINTER(1) = sizeof(int32KEY);
|
||||
PG_RETURN_POINTER(gbt_num_union((GBT_NUMKEY*)out, entryvec, &tinfo));
|
||||
}
|
||||
|
||||
Datum gbt_int4_penalty(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int32KEY* origentry = (int32KEY*)DatumGetPointer(((GISTENTRY*)PG_GETARG_POINTER(0))->key);
|
||||
int32KEY* newentry = (int32KEY*)DatumGetPointer(((GISTENTRY*)PG_GETARG_POINTER(1))->key);
|
||||
float* result = (float*)PG_GETARG_POINTER(2);
|
||||
|
||||
penalty_num(result, origentry->lower, origentry->upper, newentry->lower, newentry->upper);
|
||||
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
Datum gbt_int4_picksplit(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_POINTER(
|
||||
gbt_num_picksplit((GistEntryVector*)PG_GETARG_POINTER(0), (GIST_SPLITVEC*)PG_GETARG_POINTER(1), &tinfo));
|
||||
}
|
||||
|
||||
Datum gbt_int4_same(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int32KEY* b1 = (int32KEY*)PG_GETARG_POINTER(0);
|
||||
int32KEY* b2 = (int32KEY*)PG_GETARG_POINTER(1);
|
||||
bool* result = (bool*)PG_GETARG_POINTER(2);
|
||||
|
||||
*result = gbt_num_same((GBT_NUMKEY*)b1, (GBT_NUMKEY*)b2, &tinfo);
|
||||
PG_RETURN_POINTER(result);
|
||||
// Define a function that calculates the distance between two GiST entries.
|
||||
Datum gbt_int4_distance(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Get the GiST entry and query value from the function arguments.
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
int32 query = PG_GETARG_INT32(1);
|
||||
|
||||
// Extract the lower and upper bounds from the GiST entry.
|
||||
int32KEY* kkk = (int32KEY*)DatumGetPointer(entry->key);
|
||||
GBT_NUMKEY_R key;
|
||||
|
||||
key.lower = (GBT_NUMKEY*)&kkk->lower;
|
||||
key.upper = (GBT_NUMKEY*)&kkk->upper;
|
||||
|
||||
// Calculate and return the distance between the GiST entry and the query value.
|
||||
PG_RETURN_FLOAT8(gbt_num_distance(&key, (void*)&query, GIST_LEAF(entry), &tinfo));
|
||||
}
|
||||
|
||||
// Define a function that calculates the union of a set of GiST entries.
|
||||
Datum gbt_int4_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Get the vector of GiST entries and output buffer from the function arguments.
|
||||
GistEntryVector* entryvec = (GistEntryVector*)PG_GETARG_POINTER(0);
|
||||
void* out = palloc(sizeof(int32KEY));
|
||||
|
||||
// Set the size of the output buffer.
|
||||
*(int*)PG_GETARG_POINTER(1) = sizeof(int32KEY);
|
||||
|
||||
// Calculate and return the union of the set of GiST entries.
|
||||
PG_RETURN_POINTER(gbt_num_union((GBT_NUMKEY*)out, entryvec, &tinfo));
|
||||
}
|
||||
|
||||
// Define a function that calculates the penalty for splitting a set of GiST entries.
|
||||
Datum gbt_int4_penalty(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Get the original and new GiST entries, as well as the output buffer, from the function arguments.
|
||||
int32KEY* origentry = (int32KEY*)DatumGetPointer(((GISTENTRY*)PG_GETARG_POINTER(0))->key);
|
||||
int32KEY* newentry = (int32KEY*)DatumGetPointer(((GISTENTRY*)PG_GETARG_POINTER(1))->key);
|
||||
float* result = (float*)PG_GETARG_POINTER(2);
|
||||
|
||||
// Calculate the penalty for splitting the set of GiST entries.
|
||||
penalty_num(result, origentry->lower, origentry->upper, newentry->lower, newentry->upper);
|
||||
|
||||
// Return the calculated penalty.
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
// Define a function that selects which GiST entries to split.
|
||||
Datum gbt_int4_picksplit(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Select which GiST entries to split and return the result.
|
||||
PG_RETURN_POINTER(
|
||||
gbt_num_picksplit((GistEntryVector*)PG_GETARG_POINTER(0), (GIST_SPLITVEC*)PG_GETARG_POINTER(1), &tinfo));
|
||||
}
|
||||
|
||||
// Define a function that checks if two GiST entries are equal.
|
||||
Datum gbt_int4_same(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Get the two GiST entries and output buffer from the function arguments.
|
||||
int32KEY* b1 = (int32KEY*)PG_GETARG_POINTER(0);
|
||||
int32KEY* b2 = (int32KEY*)PG_GETARG_POINTER(1);
|
||||
bool* result = (bool*)PG_GETARG_POINTER(2);
|
||||
|
||||
// Check if the two GiST entries are equal and store the result in the output buffer.
|
||||
*result = gbt_num_same((GBT_NUMKEY*)b1, (GBT_NUMKEY*)b2, &tinfo);
|
||||
|
||||
// Return the output buffer.
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,110 +1,130 @@
|
|||
/*
|
||||
* contrib/btree_gist/btree_int8.c
|
||||
*/
|
||||
#include "postgres.h"
|
||||
#include "knl/knl_variable.h"
|
||||
|
||||
#include "btree_gist.h"
|
||||
#include "btree_utils_num.h"
|
||||
|
||||
typedef struct int64key {
|
||||
int64 lower;
|
||||
int64 upper;
|
||||
} int64KEY;
|
||||
|
||||
/*
|
||||
** int64 ops
|
||||
*/
|
||||
PG_FUNCTION_INFO_V1(gbt_int8_compress);
|
||||
PG_FUNCTION_INFO_V1(gbt_int8_union);
|
||||
PG_FUNCTION_INFO_V1(gbt_int8_picksplit);
|
||||
PG_FUNCTION_INFO_V1(gbt_int8_consistent);
|
||||
PG_FUNCTION_INFO_V1(gbt_int8_distance);
|
||||
PG_FUNCTION_INFO_V1(gbt_int8_penalty);
|
||||
PG_FUNCTION_INFO_V1(gbt_int8_same);
|
||||
|
||||
extern "C" Datum gbt_int8_compress(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gbt_int8_union(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gbt_int8_picksplit(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gbt_int8_consistent(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gbt_int8_distance(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gbt_int8_penalty(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gbt_int8_same(PG_FUNCTION_ARGS);
|
||||
|
||||
static bool gbt_int8gt(const void* a, const void* b)
|
||||
{
|
||||
return (*((const int64*)a) > *((const int64*)b));
|
||||
}
|
||||
static bool gbt_int8ge(const void* a, const void* b)
|
||||
{
|
||||
return (*((const int64*)a) >= *((const int64*)b));
|
||||
}
|
||||
static bool gbt_int8eq(const void* a, const void* b)
|
||||
{
|
||||
return (*((const int64*)a) == *((const int64*)b));
|
||||
}
|
||||
static bool gbt_int8le(const void* a, const void* b)
|
||||
{
|
||||
return (*((const int64*)a) <= *((const int64*)b));
|
||||
}
|
||||
static bool gbt_int8lt(const void* a, const void* b)
|
||||
{
|
||||
return (*((const int64*)a) < *((const int64*)b));
|
||||
// Include the PostgreSQL header file, which contains all the basic PostgreSQL data types and function definitions.
|
||||
#include "postgres.h"
|
||||
// Include the knl/knl_variable.h header file, which is part of the PostgreSQL kernel and contains the definitions of some internal variables and functions.
|
||||
#include "knl/knl_variable.h"
|
||||
|
||||
// Include the btree_gist.h header file, which defines the B-tree structure used to implement the GiST index.
|
||||
#include "btree_gist.h"
|
||||
// Include the btree_utils_num.h header file, which contains some utility functions for operating on B-trees.
|
||||
#include "btree_utils_num.h"
|
||||
|
||||
// Define a structure int64key for storing the lower and upper bounds of a 64-bit integer.
|
||||
typedef struct int64key {
|
||||
// The lower bound of the 64-bit integer.
|
||||
int64 lower;
|
||||
// The upper bound of the 64-bit integer.
|
||||
int64 upper;
|
||||
} int64KEY;
|
||||
|
||||
/*
|
||||
** int64 ops
|
||||
*/
|
||||
// Define a series of function info macros, which are used to register functions in PostgreSQL.
|
||||
PG_FUNCTION_INFO_V1(gbt_int8_compress); // Compression function.
|
||||
PG_FUNCTION_INFO_V1(gbt_int8_union); // Merging function.
|
||||
PG_FUNCTION_INFO_V1(gbt_int8_picksplit); // Splitting function.
|
||||
PG_FUNCTION_INFO_V1(gbt_int8_consistent);// Consistency check function.
|
||||
PG_FUNCTION_INFO_V1(gbt_int8_distance); // Distance function.
|
||||
PG_FUNCTION_INFO_V1(gbt_int8_penalty); // Penalty function.
|
||||
PG_FUNCTION_INFO_V1(gbt_int8_same); // Sameness check function.
|
||||
|
||||
// Define a series of function prototypes, which are used to implement different operations on the GiST index.
|
||||
extern "C" Datum gbt_int8_compress(PG_FUNCTION_ARGS); // Compression function.
|
||||
extern "C" Datum gbt_int8_union(PG_FUNCTION_ARGS); // Merging function.
|
||||
extern "C" Datum gbt_int8_picksplit(PG_FUNCTION_ARGS); // Splitting function.
|
||||
extern "C" Datum gbt_int8_consistent(PG_FUNCTION_ARGS);// Consistency check function.
|
||||
extern "C" Datum gbt_int8_distance(PG_FUNCTION_ARGS); // Distance function.
|
||||
extern "C" Datum gbt_int8_penalty(PG_FUNCTION_ARGS); // Penalty function.
|
||||
extern "C" Datum gbt_int8_same(PG_FUNCTION_ARGS); // Sameness check function.
|
||||
|
||||
// Define a series of comparison functions, which are used to compare the sizes of two 64-bit integers.
|
||||
static bool gbt_int8gt(const void* a, const void* b) // Greater than comparison.
|
||||
{
|
||||
return (*((const int64*)a) > *((const int64*)b));
|
||||
}
|
||||
static bool gbt_int8ge(const void* a, const void* b) // Greater than or equal to comparison.
|
||||
{
|
||||
return (*((const int64*)a) >= *((const int64*)b));
|
||||
}
|
||||
static bool gbt_int8eq(const void* a, const void* b) // Equal to comparison.
|
||||
{
|
||||
return (*((const int64*)a) == *((const int64*)b));
|
||||
}
|
||||
static bool gbt_int8le(const void* a, const void* b) // Less than or equal to comparison.
|
||||
{
|
||||
return (*((const int64*)a) <= *((const int64*)b));
|
||||
}
|
||||
static bool gbt_int8lt(const void* a, const void* b) // Less than comparison.
|
||||
{
|
||||
return (*((const int64*)a) < *((const int64*)b));
|
||||
}
|
||||
|
||||
static int gbt_int8key_cmp(const void* a, const void* b)
|
||||
{
|
||||
int64KEY* ia = (int64KEY*)(((const Nsrt*)a)->t);
|
||||
int64KEY* ib = (int64KEY*)(((const Nsrt*)b)->t);
|
||||
|
||||
if (ia->lower == ib->lower) {
|
||||
if (ia->upper == ib->upper)
|
||||
return 0;
|
||||
|
||||
return (ia->upper > ib->upper) ? 1 : -1;
|
||||
}
|
||||
|
||||
return (ia->lower > ib->lower) ? 1 : -1;
|
||||
// Define a function to compare two 64-bit integers.
|
||||
static int gbt_int8key_cmp(const void* a, const void* b)
|
||||
{
|
||||
// Cast the input pointers to their original types.
|
||||
int64KEY* ia = (int64KEY*)(((const Nsrt*)a)->t);
|
||||
int64KEY* ib = (int64KEY*)(((const Nsrt*)b)->t);
|
||||
|
||||
// Compare the lower bounds first. If they are equal, compare the upper bounds.
|
||||
if (ia->lower == ib->lower) {
|
||||
if (ia->upper == ib->upper)
|
||||
return 0; // Return 0 if both are equal.
|
||||
|
||||
return (ia->upper > ib->upper) ? 1 : -1; // Return 1 if ia->upper is greater than ib->upper, else return -1.
|
||||
}
|
||||
|
||||
return (ia->lower > ib->lower) ? 1 : -1; // Return 1 if ia->lower is greater than ib->lower, else return -1.
|
||||
}
|
||||
|
||||
// Define a function to calculate the distance between two 64-bit integers.
|
||||
static float8 gbt_int8_dist(const void* a, const void* b)
|
||||
{
|
||||
// Use the macro GET_FLOAT_DISTANCE to calculate the distance.
|
||||
return GET_FLOAT_DISTANCE(int64, a, b);
|
||||
}
|
||||
|
||||
// Define a structure to store the information about the GiST index.
|
||||
static const gbtree_ninfo tinfo = {gbt_t_int8,
|
||||
sizeof(int64),
|
||||
gbt_int8gt,
|
||||
gbt_int8ge,
|
||||
gbt_int8eq,
|
||||
gbt_int8le,
|
||||
gbt_int8lt,
|
||||
gbt_int8key_cmp,
|
||||
gbt_int8_dist};
|
||||
|
||||
// Register the int8_dist function in PostgreSQL.
|
||||
PG_FUNCTION_INFO_V1(int8_dist);
|
||||
extern "C" Datum int8_dist(PG_FUNCTION_ARGS);
|
||||
Datum int8_dist(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Get the input arguments.
|
||||
int64 a = PG_GETARG_INT64(0);
|
||||
int64 b = PG_GETARG_INT64(1);
|
||||
int64 r;
|
||||
int64 ra;
|
||||
|
||||
// Calculate the difference between a and b.
|
||||
r = a - b;
|
||||
ra = Abs(r); // Calculate the absolute value of r.
|
||||
|
||||
/* Check for overflow. */
|
||||
if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a)))
|
||||
ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); // Report an error if there is an overflow.
|
||||
|
||||
// Return the absolute value of the difference.
|
||||
PG_RETURN_INT64(ra);
|
||||
}
|
||||
|
||||
static float8 gbt_int8_dist(const void* a, const void* b)
|
||||
{
|
||||
return GET_FLOAT_DISTANCE(int64, a, b);
|
||||
}
|
||||
|
||||
static const gbtree_ninfo tinfo = {gbt_t_int8,
|
||||
sizeof(int64),
|
||||
gbt_int8gt,
|
||||
gbt_int8ge,
|
||||
gbt_int8eq,
|
||||
gbt_int8le,
|
||||
gbt_int8lt,
|
||||
gbt_int8key_cmp,
|
||||
gbt_int8_dist};
|
||||
|
||||
PG_FUNCTION_INFO_V1(int8_dist);
|
||||
extern "C" Datum int8_dist(PG_FUNCTION_ARGS);
|
||||
Datum int8_dist(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int64 a = PG_GETARG_INT64(0);
|
||||
int64 b = PG_GETARG_INT64(1);
|
||||
int64 r;
|
||||
int64 ra;
|
||||
|
||||
r = a - b;
|
||||
ra = Abs(r);
|
||||
|
||||
/* Overflow check. */
|
||||
if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a)))
|
||||
ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range")));
|
||||
|
||||
PG_RETURN_INT64(ra);
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* int64 ops
|
||||
**************************************************/
|
||||
|
||||
/* gbt_int8_compress - compresses a GIST entry containing an int8 key */
|
||||
Datum gbt_int8_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
|
|
@ -113,6 +133,7 @@ Datum gbt_int8_compress(PG_FUNCTION_ARGS)
|
|||
PG_RETURN_POINTER(gbt_num_compress(retval, entry, &tinfo));
|
||||
}
|
||||
|
||||
/* gbt_int8_consistent - checks if a query is consistent with an int8 key */
|
||||
Datum gbt_int8_consistent(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
|
|
@ -132,6 +153,7 @@ Datum gbt_int8_consistent(PG_FUNCTION_ARGS)
|
|||
PG_RETURN_BOOL(gbt_num_consistent(&key, (void*)&query, &strategy, GIST_LEAF(entry), &tinfo));
|
||||
}
|
||||
|
||||
/* gbt_int8_distance - calculates the distance between an int8 key and a query */
|
||||
Datum gbt_int8_distance(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
|
|
@ -146,6 +168,7 @@ Datum gbt_int8_distance(PG_FUNCTION_ARGS)
|
|||
PG_RETURN_FLOAT8(gbt_num_distance(&key, (void*)&query, GIST_LEAF(entry), &tinfo));
|
||||
}
|
||||
|
||||
/* gbt_int8_union - performs a union on a vector of int8 keys */
|
||||
Datum gbt_int8_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector* entryvec = (GistEntryVector*)PG_GETARG_POINTER(0);
|
||||
|
|
@ -155,6 +178,7 @@ Datum gbt_int8_union(PG_FUNCTION_ARGS)
|
|||
PG_RETURN_POINTER(gbt_num_union((GBT_NUMKEY*)out, entryvec, &tinfo));
|
||||
}
|
||||
|
||||
/* gbt_int8_penalty - calculates the penalty for splitting an int8 key */
|
||||
Datum gbt_int8_penalty(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int64KEY* origentry = (int64KEY*)DatumGetPointer(((GISTENTRY*)PG_GETARG_POINTER(0))->key);
|
||||
|
|
@ -166,12 +190,14 @@ Datum gbt_int8_penalty(PG_FUNCTION_ARGS)
|
|||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
/* gbt_int8_picksplit - performs a picksplit on a GIST entry vector */
|
||||
Datum gbt_int8_picksplit(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_POINTER(
|
||||
gbt_num_picksplit((GistEntryVector*)PG_GETARG_POINTER(0), (GIST_SPLITVEC*)PG_GETARG_POINTER(1), &tinfo));
|
||||
}
|
||||
|
||||
/* gbt_int8_same - checks if two int8 keys are the same */
|
||||
Datum gbt_int8_same(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int64KEY* b1 = (int64KEY*)PG_GETARG_POINTER(0);
|
||||
|
|
@ -180,4 +206,4 @@ Datum gbt_int8_same(PG_FUNCTION_ARGS)
|
|||
|
||||
*result = gbt_num_same((GBT_NUMKEY*)b1, (GBT_NUMKEY*)b2, &tinfo);
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
}
|
||||
|
|
@ -31,134 +31,169 @@ extern "C" Datum gbt_macad_consistent(PG_FUNCTION_ARGS);
|
|||
extern "C" Datum gbt_macad_penalty(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gbt_macad_same(PG_FUNCTION_ARGS);
|
||||
|
||||
static bool gbt_macadgt(const void* a, const void* b)
|
||||
{
|
||||
return DatumGetBool(DirectFunctionCall2(macaddr_gt, PointerGetDatum(a), PointerGetDatum(b)));
|
||||
}
|
||||
static bool gbt_macadge(const void* a, const void* b)
|
||||
{
|
||||
return DatumGetBool(DirectFunctionCall2(macaddr_ge, PointerGetDatum(a), PointerGetDatum(b)));
|
||||
// Define a function to compare two macaddr values.
|
||||
static bool gbt_macadgt(const void* a, const void* b)
|
||||
{
|
||||
// Use the macaddr_gt function to compare the input pointers and return the result as a boolean value.
|
||||
return DatumGetBool(DirectFunctionCall2(macaddr_gt, PointerGetDatum(a), PointerGetDatum(b)));
|
||||
}
|
||||
|
||||
// Define a function to compare two macaddr values.
|
||||
static bool gbt_macadge(const void* a, const void* b)
|
||||
{
|
||||
// Use the macaddr_ge function to compare the input pointers and return the result as a boolean value.
|
||||
return DatumGetBool(DirectFunctionCall2(macaddr_ge, PointerGetDatum(a), PointerGetDatum(b)));
|
||||
}
|
||||
|
||||
// Define a function to compare two macaddr values.
|
||||
static bool gbt_macadeq(const void* a, const void* b)
|
||||
{
|
||||
// Use the macaddr_eq function to compare the input pointers and return the result as a boolean value.
|
||||
return DatumGetBool(DirectFunctionCall2(macaddr_eq, PointerGetDatum(a), PointerGetDatum(b)));
|
||||
}
|
||||
|
||||
// Define a function to compare two macaddr values.
|
||||
static bool gbt_macadle(const void* a, const void* b)
|
||||
{
|
||||
// Use the macaddr_le function to compare the input pointers and return the result as a boolean value.
|
||||
return DatumGetBool(DirectFunctionCall2(macaddr_le, PointerGetDatum(a), PointerGetDatum(b)));
|
||||
}
|
||||
|
||||
// Define a function to compare two macaddr values.
|
||||
static bool gbt_macadlt(const void* a, const void* b)
|
||||
{
|
||||
// Use the macaddr_lt function to compare the input pointers and return the result as a boolean value.
|
||||
return DatumGetBool(DirectFunctionCall2(macaddr_lt, PointerGetDatum(a), PointerGetDatum(b)));
|
||||
}
|
||||
|
||||
// Define a function to compare two macaddr keys.
|
||||
static int gbt_macadkey_cmp(const void* a, const void* b)
|
||||
{
|
||||
// Cast the input pointers to their original types.
|
||||
macKEY* ia = (macKEY*)(((const Nsrt*)a)->t);
|
||||
macKEY* ib = (macKEY*)(((const Nsrt*)b)->t);
|
||||
int res;
|
||||
|
||||
// Compare the lower bounds first. If they are equal, compare the upper bounds.
|
||||
res = DatumGetInt32(DirectFunctionCall2(macaddr_cmp, MacaddrPGetDatum(&ia->lower), MacaddrPGetDatum(&ib->lower)));
|
||||
if (res == 0)
|
||||
return DatumGetInt32(DirectFunctionCall2(macaddr_cmp, MacaddrPGetDatum(&ia->upper), MacaddrPGetDatum(&ib->upper)));
|
||||
|
||||
return res; // Return the result of the comparison.
|
||||
}
|
||||
|
||||
static bool gbt_macadeq(const void* a, const void* b)
|
||||
{
|
||||
return DatumGetBool(DirectFunctionCall2(macaddr_eq, PointerGetDatum(a), PointerGetDatum(b)));
|
||||
// Define a structure to store the information about the GiST index.
|
||||
static const gbtree_ninfo tinfo = {gbt_t_macad,
|
||||
sizeof(macaddr),
|
||||
gbt_macadgt,
|
||||
gbt_macadge,
|
||||
gbt_macadeq,
|
||||
gbt_macadle,
|
||||
gbt_macadlt,
|
||||
gbt_macadkey_cmp,
|
||||
NULL};
|
||||
|
||||
/**************************************************
|
||||
* macaddr ops
|
||||
**************************************************/
|
||||
|
||||
// Define a function to convert a macaddr to a uint64.
|
||||
static uint64 mac_2_uint64(macaddr* m)
|
||||
{
|
||||
unsigned char* mi = (unsigned char*)m;
|
||||
uint64 res = 0;
|
||||
int i;
|
||||
|
||||
// Loop through each byte of the macaddr and shift it to the correct position.
|
||||
for (i = 0; i < 6; i++)
|
||||
res += (((uint64)mi[i]) << ((uint64)((5 - i) * 8)));
|
||||
return res;
|
||||
}
|
||||
|
||||
// Define a function to compress a GiST entry.
|
||||
Datum gbt_macad_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
GISTENTRY* retval = NULL;
|
||||
|
||||
// Use the gbt_num_compress function to compress the entry and return it.
|
||||
PG_RETURN_POINTER(gbt_num_compress(retval, entry, &tinfo));
|
||||
}
|
||||
|
||||
// Define a function to check the consistency of a GiST entry.
|
||||
Datum gbt_macad_consistent(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
macaddr* query = (macaddr*)PG_GETARG_POINTER(1);
|
||||
StrategyNumber strategy = (StrategyNumber)PG_GETARG_UINT16(2);
|
||||
|
||||
bool* recheck = (bool*)PG_GETARG_POINTER(4);
|
||||
macKEY* kkk = (macKEY*)DatumGetPointer(entry->key);
|
||||
GBT_NUMKEY_R key;
|
||||
|
||||
// All cases served by this function are exact, so set *recheck to false.
|
||||
*recheck = false;
|
||||
|
||||
// Set the lower and upper bounds of the key.
|
||||
key.lower = (GBT_NUMKEY*)&kkk->lower;
|
||||
key.upper = (GBT_NUMKEY*)&kkk->upper;
|
||||
|
||||
// Use the gbt_num_consistent function to check the consistency of the entry and return the result.
|
||||
PG_RETURN_BOOL(gbt_num_consistent(&key, (void*)query, &strategy, GIST_LEAF(entry), &tinfo));
|
||||
}
|
||||
|
||||
static bool gbt_macadle(const void* a, const void* b)
|
||||
{
|
||||
return DatumGetBool(DirectFunctionCall2(macaddr_le, PointerGetDatum(a), PointerGetDatum(b)));
|
||||
}
|
||||
|
||||
static bool gbt_macadlt(const void* a, const void* b)
|
||||
{
|
||||
return DatumGetBool(DirectFunctionCall2(macaddr_lt, PointerGetDatum(a), PointerGetDatum(b)));
|
||||
}
|
||||
|
||||
static int gbt_macadkey_cmp(const void* a, const void* b)
|
||||
{
|
||||
macKEY* ia = (macKEY*)(((const Nsrt*)a)->t);
|
||||
macKEY* ib = (macKEY*)(((const Nsrt*)b)->t);
|
||||
int res;
|
||||
|
||||
res = DatumGetInt32(DirectFunctionCall2(macaddr_cmp, MacaddrPGetDatum(&ia->lower), MacaddrPGetDatum(&ib->lower)));
|
||||
if (res == 0)
|
||||
return DatumGetInt32(
|
||||
DirectFunctionCall2(macaddr_cmp, MacaddrPGetDatum(&ia->upper), MacaddrPGetDatum(&ib->upper)));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static const gbtree_ninfo tinfo = {gbt_t_macad,
|
||||
sizeof(macaddr),
|
||||
gbt_macadgt,
|
||||
gbt_macadge,
|
||||
gbt_macadeq,
|
||||
gbt_macadle,
|
||||
gbt_macadlt,
|
||||
gbt_macadkey_cmp,
|
||||
NULL};
|
||||
|
||||
/**************************************************
|
||||
* macaddr ops
|
||||
**************************************************/
|
||||
|
||||
static uint64 mac_2_uint64(macaddr* m)
|
||||
{
|
||||
unsigned char* mi = (unsigned char*)m;
|
||||
uint64 res = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
res += (((uint64)mi[i]) << ((uint64)((5 - i) * 8)));
|
||||
return res;
|
||||
}
|
||||
|
||||
Datum gbt_macad_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
GISTENTRY* retval = NULL;
|
||||
|
||||
PG_RETURN_POINTER(gbt_num_compress(retval, entry, &tinfo));
|
||||
}
|
||||
|
||||
Datum gbt_macad_consistent(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
macaddr* query = (macaddr*)PG_GETARG_POINTER(1);
|
||||
StrategyNumber strategy = (StrategyNumber)PG_GETARG_UINT16(2);
|
||||
|
||||
bool* recheck = (bool*)PG_GETARG_POINTER(4);
|
||||
macKEY* kkk = (macKEY*)DatumGetPointer(entry->key);
|
||||
GBT_NUMKEY_R key;
|
||||
|
||||
/* All cases served by this function are exact */
|
||||
*recheck = false;
|
||||
|
||||
key.lower = (GBT_NUMKEY*)&kkk->lower;
|
||||
key.upper = (GBT_NUMKEY*)&kkk->upper;
|
||||
|
||||
PG_RETURN_BOOL(gbt_num_consistent(&key, (void*)query, &strategy, GIST_LEAF(entry), &tinfo));
|
||||
}
|
||||
|
||||
Datum gbt_macad_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector* entryvec = (GistEntryVector*)PG_GETARG_POINTER(0);
|
||||
void* out = palloc(sizeof(macKEY));
|
||||
|
||||
*(int*)PG_GETARG_POINTER(1) = sizeof(macKEY);
|
||||
PG_RETURN_POINTER(gbt_num_union((GBT_NUMKEY*)out, entryvec, &tinfo));
|
||||
}
|
||||
|
||||
Datum gbt_macad_penalty(PG_FUNCTION_ARGS)
|
||||
{
|
||||
macKEY* origentry = (macKEY*)DatumGetPointer(((GISTENTRY*)PG_GETARG_POINTER(0))->key);
|
||||
macKEY* newentry = (macKEY*)DatumGetPointer(((GISTENTRY*)PG_GETARG_POINTER(1))->key);
|
||||
float* result = (float*)PG_GETARG_POINTER(2);
|
||||
uint64 iorg[2], inew[2];
|
||||
|
||||
iorg[0] = mac_2_uint64(&origentry->lower);
|
||||
iorg[1] = mac_2_uint64(&origentry->upper);
|
||||
inew[0] = mac_2_uint64(&newentry->lower);
|
||||
inew[1] = mac_2_uint64(&newentry->upper);
|
||||
|
||||
penalty_num(result, iorg[0], iorg[1], inew[0], inew[1]);
|
||||
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
Datum gbt_macad_picksplit(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_POINTER(
|
||||
gbt_num_picksplit((GistEntryVector*)PG_GETARG_POINTER(0), (GIST_SPLITVEC*)PG_GETARG_POINTER(1), &tinfo));
|
||||
}
|
||||
|
||||
Datum gbt_macad_same(PG_FUNCTION_ARGS)
|
||||
{
|
||||
macKEY* b1 = (macKEY*)PG_GETARG_POINTER(0);
|
||||
macKEY* b2 = (macKEY*)PG_GETARG_POINTER(1);
|
||||
bool* result = (bool*)PG_GETARG_POINTER(2);
|
||||
|
||||
*result = gbt_num_same((GBT_NUMKEY*)b1, (GBT_NUMKEY*)b2, &tinfo);
|
||||
PG_RETURN_POINTER(result);
|
||||
// Define a function to union GiST entries.
|
||||
Datum gbt_macad_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector* entryvec = (GistEntryVector*)PG_GETARG_POINTER(0);
|
||||
void* out = palloc(sizeof(macKEY));
|
||||
|
||||
// Set the size of the output to the size of a macKEY.
|
||||
*(int*)PG_GETARG_POINTER(1) = sizeof(macKEY);
|
||||
|
||||
// Use the gbt_num_union function to union the entries and return the result.
|
||||
PG_RETURN_POINTER(gbt_num_union((GBT_NUMKEY*)out, entryvec, &tinfo));
|
||||
}
|
||||
|
||||
// Define a function to calculate the penalty of GiST entries.
|
||||
Datum gbt_macad_penalty(PG_FUNCTION_ARGS)
|
||||
{
|
||||
macKEY* origentry = (macKEY*)DatumGetPointer(((GISTENTRY*)PG_GETARG_POINTER(0))->key);
|
||||
macKEY* newentry = (macKEY*)DatumGetPointer(((GISTENTRY*)PG_GETARG_POINTER(1))->key);
|
||||
float* result = (float*)PG_GETARG_POINTER(2);
|
||||
uint64 iorg[2], inew[2];
|
||||
|
||||
// Convert the original and new entries to uint64.
|
||||
iorg[0] = mac_2_uint64(&origentry->lower);
|
||||
iorg[1] = mac_2_uint64(&origentry->upper);
|
||||
inew[0] = mac_2_uint64(&newentry->lower);
|
||||
inew[1] = mac_2_uint64(&newentry->upper);
|
||||
|
||||
// Calculate the penalty and store it in the result.
|
||||
penalty_num(result, iorg[0], iorg[1], inew[0], inew[1]);
|
||||
|
||||
// Return the result.
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
// Define a function to pick a split point for GiST entries.
|
||||
Datum gbt_macad_picksplit(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Use the gbt_num_picksplit function to pick a split point and return the result.
|
||||
PG_RETURN_POINTER(
|
||||
gbt_num_picksplit((GistEntryVector*)PG_GETARG_POINTER(0), (GIST_SPLITVEC*)PG_GETARG_POINTER(1), &tinfo));
|
||||
}
|
||||
|
||||
// Define a function to check if two GiST entries are the same.
|
||||
Datum gbt_macad_same(PG_FUNCTION_ARGS)
|
||||
{
|
||||
macKEY* b1 = (macKEY*)PG_GETARG_POINTER(0);
|
||||
macKEY* b2 = (macKEY*)PG_GETARG_POINTER(1);
|
||||
bool* result = (bool*)PG_GETARG_POINTER(2);
|
||||
|
||||
// Use the gbt_num_same function to check if the two entries are the same and store the result.
|
||||
*result = gbt_num_same((GBT_NUMKEY*)b1, (GBT_NUMKEY*)b2, &tinfo);
|
||||
|
||||
// Return the result.
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,95 +87,159 @@ Datum gbt_numeric_compress(PG_FUNCTION_ARGS)
|
|||
PG_RETURN_POINTER(gbt_var_compress(entry, &tinfo));
|
||||
}
|
||||
|
||||
Datum gbt_numeric_consistent(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
void* query = (void*)DatumGetNumeric(PG_GETARG_DATUM(1));
|
||||
StrategyNumber strategy = (StrategyNumber)PG_GETARG_UINT16(2);
|
||||
|
||||
bool* recheck = (bool*)PG_GETARG_POINTER(4);
|
||||
bool retval = false;
|
||||
GBT_VARKEY* key = (GBT_VARKEY*)DatumGetPointer(entry->key);
|
||||
GBT_VARKEY_R r = gbt_var_key_readable(key);
|
||||
|
||||
/* All cases served by this function are exact */
|
||||
*recheck = false;
|
||||
|
||||
retval = gbt_var_consistent(&r, query, strategy, PG_GET_COLLATION(), GIST_LEAF(entry), &tinfo);
|
||||
PG_RETURN_BOOL(retval);
|
||||
// Function to check consistency of a numeric value with a GIST entry
|
||||
Datum gbt_numeric_consistent(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Pointer to the GIST entry
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
|
||||
// The numeric value to be checked
|
||||
void* query = (void*)DatumGetNumeric(PG_GETARG_DATUM(1));
|
||||
|
||||
// The strategy number representing the strategy to be used
|
||||
StrategyNumber strategy = (StrategyNumber)PG_GETARG_UINT16(2);
|
||||
|
||||
// Pointer to a boolean variable that indicates whether a recheck is necessary
|
||||
bool* recheck = (bool*)PG_GETARG_POINTER(4);
|
||||
|
||||
// The return value, initialized to false
|
||||
bool retval = false;
|
||||
|
||||
// Pointer to the key of the GIST entry, converted to a GBT_VARKEY*
|
||||
GBT_VARKEY* key = (GBT_VARKEY*)DatumGetPointer(entry->key);
|
||||
|
||||
// The readable representation of the GBT_VARKEY
|
||||
GBT_VARKEY_R r = gbt_var_key_readable(key);
|
||||
|
||||
// All cases served by this function are exact, so set *recheck to false
|
||||
*recheck = false;
|
||||
|
||||
// Check consistency using the gbt_var_consistent function and store the result in retval
|
||||
retval = gbt_var_consistent(&r, query, strategy, PG_GET_COLLATION(), GIST_LEAF(entry), &tinfo);
|
||||
|
||||
// Return the result of the consistency check as a boolean value
|
||||
PG_RETURN_BOOL(retval);
|
||||
}
|
||||
|
||||
Datum gbt_numeric_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector* entryvec = (GistEntryVector*)PG_GETARG_POINTER(0);
|
||||
int32* size = (int*)PG_GETARG_POINTER(1);
|
||||
|
||||
PG_RETURN_POINTER(gbt_var_union(entryvec, size, PG_GET_COLLATION(), &tinfo));
|
||||
// Function to perform a union operation on numeric values using GBT
|
||||
Datum gbt_numeric_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Pointer to the GistEntryVector containing the GIST entries
|
||||
GistEntryVector* entryvec = (GistEntryVector*)PG_GETARG_POINTER(0);
|
||||
|
||||
// Pointer to an integer representing the size of the union
|
||||
int32* size = (int*)PG_GETARG_POINTER(1);
|
||||
|
||||
// Perform the union operation using gbt_var_union and return the result as a pointer
|
||||
PG_RETURN_POINTER(gbt_var_union(entryvec, size, PG_GET_COLLATION(), &tinfo));
|
||||
}
|
||||
|
||||
Datum gbt_numeric_same(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum d1 = PG_GETARG_DATUM(0);
|
||||
Datum d2 = PG_GETARG_DATUM(1);
|
||||
bool* result = (bool*)PG_GETARG_POINTER(2);
|
||||
|
||||
*result = gbt_var_same(d1, d2, PG_GET_COLLATION(), &tinfo);
|
||||
PG_RETURN_POINTER(result);
|
||||
// Function to check if two numeric values are the same using GBT
|
||||
Datum gbt_numeric_same(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// The first numeric value
|
||||
Datum d1 = PG_GETARG_DATUM(0);
|
||||
|
||||
// The second numeric value
|
||||
Datum d2 = PG_GETARG_DATUM(1);
|
||||
|
||||
// Pointer to a boolean variable that will store the result
|
||||
bool* result = (bool*)PG_GETARG_POINTER(2);
|
||||
|
||||
// Check if the two numeric values are the same using gbt_var_same and store the result in *result
|
||||
*result = gbt_var_same(d1, d2, PG_GET_COLLATION(), &tinfo);
|
||||
|
||||
// Return the result as a pointer
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
Datum gbt_numeric_penalty(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* o = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
GISTENTRY* n = (GISTENTRY*)PG_GETARG_POINTER(1);
|
||||
float* result = (float*)PG_GETARG_POINTER(2);
|
||||
|
||||
Numeric us, os, ds;
|
||||
|
||||
GBT_VARKEY* org = (GBT_VARKEY*)DatumGetPointer(o->key);
|
||||
GBT_VARKEY* newe = (GBT_VARKEY*)DatumGetPointer(n->key);
|
||||
Datum uni;
|
||||
GBT_VARKEY_R rk, ok, uk;
|
||||
|
||||
rk = gbt_var_key_readable(org);
|
||||
uni = PointerGetDatum(gbt_var_key_copy(&rk, TRUE));
|
||||
gbt_var_bin_union(&uni, newe, PG_GET_COLLATION(), &tinfo);
|
||||
ok = gbt_var_key_readable(org);
|
||||
uk = gbt_var_key_readable((GBT_VARKEY*)DatumGetPointer(uni));
|
||||
|
||||
us = DatumGetNumeric(DirectFunctionCall2(numeric_sub, PointerGetDatum(uk.upper), PointerGetDatum(uk.lower)));
|
||||
|
||||
os = DatumGetNumeric(DirectFunctionCall2(numeric_sub, PointerGetDatum(ok.upper), PointerGetDatum(ok.lower)));
|
||||
|
||||
ds = DatumGetNumeric(DirectFunctionCall2(numeric_sub, NumericGetDatum(us), NumericGetDatum(os)));
|
||||
|
||||
if (numeric_is_nan(us)) {
|
||||
if (numeric_is_nan(os))
|
||||
*result = 0.0;
|
||||
else
|
||||
*result = 1.0;
|
||||
} else {
|
||||
Numeric nul = DatumGetNumeric(DirectFunctionCall1(int4_numeric, Int32GetDatum(0)));
|
||||
|
||||
*result = 0.0;
|
||||
|
||||
if (DirectFunctionCall2(numeric_gt, NumericGetDatum(ds), NumericGetDatum(nul))) {
|
||||
*result += FLT_MIN;
|
||||
os = DatumGetNumeric(DirectFunctionCall2(numeric_div, NumericGetDatum(ds), NumericGetDatum(us)));
|
||||
*result += (float4)DatumGetFloat8(DirectFunctionCall1(numeric_float8_no_overflow, NumericGetDatum(os)));
|
||||
}
|
||||
}
|
||||
|
||||
if (*result > 0)
|
||||
*result *= (FLT_MAX / (((GISTENTRY*)PG_GETARG_POINTER(0))->rel->rd_att->natts + 1));
|
||||
|
||||
PG_RETURN_POINTER(result);
|
||||
// Function to calculate the penalty for a numeric value using GBT
|
||||
Datum gbt_numeric_penalty(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Pointer to the original GIST entry
|
||||
GISTENTRY* o = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
|
||||
// Pointer to the new GIST entry
|
||||
GISTENTRY* n = (GISTENTRY*)PG_GETARG_POINTER(1);
|
||||
|
||||
// Pointer to a float variable that will store the result
|
||||
float* result = (float*)PG_GETARG_POINTER(2);
|
||||
|
||||
Numeric us, os, ds;
|
||||
|
||||
// Pointers to the keys of the original and new GIST entries
|
||||
GBT_VARKEY* org = (GBT_VARKEY*)DatumGetPointer(o->key);
|
||||
GBT_VARKEY* newe = (GBT_VARKEY*)DatumGetPointer(n->key);
|
||||
|
||||
// The union of the original and new keys
|
||||
Datum uni;
|
||||
GBT_VARKEY_R rk, ok, uk;
|
||||
|
||||
// Make the original key readable and store it in rk
|
||||
rk = gbt_var_key_readable(org);
|
||||
|
||||
// Create a copy of the original key and store it in uni
|
||||
uni = PointerGetDatum(gbt_var_key_copy(&rk, TRUE));
|
||||
|
||||
// Perform a union operation on the original and new keys and update uni
|
||||
gbt_var_bin_union(&uni, newe, PG_GET_COLLATION(), &tinfo);
|
||||
|
||||
// Make the original key readable and store it in ok
|
||||
ok = gbt_var_key_readable(org);
|
||||
|
||||
// Make the union key readable and store it in uk
|
||||
uk = gbt_var_key_readable((GBT_VARKEY*)DatumGetPointer(uni));
|
||||
|
||||
// Calculate the upper and lower bounds of the union and store them in us
|
||||
us = DatumGetNumeric(DirectFunctionCall2(numeric_sub, PointerGetDatum(uk.upper), PointerGetDatum(uk.lower)));
|
||||
|
||||
// Calculate the upper and lower bounds of the original key and store them in os
|
||||
os = DatumGetNumeric(DirectFunctionCall2(numeric_sub, PointerGetDatum(ok.upper), PointerGetDatum(ok.lower)));
|
||||
|
||||
// Calculate the difference between us and os and store it in ds
|
||||
ds = DatumGetNumeric(DirectFunctionCall2(numeric_sub, NumericGetDatum(us), NumericGetDatum(os)));
|
||||
|
||||
// Check if us is NaN (Not a Number)
|
||||
if (numeric_is_nan(us)) {
|
||||
// If os is also NaN, set the result to 0.0; otherwise, set it to 1.0
|
||||
if (numeric_is_nan(os))
|
||||
*result = 0.0;
|
||||
else
|
||||
*result = 1.0;
|
||||
} else {
|
||||
// Create a numeric value representing 0 and store it in nul
|
||||
Numeric nul = DatumGetNumeric(DirectFunctionCall1(int4_numeric, Int32GetDatum(0)));
|
||||
|
||||
// Initialize the result to 0.0
|
||||
*result = 0.0;
|
||||
|
||||
// Check if ds is greater than nul and, if so, update the result accordingly
|
||||
if (DirectFunctionCall2(numeric_gt, NumericGetDatum(ds), NumericGetDatum(nul))) {
|
||||
*result += FLT_MIN;
|
||||
os = DatumGetNumeric(DirectFunctionCall2(numeric_div, NumericGetDatum(ds), NumericGetDatum(us)));
|
||||
*result += (float4)DatumGetFloat8(DirectFunctionCall1(numeric_float8_no_overflow, NumericGetDatum(os)));
|
||||
}
|
||||
}
|
||||
|
||||
// If the result is greater than 0, scale it by a certain factor and return it as a pointer; otherwise, return it as-is
|
||||
if (*result > 0)
|
||||
*result *= (FLT_MAX / (((GISTENTRY*)PG_GETARG_POINTER(0))->rel->rd_att->natts + 1));
|
||||
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
Datum gbt_numeric_picksplit(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector* entryvec = (GistEntryVector*)PG_GETARG_POINTER(0);
|
||||
GIST_SPLITVEC* v = (GIST_SPLITVEC*)PG_GETARG_POINTER(1);
|
||||
|
||||
gbt_var_picksplit(entryvec, v, PG_GET_COLLATION(), &tinfo);
|
||||
PG_RETURN_POINTER(v);
|
||||
// Function to perform a picksplit operation on numeric values using GBT
|
||||
Datum gbt_numeric_picksplit(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Pointer to the GistEntryVector containing the GIST entries
|
||||
GistEntryVector* entryvec = (GistEntryVector*)PG_GETARG_POINTER(0);
|
||||
|
||||
// Pointer to the GIST_SPLITVEC that will store the result of the picksplit operation
|
||||
GIST_SPLITVEC* v = (GIST_SPLITVEC*)PG_GETARG_POINTER(1);
|
||||
|
||||
// Perform the picksplit operation using gbt_var_picksplit and store the result in v
|
||||
gbt_var_picksplit(entryvec, v, PG_GET_COLLATION(), &tinfo);
|
||||
|
||||
// Return the result as a pointer
|
||||
PG_RETURN_POINTER(v);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,164 +15,199 @@ typedef struct {
|
|||
/*
|
||||
** OID ops
|
||||
*/
|
||||
PG_FUNCTION_INFO_V1(gbt_oid_compress);
|
||||
PG_FUNCTION_INFO_V1(gbt_oid_union);
|
||||
PG_FUNCTION_INFO_V1(gbt_oid_picksplit);
|
||||
PG_FUNCTION_INFO_V1(gbt_oid_consistent);
|
||||
PG_FUNCTION_INFO_V1(gbt_oid_distance);
|
||||
PG_FUNCTION_INFO_V1(gbt_oid_penalty);
|
||||
PG_FUNCTION_INFO_V1(gbt_oid_same);
|
||||
|
||||
extern "C" Datum gbt_oid_compress(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gbt_oid_union(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gbt_oid_picksplit(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gbt_oid_consistent(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gbt_oid_distance(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gbt_oid_penalty(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gbt_oid_same(PG_FUNCTION_ARGS);
|
||||
|
||||
static bool gbt_oidgt(const void* a, const void* b)
|
||||
{
|
||||
return (*((const Oid*)a) > *((const Oid*)b));
|
||||
}
|
||||
static bool gbt_oidge(const void* a, const void* b)
|
||||
{
|
||||
return (*((const Oid*)a) >= *((const Oid*)b));
|
||||
}
|
||||
static bool gbt_oideq(const void* a, const void* b)
|
||||
{
|
||||
return (*((const Oid*)a) == *((const Oid*)b));
|
||||
}
|
||||
static bool gbt_oidle(const void* a, const void* b)
|
||||
{
|
||||
return (*((const Oid*)a) <= *((const Oid*)b));
|
||||
}
|
||||
static bool gbt_oidlt(const void* a, const void* b)
|
||||
{
|
||||
return (*((const Oid*)a) < *((const Oid*)b));
|
||||
// These macros define the function information for each of the GiST functions.
|
||||
PG_FUNCTION_INFO_V1(gbt_oid_compress);
|
||||
PG_FUNCTION_INFO_V1(gbt_oid_union);
|
||||
PG_FUNCTION_INFO_V1(gbt_oid_picksplit);
|
||||
PG_FUNCTION_INFO_V1(gbt_oid_consistent);
|
||||
PG_FUNCTION_INFO_V1(gbt_oid_distance);
|
||||
PG_FUNCTION_INFO_V1(gbt_oid_penalty);
|
||||
PG_FUNCTION_INFO_V1(gbt_oid_same);
|
||||
|
||||
// These functions are defined as extern "C" because they are called from C code.
|
||||
// Each function takes PG_FUNCTION_ARGS as parameters and returns a Datum.
|
||||
extern "C" Datum gbt_oid_compress(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gbt_oid_union(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gbt_oid_picksplit(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gbt_oid_consistent(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gbt_oid_distance(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gbt_oid_penalty(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gbt_oid_same(PG_FUNCTION_ARGS);
|
||||
|
||||
// These functions are used to compare Oids. They take two void pointers and return a bool.
|
||||
static bool gbt_oidgt(const void* a, const void* b)
|
||||
{
|
||||
// Compare the Oids and return true if the first is greater than the second.
|
||||
return (*((const Oid*)a) > *((const Oid*)b));
|
||||
}
|
||||
static bool gbt_oidge(const void* a, const void* b)
|
||||
{
|
||||
// Compare the Oids and return true if the first is greater than or equal to the second.
|
||||
return (*((const Oid*)a) >= *((const Oid*)b));
|
||||
}
|
||||
static bool gbt_oideq(const void* a, const void* b)
|
||||
{
|
||||
// Compare the Oids and return true if they are equal.
|
||||
return (*((const Oid*)a) == *((const Oid*)b));
|
||||
}
|
||||
static bool gbt_oidle(const void* a, const void* b)
|
||||
{
|
||||
// Compare the Oids and return true if the first is less than or equal to the second.
|
||||
return (*((const Oid*)a) <= *((const Oid*)b));
|
||||
}
|
||||
static bool gbt_oidlt(const void* a, const void* b)
|
||||
{
|
||||
// Compare the Oids and return true if the first is less than the second.
|
||||
return (*((const Oid*)a) < *((const Oid*)b));
|
||||
}
|
||||
|
||||
static int gbt_oidkey_cmp(const void* a, const void* b)
|
||||
{
|
||||
oidKEY* ia = (oidKEY*)(((const Nsrt*)a)->t);
|
||||
oidKEY* ib = (oidKEY*)(((const Nsrt*)b)->t);
|
||||
|
||||
if (ia->lower == ib->lower) {
|
||||
if (ia->upper == ib->upper)
|
||||
return 0;
|
||||
|
||||
return (ia->upper > ib->upper) ? 1 : -1;
|
||||
}
|
||||
|
||||
return (ia->lower > ib->lower) ? 1 : -1;
|
||||
// Define a function to compare two oidKEYs.
|
||||
static int gbt_oidkey_cmp(const void* a, const void* b)
|
||||
{
|
||||
oidKEY* ia = (oidKEY*)(((const Nsrt*)a)->t);
|
||||
oidKEY* ib = (oidKEY*)(((const Nsrt*)b)->t);
|
||||
|
||||
// Compare the lower and upper bounds of the oidKEYs.
|
||||
if (ia->lower == ib->lower) {
|
||||
if (ia->upper == ib->upper)
|
||||
return 0;
|
||||
|
||||
return (ia->upper > ib->upper) ? 1 : -1;
|
||||
}
|
||||
|
||||
return (ia->lower > ib->lower) ? 1 : -1;
|
||||
}
|
||||
|
||||
// Define a function to calculate the distance between two Oids.
|
||||
static float8 gbt_oid_dist(const void* a, const void* b)
|
||||
{
|
||||
Oid aa = *(const Oid*)a;
|
||||
Oid bb = *(const Oid*)b;
|
||||
|
||||
// Calculate the distance between the two Oids.
|
||||
if (aa < bb)
|
||||
return (float8)(bb - aa);
|
||||
else
|
||||
return (float8)(aa - bb);
|
||||
}
|
||||
|
||||
// Define the tree information for the GiST index.
|
||||
static const gbtree_ninfo tinfo = {
|
||||
gbt_t_oid, sizeof(Oid), gbt_oidgt, gbt_oidge, gbt_oideq, gbt_oidle, gbt_oidlt, gbt_oidkey_cmp, gbt_oid_dist};
|
||||
|
||||
// Define the function information for the oid_dist function.
|
||||
PG_FUNCTION_INFO_V1(oid_dist);
|
||||
extern "C" Datum oid_dist(PG_FUNCTION_ARGS);
|
||||
Datum oid_dist(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid a = PG_GETARG_OID(0);
|
||||
Oid b = PG_GETARG_OID(1);
|
||||
Oid res;
|
||||
|
||||
// Calculate the distance between the two Oids.
|
||||
if (a < b)
|
||||
res = b - a;
|
||||
else
|
||||
res = a - b;
|
||||
PG_RETURN_OID(res);
|
||||
}
|
||||
|
||||
static float8 gbt_oid_dist(const void* a, const void* b)
|
||||
{
|
||||
Oid aa = *(const Oid*)a;
|
||||
Oid bb = *(const Oid*)b;
|
||||
|
||||
if (aa < bb)
|
||||
return (float8)(bb - aa);
|
||||
else
|
||||
return (float8)(aa - bb);
|
||||
}
|
||||
|
||||
static const gbtree_ninfo tinfo = {
|
||||
gbt_t_oid, sizeof(Oid), gbt_oidgt, gbt_oidge, gbt_oideq, gbt_oidle, gbt_oidlt, gbt_oidkey_cmp, gbt_oid_dist};
|
||||
|
||||
PG_FUNCTION_INFO_V1(oid_dist);
|
||||
extern "C" Datum oid_dist(PG_FUNCTION_ARGS);
|
||||
Datum oid_dist(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid a = PG_GETARG_OID(0);
|
||||
Oid b = PG_GETARG_OID(1);
|
||||
Oid res;
|
||||
|
||||
if (a < b)
|
||||
res = b - a;
|
||||
else
|
||||
res = a - b;
|
||||
PG_RETURN_OID(res);
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Oid ops
|
||||
**************************************************/
|
||||
|
||||
Datum gbt_oid_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
GISTENTRY* retval = NULL;
|
||||
|
||||
PG_RETURN_POINTER(gbt_num_compress(retval, entry, &tinfo));
|
||||
// Function to compress a GiST entry.
|
||||
// It takes a single argument of type GISTENTRY* and returns a pointer to the compressed entry.
|
||||
Datum gbt_oid_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
GISTENTRY* retval = NULL;
|
||||
|
||||
PG_RETURN_POINTER(gbt_num_compress(retval, entry, &tinfo));
|
||||
}
|
||||
|
||||
// Function to check if an Oid is consistent with a GiST entry.
|
||||
// It takes four arguments: a GISTENTRY*, an Oid, a StrategyNumber, and a bool*.
|
||||
// The function sets the bool* to false, indicating that all cases served by this function are exact.
|
||||
// It returns a bool indicating if the Oid is consistent with the GiST entry.
|
||||
Datum gbt_oid_consistent(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
Oid query = PG_GETARG_OID(1);
|
||||
StrategyNumber strategy = (StrategyNumber)PG_GETARG_UINT16(2);
|
||||
|
||||
bool* recheck = (bool*)PG_GETARG_POINTER(4);
|
||||
oidKEY* kkk = (oidKEY*)DatumGetPointer(entry->key);
|
||||
GBT_NUMKEY_R key;
|
||||
|
||||
/* All cases served by this function are exact */
|
||||
*recheck = false;
|
||||
|
||||
key.lower = (GBT_NUMKEY*)&kkk->lower;
|
||||
key.upper = (GBT_NUMKEY*)&kkk->upper;
|
||||
|
||||
PG_RETURN_BOOL(gbt_num_consistent(&key, (void*)&query, &strategy, GIST_LEAF(entry), &tinfo));
|
||||
}
|
||||
|
||||
// Function to calculate the distance between an Oid and a GiST entry.
|
||||
// It takes two arguments: a GISTENTRY* and an Oid.
|
||||
// The function returns a float8 representing the distance between the Oid and the GiST entry.
|
||||
Datum gbt_oid_distance(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
Oid query = PG_GETARG_OID(1);
|
||||
|
||||
oidKEY* kkk = (oidKEY*)DatumGetPointer(entry->key);
|
||||
GBT_NUMKEY_R key;
|
||||
|
||||
key.lower = (GBT_NUMKEY*)&kkk->lower;
|
||||
key.upper = (GBT_NUMKEY*)&kkk->upper;
|
||||
|
||||
PG_RETURN_FLOAT8(gbt_num_distance(&key, (void*)&query, GIST_LEAF(entry), &tinfo));
|
||||
}
|
||||
|
||||
Datum gbt_oid_consistent(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
Oid query = PG_GETARG_OID(1);
|
||||
StrategyNumber strategy = (StrategyNumber)PG_GETARG_UINT16(2);
|
||||
|
||||
bool* recheck = (bool*)PG_GETARG_POINTER(4);
|
||||
oidKEY* kkk = (oidKEY*)DatumGetPointer(entry->key);
|
||||
GBT_NUMKEY_R key;
|
||||
|
||||
/* All cases served by this function are exact */
|
||||
*recheck = false;
|
||||
|
||||
key.lower = (GBT_NUMKEY*)&kkk->lower;
|
||||
key.upper = (GBT_NUMKEY*)&kkk->upper;
|
||||
|
||||
PG_RETURN_BOOL(gbt_num_consistent(&key, (void*)&query, &strategy, GIST_LEAF(entry), &tinfo));
|
||||
}
|
||||
|
||||
Datum gbt_oid_distance(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
Oid query = PG_GETARG_OID(1);
|
||||
|
||||
oidKEY* kkk = (oidKEY*)DatumGetPointer(entry->key);
|
||||
GBT_NUMKEY_R key;
|
||||
|
||||
key.lower = (GBT_NUMKEY*)&kkk->lower;
|
||||
key.upper = (GBT_NUMKEY*)&kkk->upper;
|
||||
|
||||
PG_RETURN_FLOAT8(gbt_num_distance(&key, (void*)&query, GIST_LEAF(entry), &tinfo));
|
||||
}
|
||||
|
||||
Datum gbt_oid_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector* entryvec = (GistEntryVector*)PG_GETARG_POINTER(0);
|
||||
void* out = palloc(sizeof(oidKEY));
|
||||
|
||||
*(int*)PG_GETARG_POINTER(1) = sizeof(oidKEY);
|
||||
PG_RETURN_POINTER(gbt_num_union((GBT_NUMKEY*)out, entryvec, &tinfo));
|
||||
}
|
||||
|
||||
Datum gbt_oid_penalty(PG_FUNCTION_ARGS)
|
||||
{
|
||||
oidKEY* origentry = (oidKEY*)DatumGetPointer(((GISTENTRY*)PG_GETARG_POINTER(0))->key);
|
||||
oidKEY* newentry = (oidKEY*)DatumGetPointer(((GISTENTRY*)PG_GETARG_POINTER(1))->key);
|
||||
float* result = (float*)PG_GETARG_POINTER(2);
|
||||
|
||||
penalty_num(result, origentry->lower, origentry->upper, newentry->lower, newentry->upper);
|
||||
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
Datum gbt_oid_picksplit(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_POINTER(
|
||||
gbt_num_picksplit((GistEntryVector*)PG_GETARG_POINTER(0), (GIST_SPLITVEC*)PG_GETARG_POINTER(1), &tinfo));
|
||||
}
|
||||
|
||||
Datum gbt_oid_same(PG_FUNCTION_ARGS)
|
||||
{
|
||||
oidKEY* b1 = (oidKEY*)PG_GETARG_POINTER(0);
|
||||
oidKEY* b2 = (oidKEY*)PG_GETARG_POINTER(1);
|
||||
bool* result = (bool*)PG_GETARG_POINTER(2);
|
||||
|
||||
*result = gbt_num_same((GBT_NUMKEY*)b1, (GBT_NUMKEY*)b2, &tinfo);
|
||||
PG_RETURN_POINTER(result);
|
||||
// Function to union a GiST entry vector.
|
||||
// It takes a single argument of type GistEntryVector* and returns a pointer to the unioned entry.
|
||||
Datum gbt_oid_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector* entryvec = (GistEntryVector*)PG_GETARG_POINTER(0);
|
||||
void* out = palloc(sizeof(oidKEY));
|
||||
|
||||
*(int*)PG_GETARG_POINTER(1) = sizeof(oidKEY);
|
||||
PG_RETURN_POINTER(gbt_num_union((GBT_NUMKEY*)out, entryvec, &tinfo));
|
||||
}
|
||||
|
||||
// Function to calculate the penalty of merging two GiST entries.
|
||||
// It takes two arguments of type oidKEY* and a float*.
|
||||
// The function calls penalty_num to calculate the penalty and returns a pointer to the result.
|
||||
Datum gbt_oid_penalty(PG_FUNCTION_ARGS)
|
||||
{
|
||||
oidKEY* origentry = (oidKEY*)DatumGetPointer(((GISTENTRY*)PG_GETARG_POINTER(0))->key);
|
||||
oidKEY* newentry = (oidKEY*)DatumGetPointer(((GISTENTRY*)PG_GETARG_POINTER(1))->key);
|
||||
float* result = (float*)PG_GETARG_POINTER(2);
|
||||
|
||||
penalty_num(result, origentry->lower, origentry->upper, newentry->lower, newentry->upper);
|
||||
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
// Function to pick a split point for a GiST entry vector.
|
||||
// It takes two arguments of type GistEntryVector* and GIST_SPLITVEC*.
|
||||
// The function returns a pointer to the split point.
|
||||
Datum gbt_oid_picksplit(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_POINTER(
|
||||
gbt_num_picksplit((GistEntryVector*)PG_GETARG_POINTER(0), (GIST_SPLITVEC*)PG_GETARG_POINTER(1), &tinfo));
|
||||
}
|
||||
|
||||
// Function to check if two GiST entries are the same.
|
||||
// It takes two arguments of type oidKEY* and a bool*.
|
||||
// The function calls gbt_num_same to check if the entries are the same and returns a pointer to the result.
|
||||
Datum gbt_oid_same(PG_FUNCTION_ARGS)
|
||||
{
|
||||
oidKEY* b1 = (oidKEY*)PG_GETARG_POINTER(0);
|
||||
oidKEY* b2 = (oidKEY*)PG_GETARG_POINTER(1);
|
||||
bool* result = (bool*)PG_GETARG_POINTER(2);
|
||||
|
||||
*result = gbt_num_same((GBT_NUMKEY*)b1, (GBT_NUMKEY*)b2, &tinfo);
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,118 +68,158 @@ static gbtree_vinfo tinfo = {
|
|||
* Text ops
|
||||
**************************************************/
|
||||
|
||||
Datum gbt_text_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
|
||||
if (tinfo.eml == 0) {
|
||||
tinfo.eml = pg_database_encoding_max_length();
|
||||
}
|
||||
|
||||
PG_RETURN_POINTER(gbt_var_compress(entry, &tinfo));
|
||||
// Function to compress a GiST entry for text type.
|
||||
// It takes a single argument of type GISTENTRY* and returns a pointer to the compressed entry.
|
||||
// If the tinfo.eml is 0, it sets it to the maximum length of the database encoding.
|
||||
Datum gbt_text_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
|
||||
if (tinfo.eml == 0) {
|
||||
tinfo.eml = pg_database_encoding_max_length();
|
||||
}
|
||||
|
||||
PG_RETURN_POINTER(gbt_var_compress(entry, &tinfo));
|
||||
}
|
||||
|
||||
// Function to compress a GiST entry for bpchar type.
|
||||
// It takes a single argument of type GISTENTRY* and returns a pointer to the compressed entry.
|
||||
// If the tinfo.eml is 0, it sets it to the maximum length of the database encoding.
|
||||
// If the entry is a leafkey, it trims the key and compresses the trimmed entry. Otherwise, it returns the entry as it is.
|
||||
Datum gbt_bpchar_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
GISTENTRY* retval = NULL;
|
||||
|
||||
if (tinfo.eml == 0) {
|
||||
tinfo.eml = pg_database_encoding_max_length();
|
||||
}
|
||||
|
||||
if (entry->leafkey) {
|
||||
Datum d = DirectFunctionCall1(rtrim1, entry->key);
|
||||
GISTENTRY trim;
|
||||
|
||||
gistentryinit(trim, d, entry->rel, entry->page, entry->offset, TRUE);
|
||||
retval = gbt_var_compress(&trim, &tinfo);
|
||||
} else
|
||||
retval = entry;
|
||||
|
||||
PG_RETURN_POINTER(retval);
|
||||
}
|
||||
|
||||
// Function to check if a text is consistent with a GiST entry for text type.
|
||||
// It takes four arguments: a GISTENTRY*, a void* representing the text, a StrategyNumber, and a bool*.
|
||||
// The function sets the bool* to false, indicating that all cases served by this function are exact.
|
||||
// It returns a bool indicating if the text is consistent with the GiST entry.
|
||||
// If the tinfo.eml is 0, it sets it to the maximum length of the database encoding.
|
||||
Datum gbt_text_consistent(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
void* query = (void*)DatumGetTextP(PG_GETARG_DATUM(1));
|
||||
StrategyNumber strategy = (StrategyNumber)PG_GETARG_UINT16(2);
|
||||
|
||||
bool* recheck = (bool*)PG_GETARG_POINTER(4);
|
||||
bool retval = false;
|
||||
GBT_VARKEY* key = (GBT_VARKEY*)DatumGetPointer(entry->key);
|
||||
GBT_VARKEY_R r = gbt_var_key_readable(key);
|
||||
|
||||
/* All cases served by this function are exact */
|
||||
*recheck = false;
|
||||
|
||||
if (tinfo.eml == 0) {
|
||||
tinfo.eml = pg_database_encoding_max_length();
|
||||
}
|
||||
|
||||
retval = gbt_var_consistent(&r, query, strategy, PG_GET_COLLATION(), GIST_LEAF(entry), &tinfo);
|
||||
|
||||
PG_RETURN_BOOL(retval);
|
||||
}
|
||||
|
||||
Datum gbt_bpchar_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
GISTENTRY* retval = NULL;
|
||||
|
||||
if (tinfo.eml == 0) {
|
||||
tinfo.eml = pg_database_encoding_max_length();
|
||||
}
|
||||
|
||||
if (entry->leafkey) {
|
||||
|
||||
Datum d = DirectFunctionCall1(rtrim1, entry->key);
|
||||
GISTENTRY trim;
|
||||
|
||||
gistentryinit(trim, d, entry->rel, entry->page, entry->offset, TRUE);
|
||||
retval = gbt_var_compress(&trim, &tinfo);
|
||||
} else
|
||||
retval = entry;
|
||||
|
||||
PG_RETURN_POINTER(retval);
|
||||
}
|
||||
|
||||
Datum gbt_text_consistent(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
void* query = (void*)DatumGetTextP(PG_GETARG_DATUM(1));
|
||||
StrategyNumber strategy = (StrategyNumber)PG_GETARG_UINT16(2);
|
||||
|
||||
bool* recheck = (bool*)PG_GETARG_POINTER(4);
|
||||
bool retval = false;
|
||||
GBT_VARKEY* key = (GBT_VARKEY*)DatumGetPointer(entry->key);
|
||||
GBT_VARKEY_R r = gbt_var_key_readable(key);
|
||||
|
||||
/* All cases served by this function are exact */
|
||||
*recheck = false;
|
||||
|
||||
if (tinfo.eml == 0) {
|
||||
tinfo.eml = pg_database_encoding_max_length();
|
||||
}
|
||||
|
||||
retval = gbt_var_consistent(&r, query, strategy, PG_GET_COLLATION(), GIST_LEAF(entry), &tinfo);
|
||||
|
||||
PG_RETURN_BOOL(retval);
|
||||
}
|
||||
|
||||
Datum gbt_bpchar_consistent(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
void* query = (void*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(1)));
|
||||
StrategyNumber strategy = (StrategyNumber)PG_GETARG_UINT16(2);
|
||||
|
||||
bool* recheck = (bool*)PG_GETARG_POINTER(4);
|
||||
bool retval = false;
|
||||
GBT_VARKEY* key = (GBT_VARKEY*)DatumGetPointer(entry->key);
|
||||
GBT_VARKEY_R r = gbt_var_key_readable(key);
|
||||
void* trim = (void*)DatumGetPointer(DirectFunctionCall1(rtrim1, PointerGetDatum(query)));
|
||||
|
||||
/* All cases served by this function are exact */
|
||||
*recheck = false;
|
||||
|
||||
if (tinfo.eml == 0) {
|
||||
tinfo.eml = pg_database_encoding_max_length();
|
||||
}
|
||||
|
||||
retval = gbt_var_consistent(&r, trim, strategy, PG_GET_COLLATION(), GIST_LEAF(entry), &tinfo);
|
||||
PG_RETURN_BOOL(retval);
|
||||
}
|
||||
|
||||
Datum gbt_text_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector* entryvec = (GistEntryVector*)PG_GETARG_POINTER(0);
|
||||
int32* size = (int*)PG_GETARG_POINTER(1);
|
||||
|
||||
PG_RETURN_POINTER(gbt_var_union(entryvec, size, PG_GET_COLLATION(), &tinfo));
|
||||
}
|
||||
|
||||
Datum gbt_text_picksplit(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector* entryvec = (GistEntryVector*)PG_GETARG_POINTER(0);
|
||||
GIST_SPLITVEC* v = (GIST_SPLITVEC*)PG_GETARG_POINTER(1);
|
||||
|
||||
gbt_var_picksplit(entryvec, v, PG_GET_COLLATION(), &tinfo);
|
||||
PG_RETURN_POINTER(v);
|
||||
}
|
||||
|
||||
Datum gbt_text_same(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum d1 = PG_GETARG_DATUM(0);
|
||||
Datum d2 = PG_GETARG_DATUM(1);
|
||||
bool* result = (bool*)PG_GETARG_POINTER(2);
|
||||
|
||||
*result = gbt_var_same(d1, d2, PG_GET_COLLATION(), &tinfo);
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
Datum gbt_text_penalty(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* o = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
GISTENTRY* n = (GISTENTRY*)PG_GETARG_POINTER(1);
|
||||
float* result = (float*)PG_GETARG_POINTER(2);
|
||||
|
||||
PG_RETURN_POINTER(gbt_var_penalty(result, o, n, PG_GET_COLLATION(), &tinfo));
|
||||
// Check if a bpchar is consistent with a GiST entry for bpchar type.
|
||||
Datum gbt_bpchar_consistent(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Get the GiST entry.
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
// Get the query.
|
||||
void* query = (void*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(1)));
|
||||
// Get the strategy.
|
||||
StrategyNumber strategy = (StrategyNumber)PG_GETARG_UINT16(2);
|
||||
|
||||
// Get the recheck boolean.
|
||||
bool* recheck = (bool*)PG_GETARG_POINTER(4);
|
||||
// Initialize the return value.
|
||||
bool retval = false;
|
||||
// Get the key.
|
||||
GBT_VARKEY* key = (GBT_VARKEY*)DatumGetPointer(entry->key);
|
||||
// Make the key readable.
|
||||
GBT_VARKEY_R r = gbt_var_key_readable(key);
|
||||
// Trim the query.
|
||||
void* trim = (void*)DatumGetPointer(DirectFunctionCall1(rtrim1, PointerGetDatum(query)));
|
||||
|
||||
// All cases served by this function are exact.
|
||||
*recheck = false;
|
||||
|
||||
// If the tinfo.eml is 0, set it to the maximum length of the database encoding.
|
||||
if (tinfo.eml == 0) {
|
||||
tinfo.eml = pg_database_encoding_max_length();
|
||||
}
|
||||
|
||||
// Check if the query is consistent with the GiST entry.
|
||||
retval = gbt_var_consistent(&r, trim, strategy, PG_GET_COLLATION(), GIST_LEAF(entry), &tinfo);
|
||||
// Return the result.
|
||||
PG_RETURN_BOOL(retval);
|
||||
}
|
||||
|
||||
// Union GiST entries for text type.
|
||||
Datum gbt_text_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Get the GiST entry vector.
|
||||
GistEntryVector* entryvec = (GistEntryVector*)PG_GETARG_POINTER(0);
|
||||
// Get the size.
|
||||
int32* size = (int*)PG_GETARG_POINTER(1);
|
||||
|
||||
// Union the entries and return the result.
|
||||
PG_RETURN_POINTER(gbt_var_union(entryvec, size, PG_GET_COLLATION(), &tinfo));
|
||||
}
|
||||
|
||||
// Split GiST entries for text type.
|
||||
Datum gbt_text_picksplit(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Get the GiST entry vector.
|
||||
GistEntryVector* entryvec = (GistEntryVector*)PG_GETARG_POINTER(0);
|
||||
// Get the split vector.
|
||||
GIST_SPLITVEC* v = (GIST_SPLITVEC*)PG_GETARG_POINTER(1);
|
||||
|
||||
// Split the entries.
|
||||
gbt_var_picksplit(entryvec, v, PG_GET_COLLATION(), &tinfo);
|
||||
// Return the split vector.
|
||||
PG_RETURN_POINTER(v);
|
||||
}
|
||||
|
||||
// Check if two text values are the same.
|
||||
Datum gbt_text_same(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Get the two text values.
|
||||
Datum d1 = PG_GETARG_DATUM(0);
|
||||
Datum d2 = PG_GETARG_DATUM(1);
|
||||
// Get the result boolean.
|
||||
bool* result = (bool*)PG_GETARG_POINTER(2);
|
||||
|
||||
// Check if the two text values are the same.
|
||||
*result = gbt_var_same(d1, d2, PG_GET_COLLATION(), &tinfo);
|
||||
// Return the result.
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
// Calculate the penalty for GiST entries for text type.
|
||||
Datum gbt_text_penalty(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Get the two GiST entries.
|
||||
GISTENTRY* o = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
GISTENTRY* n = (GISTENTRY*)PG_GETARG_POINTER(1);
|
||||
// Get the result float.
|
||||
float* result = (float*)PG_GETARG_POINTER(2);
|
||||
|
||||
// Calculate the penalty
|
||||
PG_RETURN_POINTER(gbt_var_penalty(result,o,n,PG_GET_COLLATION(),&tinfo));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,133 +43,180 @@ extern "C" Datum gbt_time_same(PG_FUNCTION_ARGS);
|
|||
#define TimeADTGetDatumFast(X) PointerGetDatum(&(X))
|
||||
#endif
|
||||
|
||||
static bool gbt_timegt(const void* a, const void* b)
|
||||
{
|
||||
const TimeADT* aa = (const TimeADT*)a;
|
||||
const TimeADT* bb = (const TimeADT*)b;
|
||||
|
||||
return DatumGetBool(DirectFunctionCall2(time_gt, TimeADTGetDatumFast(*aa), TimeADTGetDatumFast(*bb)));
|
||||
// Compare if time a is greater than time b
|
||||
static bool gbt_timegt(const void* a, const void* b)
|
||||
{
|
||||
const TimeADT* aa = (const TimeADT*)a; // Cast void pointer a to TimeADT pointer
|
||||
const TimeADT* bb = (const TimeADT*)b; // Cast void pointer b to TimeADT pointer
|
||||
|
||||
// Use the function time_gt to compare the two time objects, and return the result as a boolean value
|
||||
return DatumGetBool(DirectFunctionCall2(time_gt, TimeADTGetDatumFast(*aa), TimeADTGetDatumFast(*bb)));
|
||||
}
|
||||
|
||||
// Compare if time a is greater than or equal to time b
|
||||
static bool gbt_timege(const void* a, const void* b)
|
||||
{
|
||||
const TimeADT* aa = (const TimeADT*)a; // Cast void pointer a to TimeADT pointer
|
||||
const TimeADT* bb = (const TimeADT*)b; // Cast void pointer b to TimeADT pointer
|
||||
|
||||
// Use the function time_ge to compare the two time objects, and return the result as a boolean value
|
||||
return DatumGetBool(DirectFunctionCall2(time_ge, TimeADTGetDatumFast(*aa), TimeADTGetDatumFast(*bb)));
|
||||
}
|
||||
|
||||
// Compare if time a is equal to time b
|
||||
static bool gbt_timeeq(const void* a, const void* b)
|
||||
{
|
||||
const TimeADT* aa = (const TimeADT*)a; // Cast void pointer a to TimeADT pointer
|
||||
const TimeADT* bb = (const TimeADT*)b; // Cast void pointer b to TimeADT pointer
|
||||
|
||||
// Use the function time_eq to compare the two time objects, and return the result as a boolean value
|
||||
return DatumGetBool(DirectFunctionCall2(time_eq, TimeADTGetDatumFast(*aa), TimeADTGetDatumFast(*bb)));
|
||||
}
|
||||
|
||||
// Compare if time a is less than or equal to time b
|
||||
static bool gbt_timele(const void* a, const void* b)
|
||||
{
|
||||
const TimeADT* aa = (const TimeADT*)a; // Cast void pointer a to TimeADT pointer
|
||||
const TimeADT* bb = (const TimeADT*)b; // Cast void pointer b to TimeADT pointer
|
||||
|
||||
// Use the function time_le to compare the two time objects, and return the result as a boolean value
|
||||
return DatumGetBool(DirectFunctionCall2(time_le, TimeADTGetDatumFast(*aa), TimeADTGetDatumFast(*bb)));
|
||||
}
|
||||
|
||||
// Compare if time a is less than time b
|
||||
static bool gbt_timelt(const void* a, const void* b)
|
||||
{
|
||||
const TimeADT* aa = (const TimeADT*)a; // Cast void pointer a to TimeADT pointer
|
||||
const TimeADT* bb = (const TimeADT*)b; // Cast void pointer b to TimeADT pointer
|
||||
|
||||
// Use the function time_lt to compare the two time objects, and return the result as a boolean value
|
||||
return DatumGetBool(DirectFunctionCall2(time_lt, TimeADTGetDatumFast(*aa), TimeADTGetDatumFast(*bb)));
|
||||
}
|
||||
|
||||
static bool gbt_timege(const void* a, const void* b)
|
||||
{
|
||||
const TimeADT* aa = (const TimeADT*)a;
|
||||
const TimeADT* bb = (const TimeADT*)b;
|
||||
|
||||
return DatumGetBool(DirectFunctionCall2(time_ge, TimeADTGetDatumFast(*aa), TimeADTGetDatumFast(*bb)));
|
||||
}
|
||||
|
||||
static bool gbt_timeeq(const void* a, const void* b)
|
||||
{
|
||||
const TimeADT* aa = (const TimeADT*)a;
|
||||
const TimeADT* bb = (const TimeADT*)b;
|
||||
|
||||
return DatumGetBool(DirectFunctionCall2(time_eq, TimeADTGetDatumFast(*aa), TimeADTGetDatumFast(*bb)));
|
||||
}
|
||||
|
||||
static bool gbt_timele(const void* a, const void* b)
|
||||
{
|
||||
const TimeADT* aa = (const TimeADT*)a;
|
||||
const TimeADT* bb = (const TimeADT*)b;
|
||||
|
||||
return DatumGetBool(DirectFunctionCall2(time_le, TimeADTGetDatumFast(*aa), TimeADTGetDatumFast(*bb)));
|
||||
}
|
||||
|
||||
static bool gbt_timelt(const void* a, const void* b)
|
||||
{
|
||||
const TimeADT* aa = (const TimeADT*)a;
|
||||
const TimeADT* bb = (const TimeADT*)b;
|
||||
|
||||
return DatumGetBool(DirectFunctionCall2(time_lt, TimeADTGetDatumFast(*aa), TimeADTGetDatumFast(*bb)));
|
||||
}
|
||||
|
||||
static int gbt_timekey_cmp(const void* a, const void* b)
|
||||
{
|
||||
timeKEY* ia = (timeKEY*)(((const Nsrt*)a)->t);
|
||||
timeKEY* ib = (timeKEY*)(((const Nsrt*)b)->t);
|
||||
int res;
|
||||
|
||||
res = DatumGetInt32(DirectFunctionCall2(time_cmp, TimeADTGetDatumFast(ia->lower), TimeADTGetDatumFast(ib->lower)));
|
||||
if (res == 0)
|
||||
return DatumGetInt32(
|
||||
DirectFunctionCall2(time_cmp, TimeADTGetDatumFast(ia->upper), TimeADTGetDatumFast(ib->upper)));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static float8 gbt_time_dist(const void* a, const void* b)
|
||||
{
|
||||
const TimeADT* aa = (const TimeADT*)a;
|
||||
const TimeADT* bb = (const TimeADT*)b;
|
||||
Interval* i = NULL;
|
||||
|
||||
i = DatumGetIntervalP(DirectFunctionCall2(time_mi_time, TimeADTGetDatumFast(*aa), TimeADTGetDatumFast(*bb)));
|
||||
return (float8)Abs(INTERVAL_TO_SEC(i));
|
||||
}
|
||||
|
||||
static const gbtree_ninfo tinfo = {gbt_t_time,
|
||||
sizeof(TimeADT),
|
||||
gbt_timegt,
|
||||
gbt_timege,
|
||||
gbt_timeeq,
|
||||
gbt_timele,
|
||||
gbt_timelt,
|
||||
gbt_timekey_cmp,
|
||||
gbt_time_dist};
|
||||
|
||||
PG_FUNCTION_INFO_V1(time_dist);
|
||||
extern "C" Datum time_dist(PG_FUNCTION_ARGS);
|
||||
Datum time_dist(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum diff = DirectFunctionCall2(time_mi_time, PG_GETARG_DATUM(0), PG_GETARG_DATUM(1));
|
||||
|
||||
PG_RETURN_INTERVAL_P(abs_interval(DatumGetIntervalP(diff)));
|
||||
// Compare two timeKEY objects a and b
|
||||
static int gbt_timekey_cmp(const void* a, const void* b)
|
||||
{
|
||||
// Cast void pointers a and b to timeKEY pointers
|
||||
timeKEY* ia = (timeKEY*)(((const Nsrt*)a)->t);
|
||||
timeKEY* ib = (timeKEY*)(((const Nsrt*)b)->t);
|
||||
int res;
|
||||
|
||||
// Compare the lower bounds of the timeKEY objects
|
||||
res = DatumGetInt32(DirectFunctionCall2(time_cmp, TimeADTGetDatumFast(ia->lower), TimeADTGetDatumFast(ib->lower)));
|
||||
// If the lower bounds are equal, compare the upper bounds
|
||||
if (res == 0)
|
||||
return DatumGetInt32(
|
||||
DirectFunctionCall2(time_cmp, TimeADTGetDatumFast(ia->upper), TimeADTGetDatumFast(ib->upper)));
|
||||
|
||||
// Return the result of the comparison of the lower bounds
|
||||
return res;
|
||||
}
|
||||
|
||||
// Calculate the distance between two time objects a and b
|
||||
static float8 gbt_time_dist(const void* a, const void* b)
|
||||
{
|
||||
// Cast void pointers a and b to TimeADT pointers
|
||||
const TimeADT* aa = (const TimeADT*)a;
|
||||
const TimeADT* bb = (const TimeADT*)b;
|
||||
Interval* i = NULL;
|
||||
|
||||
// Call the function time_mi_time to get the interval between the two time objects
|
||||
i = DatumGetIntervalP(DirectFunctionCall2(time_mi_time, TimeADTGetDatumFast(*aa), TimeADTGetDatumFast(*bb)));
|
||||
// Return the absolute value of the interval converted to seconds
|
||||
return (float8)Abs(INTERVAL_TO_SEC(i));
|
||||
}
|
||||
|
||||
// Define the information about the time type for the generalized binary tree (gbtree)
|
||||
static const gbtree_ninfo tinfo = {gbt_t_time,
|
||||
sizeof(TimeADT),
|
||||
gbt_timegt,
|
||||
gbt_timege,
|
||||
gbt_timeeq,
|
||||
gbt_timele,
|
||||
gbt_timelt,
|
||||
gbt_timekey_cmp,
|
||||
gbt_time_dist};
|
||||
|
||||
// Define the information about the time_dist function for PostgreSQL
|
||||
PG_FUNCTION_INFO_V1(time_dist);
|
||||
extern "C" Datum time_dist(PG_FUNCTION_ARGS);
|
||||
// Define the time_dist function for PostgreSQL
|
||||
Datum time_dist(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Call the function time_mi_time to get the interval between the two time objects passed as arguments
|
||||
Datum diff = DirectFunctionCall2(time_mi_time, PG_GETARG_DATUM(0), PG_GETARG_DATUM(1));
|
||||
|
||||
// Return the absolute value of the interval as a PostgreSQL interval object
|
||||
PG_RETURN_INTERVAL_P(abs_interval(DatumGetIntervalP(diff)));
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* time ops
|
||||
**************************************************/
|
||||
|
||||
Datum gbt_time_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
GISTENTRY* retval = NULL;
|
||||
|
||||
PG_RETURN_POINTER(gbt_num_compress(retval, entry, &tinfo));
|
||||
}
|
||||
|
||||
Datum gbt_timetz_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
GISTENTRY* retval = NULL;
|
||||
|
||||
if (entry->leafkey) {
|
||||
timeKEY* r = (timeKEY*)palloc(sizeof(timeKEY));
|
||||
TimeTzADT* tz = DatumGetTimeTzADTP(entry->key);
|
||||
TimeADT tmp;
|
||||
|
||||
retval = (GISTENTRY*)palloc(sizeof(GISTENTRY));
|
||||
|
||||
/* We are using the time + zone only to compress */
|
||||
#ifdef HAVE_INT64_TIMESTAMP
|
||||
tmp = tz->time + (tz->zone * INT64CONST(1000000));
|
||||
#else
|
||||
tmp = (tz->time + tz->zone);
|
||||
#endif
|
||||
r->lower = r->upper = tmp;
|
||||
gistentryinit(*retval, PointerGetDatum(r), entry->rel, entry->page, entry->offset, FALSE);
|
||||
} else
|
||||
retval = entry;
|
||||
PG_RETURN_POINTER(retval);
|
||||
}
|
||||
|
||||
Datum gbt_time_consistent(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
TimeADT query = PG_GETARG_TIMEADT(1);
|
||||
StrategyNumber strategy = (StrategyNumber)PG_GETARG_UINT16(2);
|
||||
|
||||
bool* recheck = (bool*)PG_GETARG_POINTER(4);
|
||||
// Compress the time data
|
||||
Datum gbt_time_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Get the entry from the argument
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
// Initialize the return value
|
||||
GISTENTRY* retval = NULL;
|
||||
|
||||
// Return the compressed value
|
||||
PG_RETURN_POINTER(gbt_num_compress(retval, entry, &tinfo));
|
||||
}
|
||||
|
||||
// Compress the time zone data
|
||||
Datum gbt_timetz_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Get the entry from the argument
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
// Initialize the return value
|
||||
GISTENTRY* retval = NULL;
|
||||
|
||||
// If the entry is a leaf key
|
||||
if (entry->leafkey) {
|
||||
// Allocate memory for the timeKEY object
|
||||
timeKEY* r = (timeKEY*)palloc(sizeof(timeKEY));
|
||||
// Get the time zone data from the entry
|
||||
TimeTzADT* tz = DatumGetTimeTzADTP(entry->key);
|
||||
// Initialize a temporary time object
|
||||
TimeADT tmp;
|
||||
|
||||
// Allocate memory for the return entry
|
||||
retval = (GISTENTRY*)palloc(sizeof(GISTENTRY));
|
||||
|
||||
// Use the time and zone to compress the data
|
||||
#ifdef HAVE_INT64_TIMESTAMP
|
||||
tmp = tz->time + (tz->zone * INT64CONST(1000000));
|
||||
#else
|
||||
tmp = (tz->time + tz->zone);
|
||||
#endif
|
||||
// Set the lower and upper bounds of the timeKEY object to the compressed time value
|
||||
r->lower = r->upper = tmp;
|
||||
// Initialize the return entry with the compressed timeKEY object and other information from the original entry
|
||||
gistentryinit(*retval, PointerGetDatum(r), entry->rel, entry->page, entry->offset, FALSE);
|
||||
} else {
|
||||
// If the entry is not a leaf key, return the original entry
|
||||
retval = entry;
|
||||
}
|
||||
// Return the compressed entry or the original entry if it is not a leaf key
|
||||
PG_RETURN_POINTER(retval);
|
||||
}
|
||||
|
||||
// Check if the query is consistent with the compressed time data
|
||||
Datum gbt_time_consistent(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Get the entry from the argument
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
// Get the query time from the argument
|
||||
TimeADT query = PG_GETARG_TIMEADT(1);
|
||||
// Get the strategy number from the argument
|
||||
StrategyNumber strategy = (StrategyNumber)PG_GETARG_UINT16(2);
|
||||
|
||||
// Get a pointer to the recheck boolean from the argument
|
||||
bool* recheck = (bool*)PG_GETARG_POINTER(4);
|
||||
|
||||
timeKEY* kkk = (timeKEY*)DatumGetPointer(entry->key);
|
||||
GBT_NUMKEY_R key;
|
||||
|
||||
|
|
@ -182,101 +229,142 @@ Datum gbt_time_consistent(PG_FUNCTION_ARGS)
|
|||
PG_RETURN_BOOL(gbt_num_consistent(&key, (void*)&query, &strategy, GIST_LEAF(entry), &tinfo));
|
||||
}
|
||||
|
||||
Datum gbt_time_distance(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
TimeADT query = PG_GETARG_TIMEADT(1);
|
||||
|
||||
timeKEY* kkk = (timeKEY*)DatumGetPointer(entry->key);
|
||||
GBT_NUMKEY_R key;
|
||||
|
||||
key.lower = (GBT_NUMKEY*)&kkk->lower;
|
||||
key.upper = (GBT_NUMKEY*)&kkk->upper;
|
||||
|
||||
PG_RETURN_FLOAT8(gbt_num_distance(&key, (void*)&query, GIST_LEAF(entry), &tinfo));
|
||||
}
|
||||
|
||||
Datum gbt_timetz_consistent(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
TimeTzADT* query = PG_GETARG_TIMETZADT_P(1);
|
||||
StrategyNumber strategy = (StrategyNumber)PG_GETARG_UINT16(2);
|
||||
|
||||
bool* recheck = (bool*)PG_GETARG_POINTER(4);
|
||||
timeKEY* kkk = (timeKEY*)DatumGetPointer(entry->key);
|
||||
TimeADT qqq;
|
||||
GBT_NUMKEY_R key;
|
||||
|
||||
/* All cases served by this function are inexact */
|
||||
*recheck = true;
|
||||
|
||||
#ifdef HAVE_INT64_TIMESTAMP
|
||||
qqq = query->time + (query->zone * INT64CONST(1000000));
|
||||
#else
|
||||
qqq = (query->time + query->zone);
|
||||
#endif
|
||||
|
||||
key.lower = (GBT_NUMKEY*)&kkk->lower;
|
||||
key.upper = (GBT_NUMKEY*)&kkk->upper;
|
||||
|
||||
PG_RETURN_BOOL(gbt_num_consistent(&key, (void*)&qqq, &strategy, GIST_LEAF(entry), &tinfo));
|
||||
}
|
||||
|
||||
Datum gbt_time_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector* entryvec = (GistEntryVector*)PG_GETARG_POINTER(0);
|
||||
// Calculate the distance between the time data and the query
|
||||
Datum gbt_time_distance(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Get the entry from the argument
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
// Get the query time from the argument
|
||||
TimeADT query = PG_GETARG_TIMEADT(1);
|
||||
|
||||
// Get the timeKEY object from the entry's key datum object
|
||||
timeKEY* kkk = (timeKEY*)DatumGetPointer(entry->key);
|
||||
// Initialize the key structure with the lower and upper bounds of the timeKEY object
|
||||
GBT_NUMKEY_R key;
|
||||
|
||||
key.lower = (GBT_NUMKEY*)&kkk->lower;
|
||||
key.upper = (GBT_NUMKEY*)&kkk->upper;
|
||||
|
||||
// Return the distance between the time data and the query
|
||||
PG_RETURN_FLOAT8(gbt_num_distance(&key, (void*)&query, GIST_LEAF(entry), &tinfo));
|
||||
}
|
||||
|
||||
// Check if the query is consistent with the time zone data
|
||||
Datum gbt_timetz_consistent(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Get the entry from the argument
|
||||
GISTENTRY* entry = (GISTENTRY*)PG_GETARG_POINTER(0);
|
||||
// Get the query time zone from the argument
|
||||
TimeTzADT* query = PG_GETARG_TIMETZADT_P(1);
|
||||
// Get the strategy number from the argument
|
||||
StrategyNumber strategy = (StrategyNumber)PG_GETARG_UINT16(2);
|
||||
|
||||
// Get a pointer to the recheck boolean from the argument
|
||||
bool* recheck = (bool*)PG_GETARG_POINTER(4);
|
||||
// Get the timeKEY object from the entry's key datum object
|
||||
timeKEY* kkk = (timeKEY*)DatumGetPointer(entry->key);
|
||||
// Initialize a temporary time object
|
||||
TimeADT qqq;
|
||||
// Initialize the key structure with the lower and upper bounds of the timeKEY object
|
||||
GBT_NUMKEY_R key;
|
||||
|
||||
/* All cases served by this function are inexact */
|
||||
*recheck = true;
|
||||
|
||||
#ifdef HAVE_INT64_TIMESTAMP
|
||||
qqq = query->time + (query->zone * INT64CONST(1000000));
|
||||
#else
|
||||
qqq = (query->time + query->zone);
|
||||
#endif
|
||||
|
||||
key.lower = (GBT_NUMKEY*)&kkk->lower;
|
||||
key.upper = (GBT_NUMKEY*)&kkk->upper;
|
||||
|
||||
// Return if the query is consistent with the time zone data
|
||||
PG_RETURN_BOOL(gbt_num_consistent(&key, (void*)&qqq, &strategy, GIST_LEAF(entry), &tinfo));
|
||||
}
|
||||
|
||||
// Union the time data
|
||||
Datum gbt_time_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Get the entry vector from the argument
|
||||
GistEntryVector* entryvec = (GistEntryVector*)PG_GETARG_POINTER(0);
|
||||
void* out = palloc(sizeof(timeKEY));
|
||||
|
||||
*(int*)PG_GETARG_POINTER(1) = sizeof(timeKEY);
|
||||
PG_RETURN_POINTER(gbt_num_union((GBT_NUMKEY*)out, entryvec, &tinfo));
|
||||
}
|
||||
|
||||
Datum gbt_time_penalty(PG_FUNCTION_ARGS)
|
||||
{
|
||||
timeKEY* origentry = (timeKEY*)DatumGetPointer(((GISTENTRY*)PG_GETARG_POINTER(0))->key);
|
||||
timeKEY* newentry = (timeKEY*)DatumGetPointer(((GISTENTRY*)PG_GETARG_POINTER(1))->key);
|
||||
float* result = (float*)PG_GETARG_POINTER(2);
|
||||
Interval* intr = NULL;
|
||||
double res;
|
||||
double res2;
|
||||
|
||||
intr = DatumGetIntervalP(
|
||||
DirectFunctionCall2(time_mi_time, TimeADTGetDatumFast(newentry->upper), TimeADTGetDatumFast(origentry->upper)));
|
||||
res = INTERVAL_TO_SEC(intr);
|
||||
res = Max(res, 0);
|
||||
|
||||
intr = DatumGetIntervalP(
|
||||
DirectFunctionCall2(time_mi_time, TimeADTGetDatumFast(origentry->lower), TimeADTGetDatumFast(newentry->lower)));
|
||||
res2 = INTERVAL_TO_SEC(intr);
|
||||
res2 = Max(res2, 0);
|
||||
|
||||
res += res2;
|
||||
|
||||
*result = 0.0;
|
||||
|
||||
if (res > 0) {
|
||||
intr = DatumGetIntervalP(DirectFunctionCall2(
|
||||
time_mi_time, TimeADTGetDatumFast(origentry->upper), TimeADTGetDatumFast(origentry->lower)));
|
||||
*result += FLT_MIN;
|
||||
*result += (float)(res / (res + INTERVAL_TO_SEC(intr)));
|
||||
*result *= (FLT_MAX / (((GISTENTRY*)PG_GETARG_POINTER(0))->rel->rd_att->natts + 1));
|
||||
}
|
||||
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
Datum gbt_time_picksplit(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_POINTER(
|
||||
gbt_num_picksplit((GistEntryVector*)PG_GETARG_POINTER(0), (GIST_SPLITVEC*)PG_GETARG_POINTER(1), &tinfo));
|
||||
}
|
||||
|
||||
Datum gbt_time_same(PG_FUNCTION_ARGS)
|
||||
{
|
||||
timeKEY* b1 = (timeKEY*)PG_GETARG_POINTER(0);
|
||||
timeKEY* b2 = (timeKEY*)PG_GETARG_POINTER(1);
|
||||
bool* result = (bool*)PG_GETARG_POINTER(2);
|
||||
|
||||
*result = gbt_num_same((GBT_NUMKEY*)b1, (GBT_NUMKEY*)b2, &tinfo);
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
// Calculate the penalty for the time data
|
||||
Datum gbt_time_penalty(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Get the original and new entries' timeKEY objects from the arguments
|
||||
timeKEY* origentry = (timeKEY*)DatumGetPointer(((GISTENTRY*)PG_GETARG_POINTER(0))->key);
|
||||
timeKEY* newentry = (timeKEY*)DatumGetPointer(((GISTENTRY*)PG_GETARG_POINTER(1))->key);
|
||||
// Get a pointer to the result float from the argument
|
||||
float* result = (float*)PG_GETARG_POINTER(2);
|
||||
// Initialize an interval object
|
||||
Interval* intr = NULL;
|
||||
// Initialize result variables
|
||||
double res;
|
||||
double res2;
|
||||
|
||||
// Calculate the time interval between the new and original entries' upper bounds
|
||||
intr = DatumGetIntervalP(
|
||||
DirectFunctionCall2(time_mi_time, TimeADTGetDatumFast(newentry->upper), TimeADTGetDatumFast(origentry->upper)));
|
||||
// Convert the interval to seconds and take the maximum value as 0
|
||||
res = INTERVAL_TO_SEC(intr);
|
||||
res = Max(res, 0);
|
||||
|
||||
// Calculate the time interval between the new and original entries' lower bounds
|
||||
intr = DatumGetIntervalP(
|
||||
DirectFunctionCall2(time_mi_time, TimeADTGetDatumFast(origentry->lower), TimeADTGetDatumFast(newentry->lower)));
|
||||
// Convert the interval to seconds and take the maximum value as 0
|
||||
res2 = INTERVAL_TO_SEC(intr);
|
||||
res2 = Max(res2, 0);
|
||||
|
||||
// Add the two intervals together
|
||||
res += res2;
|
||||
|
||||
// Initialize the result to 0.0
|
||||
*result = 0.0;
|
||||
|
||||
// If the total interval is greater than 0, calculate the penalty
|
||||
if (res > 0) {
|
||||
// Calculate the time interval between the original entry's upper and lower bounds
|
||||
intr = DatumGetIntervalP(DirectFunctionCall2(
|
||||
time_mi_time, TimeADTGetDatumFast(origentry->upper), TimeADTGetDatumFast(origentry->lower)));
|
||||
// Add a small value to the result
|
||||
*result += FLT_MIN;
|
||||
// Calculate the ratio of the total interval to the original entry's upper and lower bounds' interval
|
||||
*result += (float)(res / (res + INTERVAL_TO_SEC(intr)));
|
||||
// Scale the result by a maximum value divided by the number of attributes plus 1
|
||||
*result *= (FLT_MAX / (((GISTENTRY*)PG_GETARG_POINTER(0))->rel->rd_att->natts + 1));
|
||||
}
|
||||
|
||||
// Return a pointer to the result float
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
// Pick a split point for the time data
|
||||
Datum gbt_time_picksplit(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Return a pointer to the result of picking a split point for the time data
|
||||
PG_RETURN_POINTER(
|
||||
gbt_num_picksplit((GistEntryVector*)PG_GETARG_POINTER(0), (GIST_SPLITVEC*)PG_GETARG_POINTER(1), &tinfo));
|
||||
}
|
||||
|
||||
// Check if two time data are the same
|
||||
Datum gbt_time_same(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Get the two timeKEY objects from the arguments
|
||||
timeKEY* b1 = (timeKEY*)PG_GETARG_POINTER(0);
|
||||
timeKEY* b2 = (timeKEY*)PG_GETARG_POINTER(1);
|
||||
// Get a pointer to the result boolean from the argument
|
||||
bool* result = (bool*)PG_GETARG_POINTER(2);
|
||||
|
||||
// Check if the two time data are the same and store the result in the result boolean
|
||||
*result = gbt_num_same((GBT_NUMKEY*)b1, (GBT_NUMKEY*)b2, &tinfo);
|
||||
// Return a pointer to the result boolean
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
|
@ -240,26 +240,38 @@ Datum citext_ge(PG_FUNCTION_ARGS)
|
|||
* ===================
|
||||
*/
|
||||
|
||||
PG_FUNCTION_INFO_V1(citext_smaller);
|
||||
|
||||
Datum citext_smaller(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text* left = PG_GETARG_TEXT_PP(0);
|
||||
text* right = PG_GETARG_TEXT_PP(1);
|
||||
text* result = NULL;
|
||||
|
||||
result = (citextcmp(left, right, PG_GET_COLLATION()) < 0) ? left : right;
|
||||
PG_RETURN_TEXT_P(result);
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(citext_larger);
|
||||
|
||||
Datum citext_larger(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text* left = PG_GETARG_TEXT_PP(0);
|
||||
text* right = PG_GETARG_TEXT_PP(1);
|
||||
text* result = NULL;
|
||||
|
||||
result = (citextcmp(left, right, PG_GET_COLLATION()) > 0) ? left : right;
|
||||
PG_RETURN_TEXT_P(result);
|
||||
}
|
||||
// Declare a function named citext_smaller, which is an internal function of PostgreSQL, used to compare whether the first citext value is smaller than the second.
|
||||
PG_FUNCTION_INFO_V1(citext_smaller);
|
||||
|
||||
// Implement the citext_smaller function. This function takes two parameters (two text* pointers) and returns a text* value.
|
||||
Datum citext_smaller(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Get the first and second text* pointers from the function parameters and assign them to left and right respectively.
|
||||
text* left = PG_GETARG_TEXT_PP(0);
|
||||
text* right = PG_GETARG_TEXT_PP(1);
|
||||
// Initialize a text* variable result, which will store the result of the comparison.
|
||||
text* result = NULL;
|
||||
|
||||
// Use the citextcmp function to compare left and right. If left is smaller than right, assign left to result; otherwise, assign right to result.
|
||||
result = (citextcmp(left, right, PG_GET_COLLATION()) < 0) ? left : right;
|
||||
// Return the result of the comparison.
|
||||
PG_RETURN_TEXT_P(result);
|
||||
}
|
||||
|
||||
// Declare a function named citext_larger, which is an internal function of PostgreSQL, used to compare whether the first citext value is larger than the second.
|
||||
PG_FUNCTION_INFO_V1(citext_larger);
|
||||
|
||||
// Implement the citext_larger function. This function takes two parameters (two text* pointers) and returns a text* value.
|
||||
Datum citext_larger(PG_FUNCTION_ARGS)
|
||||
{
|
||||
// Get the first and second text* pointers from the function parameters and assign them to left and right respectively.
|
||||
text* left = PG_GETARG_TEXT_PP(0);
|
||||
text* right = PG_GETARG_TEXT_PP(1);
|
||||
// Initialize a text* variable result, which will store the result of the comparison.
|
||||
text* result = NULL;
|
||||
|
||||
// Use the citextcmp function to compare left and right. If left is larger than right, assign left to result; otherwise, assign right to result.
|
||||
result = (citextcmp(left, right, PG_GET_COLLATION()) > 0) ? left : right;
|
||||
// Return the result of the comparison.
|
||||
PG_RETURN_TEXT_P(result);
|
||||
}
|
||||
|
|
@ -363,6 +363,7 @@ void cgptree_get_group_info(struct group_info* curr_ginfo, const struct cgroup_m
|
|||
*/
|
||||
static struct group_info* cgptree_get_group_tree(const struct cgroup_mount_point& mount_info)
|
||||
{
|
||||
/* init the variable */
|
||||
int curr_depth = -1;
|
||||
int prev_depth = -1;
|
||||
void* tree_handle = NULL;
|
||||
|
|
@ -401,15 +402,15 @@ static struct group_info* cgptree_get_group_tree(const struct cgroup_mount_point
|
|||
while (error != ECGEOF) {
|
||||
/* get the relative path */
|
||||
rel_path = (char*)(info.full_path + strlen(root_path));
|
||||
|
||||
/* specific path of the file */
|
||||
tmpstr = rel_path + sizeof(GSCGROUP_TOP_DATABASE);
|
||||
cm_tmpstr = rel_path + sizeof(GSCGROUP_CM);
|
||||
tmplen = strlen(cgutil_passwd_user->pw_name);
|
||||
|
||||
if ((CHECK_GSCGROUP_TOP_DATABASE || CHECK_GSCGROUP_CM) && info.type == CGROUP_FILE_TYPE_DIR) {
|
||||
curr_ginfo = (struct group_info*)calloc(1, sizeof(struct group_info));
|
||||
|
||||
if (curr_ginfo == NULL)
|
||||
/* when it doesn't exit , create error_report*/
|
||||
if (curr_ginfo == NULL)
|
||||
goto error;
|
||||
|
||||
curr_ginfo->depth = info.depth;
|
||||
|
|
|
|||
|
|
@ -197,11 +197,10 @@ static int check_percentage_value(int bkd, int grp, int cls, int top)
|
|||
/* fixed mode */
|
||||
if (cgutil_opt.fixed) {
|
||||
/*
|
||||
* it is not allowed if more than one group percentage is specified when updating
|
||||
* cpuset by percentage
|
||||
* Alert: Fixed mode only allows one group percentage at a time when updating cpuset by percentage.
|
||||
*/
|
||||
if (bkd + cls + top + grp > 1) {
|
||||
fprintf(stderr, "ERROR: redundant options of cpu core percentage. \n");
|
||||
fprintf(stderr, "ERROR: Redundant options for cpu core percentage. \n");
|
||||
return -1;
|
||||
} else if (bkd + cls + top + grp == 0) {
|
||||
return 0;
|
||||
|
|
@ -209,36 +208,36 @@ static int check_percentage_value(int bkd, int grp, int cls, int top)
|
|||
|
||||
check_group_name_redundant(bkd, grp, cls, top);
|
||||
|
||||
/* check backend percentage, cpuset percentage range is 1-100 */
|
||||
/* Check backend percentage. Valid range: 1-100. */
|
||||
if (cgutil_opt.uflag && bkd) {
|
||||
if (cgutil_opt.bkdpct > 100 || cgutil_opt.bkdpct < 0) {
|
||||
fprintf(stderr,
|
||||
"ERROR: invalid value for cpu core percentage. "
|
||||
"its range should be 0-100. \n");
|
||||
"ERROR: Invalid value for cpu core percentage. "
|
||||
"The range should be 0-100. \n");
|
||||
return -1;
|
||||
}
|
||||
cgutil_opt.setspct = cgutil_opt.bkdpct;
|
||||
cgutil_opt.bkdpct = 0;
|
||||
}
|
||||
|
||||
/* check group percentage */
|
||||
/* Check group percentage */
|
||||
if (cgutil_opt.uflag && grp) {
|
||||
if (cgutil_opt.grppct > 100 || cgutil_opt.grppct < 0) {
|
||||
fprintf(stderr,
|
||||
"ERROR: invalid value for cpu core percentage. "
|
||||
"its range should be 0-100. \n");
|
||||
"ERROR: Invalid value for cpu core percentage. "
|
||||
"The range should be 0-100. \n");
|
||||
return -1;
|
||||
}
|
||||
cgutil_opt.setspct = cgutil_opt.grppct;
|
||||
cgutil_opt.grppct = 0;
|
||||
}
|
||||
|
||||
/* check class percentage */
|
||||
/* Check class percentage */
|
||||
if (cgutil_opt.uflag && cls) {
|
||||
if (cgutil_opt.clspct > 100 || cgutil_opt.clspct < 0) {
|
||||
fprintf(stderr,
|
||||
"ERROR: invalid value for cpu core percentage. "
|
||||
"its range should be 0-100. \n");
|
||||
"ERROR: Invalid value for cpu core percentage. "
|
||||
"The range should be 0-100. \n");
|
||||
return -1;
|
||||
}
|
||||
cgutil_opt.setspct = cgutil_opt.clspct;
|
||||
|
|
@ -246,50 +245,50 @@ static int check_percentage_value(int bkd, int grp, int cls, int top)
|
|||
cgutil_opt.clssetpct = 1;
|
||||
}
|
||||
|
||||
/* check top group percentage */
|
||||
/* Check top group percentage */
|
||||
if (cgutil_opt.uflag && top) {
|
||||
if (cgutil_opt.toppct > 100 || cgutil_opt.toppct < 0) {
|
||||
fprintf(stderr,
|
||||
"ERROR: invalid value for cpu core percentage. "
|
||||
"its range should be 0-100. \n");
|
||||
"ERROR: Invalid value for cpu core percentage. "
|
||||
"The range should be 0-100. \n");
|
||||
return -1;
|
||||
}
|
||||
cgutil_opt.setspct = cgutil_opt.toppct;
|
||||
cgutil_opt.toppct = 0;
|
||||
}
|
||||
|
||||
// if user set core percentage is 0, set a flag to show that user set
|
||||
// Set a flag to indicate that user set core percentage is 0
|
||||
if (cgutil_opt.setspct == 0)
|
||||
cgutil_opt.setfixed = 1;
|
||||
} else {
|
||||
if ((cgutil_opt.cflag || cgutil_opt.uflag) && bkd && (cgutil_opt.bkdpct >= 100 || cgutil_opt.bkdpct < 1)) {
|
||||
fprintf(stderr,
|
||||
"ERROR: invalid value for backend group dynamic percentage. "
|
||||
"its range should be 1 ~ 99!\n");
|
||||
"ERROR: Invalid value for backend group dynamic percentage. "
|
||||
"The range should be 1 ~ 99!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check backend percentage */
|
||||
/* Check backend percentage */
|
||||
if ((cgutil_opt.cflag || cgutil_opt.uflag) && grp && (cgutil_opt.grppct >= 100 || cgutil_opt.grppct < 1)) {
|
||||
fprintf(stderr,
|
||||
"ERROR: invalid value for workload group dynamic percentage. "
|
||||
"its range should be 1 ~ 99!\n");
|
||||
"ERROR: Invalid value for workload group dynamic percentage. "
|
||||
"The range should be 1 ~ 99!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check group percentage */
|
||||
/* Check group percentage */
|
||||
if ((cgutil_opt.cflag || cgutil_opt.uflag) && cls && (cgutil_opt.clspct >= 100 || (cgutil_opt.clspct < 1))) {
|
||||
fprintf(stderr,
|
||||
"ERROR: invalid value for class group dynamic percentage. "
|
||||
"its range should be 1 ~ 99!\n");
|
||||
"ERROR: Invalid value for class group dynamic percentage. "
|
||||
"The range should be 1 ~ 99!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check class percentage */
|
||||
/* Check class percentage */
|
||||
if ((cgutil_opt.cflag || cgutil_opt.uflag) && top && (cgutil_opt.toppct >= 100 || cgutil_opt.toppct < 1)) {
|
||||
fprintf(stderr,
|
||||
"ERROR: invalid value for top group dynamic percentage. "
|
||||
"its range should be 1 ~ 99!\n");
|
||||
"ERROR: Invalid value for top group dynamic percentage. "
|
||||
"The range should be 1 ~ 99!\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
@ -348,11 +347,13 @@ static int check_node_group_name()
|
|||
*/
|
||||
static void check_input_for_security(char* input)
|
||||
{
|
||||
char* danger_token[] = {"|", ";", "&", "$", "<", ">", "`", "\\", "!", "\n", NULL};
|
||||
// Array of dangerous tokens
|
||||
char* danger_token[] = {"|", ";", "&", "$", "<", ">", "`", "\", "!", "\n", NULL};
|
||||
|
||||
// Check if any of the dangerous tokens are present in the input string
|
||||
for (int i = 0; danger_token[i] != NULL; ++i) {
|
||||
if (strstr(input, danger_token[i]) != NULL) {
|
||||
printf("invalid token \"%s\"\n", danger_token[i]);
|
||||
printf("Invalid token \"%s\"\n", danger_token[i]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
|
@ -413,20 +414,20 @@ static int check_name_valid(void)
|
|||
*/
|
||||
static int check_input_valid(void)
|
||||
{
|
||||
/* check group name with flag '--fixed' */
|
||||
// Check group name with flag '--fixed'
|
||||
if (*cgutil_opt.clsname == '\0' && *cgutil_opt.wdname == '\0' && *cgutil_opt.bkdname == '\0' &&
|
||||
*cgutil_opt.topname == '\0' && cgutil_opt.fixed) {
|
||||
fprintf(stderr, "ERROR: Please specify a group name with flag \"--fixed\"\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check flag '--fixed' and '-u' */
|
||||
// Check flag '--fixed' and '-u'
|
||||
if (cgutil_opt.fixed && 0 == cgutil_opt.uflag) {
|
||||
fprintf(stderr, "ERROR: Please specify \'--fixed\' flag together with \'-u\' flag.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check group name with flag '-f' */
|
||||
// Check group name with flag '-f'
|
||||
if ((*cgutil_opt.clsname || *cgutil_opt.wdname || *cgutil_opt.bkdname ||
|
||||
(*cgutil_opt.topname &&
|
||||
(0 != strncmp(cgutil_opt.topname, GSCGROUP_TOP_DATABASE, sizeof(GSCGROUP_TOP_DATABASE))))) &&
|
||||
|
|
@ -435,43 +436,43 @@ static int check_input_valid(void)
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* users cannot use -f and --fixed at the same time */
|
||||
// Users cannot use -f and --fixed at the same time
|
||||
if (cgutil_opt.fixed && *cgutil_opt.sets) {
|
||||
fprintf(stderr, "ERROR: Please specify one option from \'-f\',\'--fixed\'.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* get current mount points */
|
||||
// Get current mount points
|
||||
if (cgexec_get_mount_points() < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check '-c', '-d', '-u' flag */
|
||||
// Check '-c', '-d', '-u' flag
|
||||
if ((cgutil_opt.cflag && cgutil_opt.dflag) || (cgutil_opt.cflag && cgutil_opt.uflag) ||
|
||||
(cgutil_opt.uflag && cgutil_opt.dflag)) {
|
||||
fprintf(stderr, "ERROR: please only specify one option from '-c', '-d' and '-u'.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check '-e' flag */
|
||||
// Check '-e' flag
|
||||
if (IS_EXCEPT_FLAG(cgutil_opt.eflag, EXCEPT_ERROR)) {
|
||||
fprintf(stderr, "ERROR: abort and penalty cannot be specified together!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check exception data from '-e' flag */
|
||||
// Check exception data from '-e' flag
|
||||
if (cgutil_opt.clsname[0] == '\0' && IS_EXCEPT_FLAG(cgutil_opt.eflag, EXCEPT_PENALTY)) {
|
||||
fprintf(stderr, "ERROR: you must specify a class name with penalty!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* set default exception data without '--penalty', '--abort' and '-a' flag */
|
||||
// Set default exception data without '--penalty', '--abort' and '-a' flag
|
||||
if (*cgutil_opt.edata && IS_EXCEPT_FLAG(cgutil_opt.eflag, EXCEPT_NONE)) {
|
||||
cgutil_opt.eflag = EXCEPT_FLAG(EXCEPT_PENALTY);
|
||||
fprintf(stdout, "NOTICE: if do not specify exceptional action, default is penalty!\n");
|
||||
}
|
||||
|
||||
/* check '--refresh', '--revert' and '--recover' flag */
|
||||
// Check '--refresh', '--revert' and '--recover' flag
|
||||
if ((cgutil_opt.cflag || cgutil_opt.dflag || cgutil_opt.uflag) &&
|
||||
(cgutil_opt.refresh || cgutil_opt.revert || cgutil_opt.recover)) {
|
||||
fprintf(stderr,
|
||||
|
|
@ -480,7 +481,7 @@ static int check_input_valid(void)
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* check '--recover' flag */
|
||||
// Check '--recover' flag
|
||||
if ((geteuid() == 0) && cgutil_opt.recover) {
|
||||
fprintf(stderr, "ERROR: you cannpt specify option '--recover' by root user!\n");
|
||||
return -1;
|
||||
|
|
@ -488,16 +489,17 @@ static int check_input_valid(void)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @Description: check user info with flags.
|
||||
* @IN void
|
||||
* @Return: -1: abnormal 0: normal
|
||||
* @See also:
|
||||
*/
|
||||
// This function checks the user and process information for the cgutil command.
|
||||
// It ensures that the command is being run with the correct permissions and that the user information is being specified correctly.
|
||||
static int check_user_process(void)
|
||||
{
|
||||
/* check root user process */
|
||||
// Check if running as root user and user info is missing for certain flags
|
||||
if ((geteuid() == 0) && ((cgutil_opt.cflag || cgutil_opt.display || cgutil_opt.uflag || cgutil_opt.dflag) &&
|
||||
cgutil_opt.user[0] == '\0')) {
|
||||
fprintf(stderr,
|
||||
|
|
@ -506,13 +508,13 @@ static int check_user_process(void)
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* check non-root user process */
|
||||
// Check if running as non-root user and user info is specified
|
||||
if (geteuid() && cgutil_opt.user[0] != '\0') {
|
||||
fprintf(stderr, "ERROR: you can't specify the user name while running as non-root user.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check user info for '-P' flag */
|
||||
// Check if running as root user and user info is missing for '-P' flag
|
||||
if (0 == geteuid() && cgutil_opt.ptree && '\0' == *cgutil_opt.user) {
|
||||
fprintf(stderr,
|
||||
"ERROR: you must specify the user name when running as root user "
|
||||
|
|
@ -520,7 +522,7 @@ static int check_user_process(void)
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* check non-root user info for '-M' flag */
|
||||
// Check if running as non-root user and trying to mount or unmount cgroup
|
||||
if ((cgutil_opt.mflag || cgutil_opt.umflag) && geteuid()) {
|
||||
fprintf(stderr, "ERROR: you must run mount or umount cgroup by root user!\n");
|
||||
return -1;
|
||||
|
|
@ -537,7 +539,7 @@ static int check_user_process(void)
|
|||
*/
|
||||
static int check_flag_process(void)
|
||||
{
|
||||
/* create flag process */
|
||||
// Check if creating a cgroup and validate group and class names
|
||||
if (cgutil_opt.cflag) {
|
||||
/* check top and backend group name */
|
||||
if (cgutil_opt.topname[0] != '\0' || cgutil_opt.bkdname[0] != '\0') {
|
||||
|
|
@ -561,7 +563,7 @@ static int check_flag_process(void)
|
|||
}
|
||||
}
|
||||
|
||||
/* delete flag process */
|
||||
// Check if deleting a cgroup and validate group and class names
|
||||
if (cgutil_opt.dflag) {
|
||||
/* check top and backend group name */
|
||||
if (cgutil_opt.topname[0] != '\0' || cgutil_opt.bkdname[0] != '\0') {
|
||||
|
|
@ -572,7 +574,7 @@ static int check_flag_process(void)
|
|||
}
|
||||
}
|
||||
|
||||
/* update flag process */
|
||||
// Check if updating a cgroup and validate group and class names
|
||||
if (cgutil_opt.uflag &&
|
||||
('\0' == cgutil_opt.topname[0] && '\0' == cgutil_opt.bkdname[0] && '\0' == cgutil_opt.clsname[0])) {
|
||||
fprintf(stderr, "ERROR: please specify the Group name when updating!\n");
|
||||
|
|
@ -825,7 +827,7 @@ static int check_cpuset_value_valid(char* cpuset)
|
|||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// check the value
|
||||
if ((a < 0) || (b < 0) || (a > b) || (b >= cgutil_cpucnt)) {
|
||||
fprintf(stderr, "ERROR: please specify the cpuset with a valid value.\n");
|
||||
return -1;
|
||||
|
|
@ -843,6 +845,7 @@ static int check_cpuset_value_valid(char* cpuset)
|
|||
* @Return: 1: OK 0: Not OK
|
||||
* @See also:
|
||||
*/
|
||||
// check configuration
|
||||
static int check_config_flag(void)
|
||||
{
|
||||
if (cgutil_opt.cflag || (cgutil_opt.dflag && (*cgutil_opt.clsname || *cgutil_opt.nodegroup)) || cgutil_opt.uflag ||
|
||||
|
|
@ -859,6 +862,7 @@ static int check_config_flag(void)
|
|||
* @Return: -1: abnormal 0: normal
|
||||
* @See also:
|
||||
*/
|
||||
// initialize the configuration
|
||||
static int initialize_cgroup_config(void)
|
||||
{
|
||||
char* hpath = NULL;
|
||||
|
|
@ -905,6 +909,7 @@ static int initialize_cgroup_config(void)
|
|||
* @Return: -1: abnormal 0: normal
|
||||
* @See also:
|
||||
*/
|
||||
// check the configuration status
|
||||
static int check_and_get_group_percent(char* percent, char* gtype)
|
||||
{
|
||||
char* bad = NULL;
|
||||
|
|
@ -941,6 +946,7 @@ static int check_and_get_group_percent(char* percent, char* gtype)
|
|||
* -1: abnormal
|
||||
* 0: normal
|
||||
*/
|
||||
// structure of long options
|
||||
static struct option long_options[] = {{"help", no_argument, NULL, 'h'},
|
||||
{"version", no_argument, NULL, 'V'},
|
||||
{"abort", no_argument, NULL, 'a'},
|
||||
|
|
@ -954,6 +960,7 @@ static struct option long_options[] = {{"help", no_argument, NULL, 'h'},
|
|||
{"rename", no_argument, NULL, 7},
|
||||
{NULL, 0, NULL, 0}};
|
||||
|
||||
// match the choice
|
||||
static int parse_options(int argc, char** argv)
|
||||
{
|
||||
int c;
|
||||
|
|
@ -1164,7 +1171,7 @@ int main(int argc, char** argv)
|
|||
" or \"/sys/devices/system\" is acceptable. \n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// set the style of string
|
||||
int rc = sprintf_s(cgutil_allset, sizeof(cgutil_allset), "%d-%d", 0, cgutil_cpucnt - 1);
|
||||
securec_check_intval(rc, , -1);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue