对于bin、tools部分代码的注释 #33

Open
Charl wants to merge 7 commits from Charl/openGauss-server:master into master
18 changed files with 1603 additions and 1139 deletions

View File

@ -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}')

View File

@ -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'

View File

@ -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);
}

View File

@ -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,

View File

@ -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);

View File

@ -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
}

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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));
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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);