pgindent run before PG 9.1 beta 1.
This commit is contained in:
parent
9a8b73147c
commit
bf50caf105
|
@ -78,18 +78,19 @@ convert_and_check_filename(text *arg, bool logAllowed)
|
|||
/* Disallow '/a/b/data/..' */
|
||||
if (path_contains_parent_reference(filename))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
(errmsg("reference to parent directory (\"..\") not allowed"))));
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
(errmsg("reference to parent directory (\"..\") not allowed"))));
|
||||
|
||||
/*
|
||||
* Allow absolute paths if within DataDir or Log_directory, even
|
||||
* though Log_directory might be outside DataDir.
|
||||
* Allow absolute paths if within DataDir or Log_directory, even
|
||||
* though Log_directory might be outside DataDir.
|
||||
*/
|
||||
if (!path_is_prefix_of_path(DataDir, filename) &&
|
||||
(!logAllowed || !is_absolute_path(Log_directory) ||
|
||||
!path_is_prefix_of_path(Log_directory, filename)))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
(errmsg("absolute path not allowed"))));
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
(errmsg("absolute path not allowed"))));
|
||||
}
|
||||
else if (!path_is_relative_and_below_cwd(filename))
|
||||
ereport(ERROR,
|
||||
|
|
|
@ -18,13 +18,13 @@
|
|||
|
||||
PG_MODULE_MAGIC;
|
||||
|
||||
void _PG_init(void);
|
||||
void _PG_init(void);
|
||||
|
||||
/* GUC Variables */
|
||||
static int auth_delay_milliseconds;
|
||||
|
||||
/* Original Hook */
|
||||
static ClientAuthentication_hook_type original_client_auth_hook = NULL;
|
||||
static ClientAuthentication_hook_type original_client_auth_hook = NULL;
|
||||
|
||||
/*
|
||||
* Check authentication
|
||||
|
@ -55,7 +55,7 @@ _PG_init(void)
|
|||
{
|
||||
/* Define custom GUC variables */
|
||||
DefineCustomIntVariable("auth_delay.milliseconds",
|
||||
"Milliseconds to delay before reporting authentication failure",
|
||||
"Milliseconds to delay before reporting authentication failure",
|
||||
NULL,
|
||||
&auth_delay_milliseconds,
|
||||
0,
|
||||
|
|
|
@ -169,7 +169,7 @@ gbt_cash_distance(PG_FUNCTION_ARGS)
|
|||
key.upper = (GBT_NUMKEY *) &kkk->upper;
|
||||
|
||||
PG_RETURN_FLOAT8(
|
||||
gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
|
||||
gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -90,9 +90,9 @@ static float8
|
|||
gdb_date_dist(const void *a, const void *b)
|
||||
{
|
||||
/* we assume the difference can't overflow */
|
||||
Datum diff = DirectFunctionCall2(date_mi,
|
||||
Datum diff = DirectFunctionCall2(date_mi,
|
||||
DateADTGetDatum(*((const DateADT *) a)),
|
||||
DateADTGetDatum(*((const DateADT *) b)));
|
||||
DateADTGetDatum(*((const DateADT *) b)));
|
||||
|
||||
return (float8) Abs(DatumGetInt32(diff));
|
||||
}
|
||||
|
@ -113,14 +113,14 @@ static const gbtree_ninfo tinfo =
|
|||
|
||||
|
||||
PG_FUNCTION_INFO_V1(date_dist);
|
||||
Datum date_dist(PG_FUNCTION_ARGS);
|
||||
Datum date_dist(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
date_dist(PG_FUNCTION_ARGS)
|
||||
{
|
||||
/* we assume the difference can't overflow */
|
||||
Datum diff = DirectFunctionCall2(date_mi,
|
||||
PG_GETARG_DATUM(0),
|
||||
PG_GETARG_DATUM(1));
|
||||
Datum diff = DirectFunctionCall2(date_mi,
|
||||
PG_GETARG_DATUM(0),
|
||||
PG_GETARG_DATUM(1));
|
||||
|
||||
PG_RETURN_INT32(Abs(DatumGetInt32(diff)));
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ gbt_date_distance(PG_FUNCTION_ARGS)
|
|||
key.upper = (GBT_NUMKEY *) &kkk->upper;
|
||||
|
||||
PG_RETURN_FLOAT8(
|
||||
gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
|
||||
gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -94,18 +94,18 @@ static const gbtree_ninfo tinfo =
|
|||
|
||||
|
||||
PG_FUNCTION_INFO_V1(float4_dist);
|
||||
Datum float4_dist(PG_FUNCTION_ARGS);
|
||||
Datum float4_dist(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
float4_dist(PG_FUNCTION_ARGS)
|
||||
{
|
||||
float4 a = PG_GETARG_FLOAT4(0);
|
||||
float4 a = PG_GETARG_FLOAT4(0);
|
||||
float4 b = PG_GETARG_FLOAT4(1);
|
||||
float4 r;
|
||||
|
||||
r = a - b;
|
||||
CHECKFLOATVAL(r, isinf(a) || isinf(b), true);
|
||||
|
||||
PG_RETURN_FLOAT4( Abs(r) );
|
||||
PG_RETURN_FLOAT4(Abs(r));
|
||||
}
|
||||
|
||||
|
||||
|
@ -162,7 +162,7 @@ gbt_float4_distance(PG_FUNCTION_ARGS)
|
|||
key.upper = (GBT_NUMKEY *) &kkk->upper;
|
||||
|
||||
PG_RETURN_FLOAT8(
|
||||
gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
|
||||
gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -76,8 +76,8 @@ gbt_float8key_cmp(const void *a, const void *b)
|
|||
static float8
|
||||
gbt_float8_dist(const void *a, const void *b)
|
||||
{
|
||||
float8 arg1 = *(const float8 *)a;
|
||||
float8 arg2 = *(const float8 *)b;
|
||||
float8 arg1 = *(const float8 *) a;
|
||||
float8 arg2 = *(const float8 *) b;
|
||||
float8 r;
|
||||
|
||||
r = arg1 - arg2;
|
||||
|
@ -102,7 +102,7 @@ static const gbtree_ninfo tinfo =
|
|||
|
||||
|
||||
PG_FUNCTION_INFO_V1(float8_dist);
|
||||
Datum float8_dist(PG_FUNCTION_ARGS);
|
||||
Datum float8_dist(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
float8_dist(PG_FUNCTION_ARGS)
|
||||
{
|
||||
|
@ -113,7 +113,7 @@ float8_dist(PG_FUNCTION_ARGS)
|
|||
r = a - b;
|
||||
CHECKFLOATVAL(r, isinf(a) || isinf(b), true);
|
||||
|
||||
PG_RETURN_FLOAT8( Abs(r) );
|
||||
PG_RETURN_FLOAT8(Abs(r));
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
|
@ -169,7 +169,7 @@ gbt_float8_distance(PG_FUNCTION_ARGS)
|
|||
key.upper = (GBT_NUMKEY *) &kkk->upper;
|
||||
|
||||
PG_RETURN_FLOAT8(
|
||||
gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
|
||||
gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -94,12 +94,12 @@ static const gbtree_ninfo tinfo =
|
|||
|
||||
|
||||
PG_FUNCTION_INFO_V1(int2_dist);
|
||||
Datum int2_dist(PG_FUNCTION_ARGS);
|
||||
Datum int2_dist(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
int2_dist(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int2 a = PG_GETARG_INT16(0);
|
||||
int2 b = PG_GETARG_INT16(1);
|
||||
int2 a = PG_GETARG_INT16(0);
|
||||
int2 b = PG_GETARG_INT16(1);
|
||||
int2 r;
|
||||
int2 ra;
|
||||
|
||||
|
@ -169,7 +169,7 @@ gbt_int2_distance(PG_FUNCTION_ARGS)
|
|||
key.upper = (GBT_NUMKEY *) &kkk->upper;
|
||||
|
||||
PG_RETURN_FLOAT8(
|
||||
gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
|
||||
gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -95,14 +95,14 @@ static const gbtree_ninfo tinfo =
|
|||
|
||||
|
||||
PG_FUNCTION_INFO_V1(int4_dist);
|
||||
Datum int4_dist(PG_FUNCTION_ARGS);
|
||||
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;
|
||||
int4 a = PG_GETARG_INT32(0);
|
||||
int4 b = PG_GETARG_INT32(1);
|
||||
int4 r;
|
||||
int4 ra;
|
||||
|
||||
r = a - b;
|
||||
ra = Abs(r);
|
||||
|
@ -111,7 +111,7 @@ int4_dist(PG_FUNCTION_ARGS)
|
|||
if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a)))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
||||
errmsg("integer out of range")));
|
||||
errmsg("integer out of range")));
|
||||
|
||||
PG_RETURN_INT32(ra);
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ gbt_int4_distance(PG_FUNCTION_ARGS)
|
|||
key.upper = (GBT_NUMKEY *) &kkk->upper;
|
||||
|
||||
PG_RETURN_FLOAT8(
|
||||
gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
|
||||
gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -95,14 +95,14 @@ static const gbtree_ninfo tinfo =
|
|||
|
||||
|
||||
PG_FUNCTION_INFO_V1(int8_dist);
|
||||
Datum int8_dist(PG_FUNCTION_ARGS);
|
||||
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;
|
||||
int64 a = PG_GETARG_INT64(0);
|
||||
int64 b = PG_GETARG_INT64(1);
|
||||
int64 r;
|
||||
int64 ra;
|
||||
|
||||
r = a - b;
|
||||
ra = Abs(r);
|
||||
|
@ -111,7 +111,7 @@ int8_dist(PG_FUNCTION_ARGS)
|
|||
if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a)))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
||||
errmsg("bigint out of range")));
|
||||
errmsg("bigint out of range")));
|
||||
|
||||
PG_RETURN_INT64(ra);
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ gbt_int8_distance(PG_FUNCTION_ARGS)
|
|||
key.upper = (GBT_NUMKEY *) &kkk->upper;
|
||||
|
||||
PG_RETURN_FLOAT8(
|
||||
gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
|
||||
gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ intr2num(const Interval *i)
|
|||
static float8
|
||||
gbt_intv_dist(const void *a, const void *b)
|
||||
{
|
||||
return (float8)Abs(intr2num((Interval*)a) - intr2num((Interval*)b));
|
||||
return (float8) Abs(intr2num((Interval *) a) - intr2num((Interval *) b));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -127,7 +127,7 @@ abs_interval(Interval *a)
|
|||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(interval_dist);
|
||||
Datum interval_dist(PG_FUNCTION_ARGS);
|
||||
Datum interval_dist(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
interval_dist(PG_FUNCTION_ARGS)
|
||||
{
|
||||
|
@ -240,7 +240,7 @@ gbt_intv_distance(PG_FUNCTION_ARGS)
|
|||
key.upper = (GBT_NUMKEY *) &kkk->upper;
|
||||
|
||||
PG_RETURN_FLOAT8(
|
||||
gbt_num_distance(&key, (void *) query, GIST_LEAF(entry), &tinfo)
|
||||
gbt_num_distance(&key, (void *) query, GIST_LEAF(entry), &tinfo)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -101,13 +101,13 @@ static const gbtree_ninfo tinfo =
|
|||
|
||||
|
||||
PG_FUNCTION_INFO_V1(oid_dist);
|
||||
Datum oid_dist(PG_FUNCTION_ARGS);
|
||||
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;
|
||||
Oid a = PG_GETARG_OID(0);
|
||||
Oid b = PG_GETARG_OID(1);
|
||||
Oid res;
|
||||
|
||||
if (a < b)
|
||||
res = b - a;
|
||||
|
@ -170,7 +170,7 @@ gbt_oid_distance(PG_FUNCTION_ARGS)
|
|||
key.upper = (GBT_NUMKEY *) &kkk->upper;
|
||||
|
||||
PG_RETURN_FLOAT8(
|
||||
gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
|
||||
gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -119,7 +119,7 @@ gbt_time_dist(const void *a, const void *b)
|
|||
{
|
||||
const TimeADT *aa = (const TimeADT *) a;
|
||||
const TimeADT *bb = (const TimeADT *) b;
|
||||
Interval *i;
|
||||
Interval *i;
|
||||
|
||||
i = DatumGetIntervalP(DirectFunctionCall2(time_mi_time,
|
||||
TimeADTGetDatumFast(*aa),
|
||||
|
@ -143,7 +143,7 @@ static const gbtree_ninfo tinfo =
|
|||
|
||||
|
||||
PG_FUNCTION_INFO_V1(time_dist);
|
||||
Datum time_dist(PG_FUNCTION_ARGS);
|
||||
Datum time_dist(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
time_dist(PG_FUNCTION_ARGS)
|
||||
{
|
||||
|
@ -239,7 +239,7 @@ gbt_time_distance(PG_FUNCTION_ARGS)
|
|||
key.upper = (GBT_NUMKEY *) &kkk->upper;
|
||||
|
||||
PG_RETURN_FLOAT8(
|
||||
gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
|
||||
gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -120,7 +120,7 @@ gbt_ts_dist(const void *a, const void *b)
|
|||
{
|
||||
const Timestamp *aa = (const Timestamp *) a;
|
||||
const Timestamp *bb = (const Timestamp *) b;
|
||||
Interval *i;
|
||||
Interval *i;
|
||||
|
||||
if (TIMESTAMP_NOT_FINITE(*aa) || TIMESTAMP_NOT_FINITE(*bb))
|
||||
return get_float8_infinity();
|
||||
|
@ -147,17 +147,17 @@ static const gbtree_ninfo tinfo =
|
|||
|
||||
|
||||
PG_FUNCTION_INFO_V1(ts_dist);
|
||||
Datum ts_dist(PG_FUNCTION_ARGS);
|
||||
Datum ts_dist(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
ts_dist(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Timestamp a = PG_GETARG_TIMESTAMP(0);
|
||||
Timestamp b = PG_GETARG_TIMESTAMP(1);
|
||||
Interval *r;
|
||||
Interval *r;
|
||||
|
||||
if (TIMESTAMP_NOT_FINITE(a) || TIMESTAMP_NOT_FINITE(b))
|
||||
{
|
||||
Interval *p = palloc(sizeof(Interval));
|
||||
Interval *p = palloc(sizeof(Interval));
|
||||
|
||||
p->day = INT_MAX;
|
||||
p->month = INT_MAX;
|
||||
|
@ -169,25 +169,24 @@ ts_dist(PG_FUNCTION_ARGS)
|
|||
PG_RETURN_INTERVAL_P(p);
|
||||
}
|
||||
else
|
||||
|
||||
r = DatumGetIntervalP(DirectFunctionCall2(timestamp_mi,
|
||||
PG_GETARG_DATUM(0),
|
||||
PG_GETARG_DATUM(1)));
|
||||
PG_RETURN_INTERVAL_P( abs_interval(r) );
|
||||
r = DatumGetIntervalP(DirectFunctionCall2(timestamp_mi,
|
||||
PG_GETARG_DATUM(0),
|
||||
PG_GETARG_DATUM(1)));
|
||||
PG_RETURN_INTERVAL_P(abs_interval(r));
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(tstz_dist);
|
||||
Datum tstz_dist(PG_FUNCTION_ARGS);
|
||||
Datum tstz_dist(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
tstz_dist(PG_FUNCTION_ARGS)
|
||||
{
|
||||
TimestampTz a = PG_GETARG_TIMESTAMPTZ(0);
|
||||
TimestampTz b = PG_GETARG_TIMESTAMPTZ(1);
|
||||
Interval *r;
|
||||
TimestampTz a = PG_GETARG_TIMESTAMPTZ(0);
|
||||
TimestampTz b = PG_GETARG_TIMESTAMPTZ(1);
|
||||
Interval *r;
|
||||
|
||||
if (TIMESTAMP_NOT_FINITE(a) || TIMESTAMP_NOT_FINITE(b))
|
||||
{
|
||||
Interval *p = palloc(sizeof(Interval));
|
||||
Interval *p = palloc(sizeof(Interval));
|
||||
|
||||
p->day = INT_MAX;
|
||||
p->month = INT_MAX;
|
||||
|
@ -202,7 +201,7 @@ tstz_dist(PG_FUNCTION_ARGS)
|
|||
r = DatumGetIntervalP(DirectFunctionCall2(timestamp_mi,
|
||||
PG_GETARG_DATUM(0),
|
||||
PG_GETARG_DATUM(1)));
|
||||
PG_RETURN_INTERVAL_P( abs_interval(r) );
|
||||
PG_RETURN_INTERVAL_P(abs_interval(r));
|
||||
}
|
||||
|
||||
|
||||
|
@ -309,7 +308,7 @@ gbt_ts_distance(PG_FUNCTION_ARGS)
|
|||
key.upper = (GBT_NUMKEY *) &kkk->upper;
|
||||
|
||||
PG_RETURN_FLOAT8(
|
||||
gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
|
||||
gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -354,7 +353,7 @@ gbt_tstz_distance(PG_FUNCTION_ARGS)
|
|||
qqq = tstz_to_ts_gmt(query);
|
||||
|
||||
PG_RETURN_FLOAT8(
|
||||
gbt_num_distance(&key, (void *) &qqq, GIST_LEAF(entry), &tinfo)
|
||||
gbt_num_distance(&key, (void *) &qqq, GIST_LEAF(entry), &tinfo)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -223,8 +223,8 @@ gbt_num_consistent(const GBT_NUMKEY_R *key,
|
|||
retval = (*tinfo->f_le) (query, key->upper);
|
||||
break;
|
||||
case BtreeGistNotEqualStrategyNumber:
|
||||
retval = (! ((*tinfo->f_eq) (query, key->lower) &&
|
||||
(*tinfo->f_eq) (query, key->upper))) ? true : false;
|
||||
retval = (!((*tinfo->f_eq) (query, key->lower) &&
|
||||
(*tinfo->f_eq) (query, key->upper))) ? true : false;
|
||||
break;
|
||||
default:
|
||||
retval = false;
|
||||
|
@ -249,9 +249,9 @@ gbt_num_distance(const GBT_NUMKEY_R *key,
|
|||
if (tinfo->f_dist == NULL)
|
||||
elog(ERROR, "KNN search is not supported for btree_gist type %d",
|
||||
(int) tinfo->t);
|
||||
if ( tinfo->f_le(query, key->lower) )
|
||||
if (tinfo->f_le(query, key->lower))
|
||||
retval = tinfo->f_dist(query, key->lower);
|
||||
else if ( tinfo->f_ge(query, key->upper) )
|
||||
else if (tinfo->f_ge(query, key->upper))
|
||||
retval = tinfo->f_dist(query, key->upper);
|
||||
else
|
||||
retval = 0.0;
|
||||
|
|
|
@ -46,7 +46,7 @@ typedef struct
|
|||
bool (*f_le) (const void *, const void *); /* less or equal */
|
||||
bool (*f_lt) (const void *, const void *); /* less than */
|
||||
int (*f_cmp) (const void *, const void *); /* key compare function */
|
||||
float8 (*f_dist) (const void *, const void *); /* key distance function */
|
||||
float8 (*f_dist) (const void *, const void *); /* key distance function */
|
||||
} gbtree_ninfo;
|
||||
|
||||
|
||||
|
@ -94,7 +94,7 @@ typedef struct
|
|||
|
||||
#define GET_FLOAT_DISTANCE(t, arg1, arg2) Abs( ((float8) *((const t *) (arg1))) - ((float8) *((const t *) (arg2))) )
|
||||
|
||||
#define SAMESIGN(a,b) (((a) < 0) == ((b) < 0))
|
||||
#define SAMESIGN(a,b) (((a) < 0) == ((b) < 0))
|
||||
|
||||
/*
|
||||
* check to see if a float4/8 val has underflowed or overflowed
|
||||
|
@ -121,7 +121,7 @@ extern bool gbt_num_consistent(const GBT_NUMKEY_R *key, const void *query,
|
|||
const gbtree_ninfo *tinfo);
|
||||
|
||||
extern float8 gbt_num_distance(const GBT_NUMKEY_R *key, const void *query,
|
||||
bool is_leaf, const gbtree_ninfo *tinfo);
|
||||
bool is_leaf, const gbtree_ninfo *tinfo);
|
||||
|
||||
extern GIST_SPLITVEC *gbt_num_picksplit(const GistEntryVector *entryvec, GIST_SPLITVEC *v,
|
||||
const gbtree_ninfo *tinfo);
|
||||
|
|
|
@ -598,7 +598,7 @@ gbt_var_consistent(
|
|||
|| gbt_var_node_pf_match(key, query, tinfo);
|
||||
break;
|
||||
case BtreeGistNotEqualStrategyNumber:
|
||||
retval = ! ((*tinfo->f_eq) (query, key->lower) && (*tinfo->f_eq) (query, key->upper));
|
||||
retval = !((*tinfo->f_eq) (query, key->lower) && (*tinfo->f_eq) (query, key->upper));
|
||||
break;
|
||||
default:
|
||||
retval = FALSE;
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
PG_MODULE_MAGIC;
|
||||
|
||||
/* Entrypoint of the module */
|
||||
void _PG_init(void);
|
||||
void _PG_init(void);
|
||||
|
||||
static void
|
||||
dummy_object_relabel(const ObjectAddress *object, const char *seclabel)
|
||||
|
|
|
@ -45,17 +45,17 @@ struct FileFdwOption
|
|||
*/
|
||||
static struct FileFdwOption valid_options[] = {
|
||||
/* File options */
|
||||
{ "filename", ForeignTableRelationId },
|
||||
{"filename", ForeignTableRelationId},
|
||||
|
||||
/* Format options */
|
||||
/* oids option is not supported */
|
||||
{ "format", ForeignTableRelationId },
|
||||
{ "header", ForeignTableRelationId },
|
||||
{ "delimiter", ForeignTableRelationId },
|
||||
{ "quote", ForeignTableRelationId },
|
||||
{ "escape", ForeignTableRelationId },
|
||||
{ "null", ForeignTableRelationId },
|
||||
{ "encoding", ForeignTableRelationId },
|
||||
{"format", ForeignTableRelationId},
|
||||
{"header", ForeignTableRelationId},
|
||||
{"delimiter", ForeignTableRelationId},
|
||||
{"quote", ForeignTableRelationId},
|
||||
{"escape", ForeignTableRelationId},
|
||||
{"null", ForeignTableRelationId},
|
||||
{"encoding", ForeignTableRelationId},
|
||||
|
||||
/*
|
||||
* force_quote is not supported by file_fdw because it's for COPY TO.
|
||||
|
@ -68,7 +68,7 @@ static struct FileFdwOption valid_options[] = {
|
|||
*/
|
||||
|
||||
/* Sentinel */
|
||||
{ NULL, InvalidOid }
|
||||
{NULL, InvalidOid}
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -76,9 +76,9 @@ static struct FileFdwOption valid_options[] = {
|
|||
*/
|
||||
typedef struct FileFdwExecutionState
|
||||
{
|
||||
char *filename; /* file to read */
|
||||
List *options; /* merged COPY options, excluding filename */
|
||||
CopyState cstate; /* state of reading file */
|
||||
char *filename; /* file to read */
|
||||
List *options; /* merged COPY options, excluding filename */
|
||||
CopyState cstate; /* state of reading file */
|
||||
} FileFdwExecutionState;
|
||||
|
||||
/*
|
||||
|
@ -94,8 +94,8 @@ PG_FUNCTION_INFO_V1(file_fdw_validator);
|
|||
* FDW callback routines
|
||||
*/
|
||||
static FdwPlan *filePlanForeignScan(Oid foreigntableid,
|
||||
PlannerInfo *root,
|
||||
RelOptInfo *baserel);
|
||||
PlannerInfo *root,
|
||||
RelOptInfo *baserel);
|
||||
static void fileExplainForeignScan(ForeignScanState *node, ExplainState *es);
|
||||
static void fileBeginForeignScan(ForeignScanState *node, int eflags);
|
||||
static TupleTableSlot *fileIterateForeignScan(ForeignScanState *node);
|
||||
|
@ -109,8 +109,8 @@ static bool is_valid_option(const char *option, Oid context);
|
|||
static void fileGetOptions(Oid foreigntableid,
|
||||
char **filename, List **other_options);
|
||||
static void estimate_costs(PlannerInfo *root, RelOptInfo *baserel,
|
||||
const char *filename,
|
||||
Cost *startup_cost, Cost *total_cost);
|
||||
const char *filename,
|
||||
Cost *startup_cost, Cost *total_cost);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -149,16 +149,16 @@ file_fdw_validator(PG_FUNCTION_ARGS)
|
|||
|
||||
/*
|
||||
* Only superusers are allowed to set options of a file_fdw foreign table.
|
||||
* This is because the filename is one of those options, and we don't
|
||||
* want non-superusers to be able to determine which file gets read.
|
||||
* This is because the filename is one of those options, and we don't want
|
||||
* non-superusers to be able to determine which file gets read.
|
||||
*
|
||||
* Putting this sort of permissions check in a validator is a bit of a
|
||||
* crock, but there doesn't seem to be any other place that can enforce
|
||||
* the check more cleanly.
|
||||
*
|
||||
* Note that the valid_options[] array disallows setting filename at
|
||||
* any options level other than foreign table --- otherwise there'd
|
||||
* still be a security hole.
|
||||
* Note that the valid_options[] array disallows setting filename at any
|
||||
* options level other than foreign table --- otherwise there'd still be a
|
||||
* security hole.
|
||||
*/
|
||||
if (catalog == ForeignTableRelationId && !superuser())
|
||||
ereport(ERROR,
|
||||
|
@ -171,7 +171,7 @@ file_fdw_validator(PG_FUNCTION_ARGS)
|
|||
*/
|
||||
foreach(cell, options_list)
|
||||
{
|
||||
DefElem *def = (DefElem *) lfirst(cell);
|
||||
DefElem *def = (DefElem *) lfirst(cell);
|
||||
|
||||
if (!is_valid_option(def->defname, catalog))
|
||||
{
|
||||
|
@ -276,7 +276,7 @@ fileGetOptions(Oid foreigntableid,
|
|||
prev = NULL;
|
||||
foreach(lc, options)
|
||||
{
|
||||
DefElem *def = (DefElem *) lfirst(lc);
|
||||
DefElem *def = (DefElem *) lfirst(lc);
|
||||
|
||||
if (strcmp(def->defname, "filename") == 0)
|
||||
{
|
||||
|
@ -302,7 +302,7 @@ filePlanForeignScan(Oid foreigntableid,
|
|||
PlannerInfo *root,
|
||||
RelOptInfo *baserel)
|
||||
{
|
||||
FdwPlan *fdwplan;
|
||||
FdwPlan *fdwplan;
|
||||
char *filename;
|
||||
List *options;
|
||||
|
||||
|
@ -313,7 +313,7 @@ filePlanForeignScan(Oid foreigntableid,
|
|||
fdwplan = makeNode(FdwPlan);
|
||||
estimate_costs(root, baserel, filename,
|
||||
&fdwplan->startup_cost, &fdwplan->total_cost);
|
||||
fdwplan->fdw_private = NIL; /* not used */
|
||||
fdwplan->fdw_private = NIL; /* not used */
|
||||
|
||||
return fdwplan;
|
||||
}
|
||||
|
@ -337,7 +337,7 @@ fileExplainForeignScan(ForeignScanState *node, ExplainState *es)
|
|||
/* Suppress file size if we're not showing cost details */
|
||||
if (es->costs)
|
||||
{
|
||||
struct stat stat_buf;
|
||||
struct stat stat_buf;
|
||||
|
||||
if (stat(filename, &stat_buf) == 0)
|
||||
ExplainPropertyLong("Foreign File Size", (long) stat_buf.st_size,
|
||||
|
@ -368,8 +368,8 @@ fileBeginForeignScan(ForeignScanState *node, int eflags)
|
|||
&filename, &options);
|
||||
|
||||
/*
|
||||
* Create CopyState from FDW options. We always acquire all columns,
|
||||
* so as to match the expected ScanTupleSlot signature.
|
||||
* Create CopyState from FDW options. We always acquire all columns, so
|
||||
* as to match the expected ScanTupleSlot signature.
|
||||
*/
|
||||
cstate = BeginCopyFrom(node->ss.ss_currentRelation,
|
||||
filename,
|
||||
|
@ -398,7 +398,7 @@ fileIterateForeignScan(ForeignScanState *node)
|
|||
{
|
||||
FileFdwExecutionState *festate = (FileFdwExecutionState *) node->fdw_state;
|
||||
TupleTableSlot *slot = node->ss.ss_ScanTupleSlot;
|
||||
bool found;
|
||||
bool found;
|
||||
ErrorContextCallback errcontext;
|
||||
|
||||
/* Set up callback to identify error line number. */
|
||||
|
@ -410,8 +410,8 @@ fileIterateForeignScan(ForeignScanState *node)
|
|||
/*
|
||||
* The protocol for loading a virtual tuple into a slot is first
|
||||
* ExecClearTuple, then fill the values/isnull arrays, then
|
||||
* ExecStoreVirtualTuple. If we don't find another row in the file,
|
||||
* we just skip the last step, leaving the slot empty as required.
|
||||
* ExecStoreVirtualTuple. If we don't find another row in the file, we
|
||||
* just skip the last step, leaving the slot empty as required.
|
||||
*
|
||||
* We can pass ExprContext = NULL because we read all columns from the
|
||||
* file, so no need to evaluate default expressions.
|
||||
|
@ -471,17 +471,17 @@ estimate_costs(PlannerInfo *root, RelOptInfo *baserel,
|
|||
const char *filename,
|
||||
Cost *startup_cost, Cost *total_cost)
|
||||
{
|
||||
struct stat stat_buf;
|
||||
BlockNumber pages;
|
||||
int tuple_width;
|
||||
double ntuples;
|
||||
double nrows;
|
||||
Cost run_cost = 0;
|
||||
Cost cpu_per_tuple;
|
||||
struct stat stat_buf;
|
||||
BlockNumber pages;
|
||||
int tuple_width;
|
||||
double ntuples;
|
||||
double nrows;
|
||||
Cost run_cost = 0;
|
||||
Cost cpu_per_tuple;
|
||||
|
||||
/*
|
||||
* Get size of the file. It might not be there at plan time, though,
|
||||
* in which case we have to use a default estimate.
|
||||
* Get size of the file. It might not be there at plan time, though, in
|
||||
* which case we have to use a default estimate.
|
||||
*/
|
||||
if (stat(filename, &stat_buf) < 0)
|
||||
stat_buf.st_size = 10 * BLCKSZ;
|
||||
|
@ -489,7 +489,7 @@ estimate_costs(PlannerInfo *root, RelOptInfo *baserel,
|
|||
/*
|
||||
* Convert size to pages for use in I/O cost estimate below.
|
||||
*/
|
||||
pages = (stat_buf.st_size + (BLCKSZ-1)) / BLCKSZ;
|
||||
pages = (stat_buf.st_size + (BLCKSZ - 1)) / BLCKSZ;
|
||||
if (pages < 1)
|
||||
pages = 1;
|
||||
|
||||
|
@ -505,10 +505,9 @@ estimate_costs(PlannerInfo *root, RelOptInfo *baserel,
|
|||
ntuples = clamp_row_est((double) stat_buf.st_size / (double) tuple_width);
|
||||
|
||||
/*
|
||||
* Now estimate the number of rows returned by the scan after applying
|
||||
* the baserestrictinfo quals. This is pretty bogus too, since the
|
||||
* planner will have no stats about the relation, but it's better than
|
||||
* nothing.
|
||||
* Now estimate the number of rows returned by the scan after applying the
|
||||
* baserestrictinfo quals. This is pretty bogus too, since the planner
|
||||
* will have no stats about the relation, but it's better than nothing.
|
||||
*/
|
||||
nrows = ntuples *
|
||||
clauselist_selectivity(root,
|
||||
|
@ -523,7 +522,7 @@ estimate_costs(PlannerInfo *root, RelOptInfo *baserel,
|
|||
baserel->rows = nrows;
|
||||
|
||||
/*
|
||||
* Now estimate costs. We estimate costs almost the same way as
|
||||
* Now estimate costs. We estimate costs almost the same way as
|
||||
* cost_seqscan(), thus assuming that I/O costs are equivalent to a
|
||||
* regular table file of the same size. However, we take per-tuple CPU
|
||||
* costs as 10x of a seqscan, to account for the cost of parsing records.
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
*/
|
||||
#ifdef LEVENSHTEIN_LESS_EQUAL
|
||||
static int levenshtein_less_equal_internal(text *s, text *t,
|
||||
int ins_c, int del_c, int sub_c, int max_d);
|
||||
int ins_c, int del_c, int sub_c, int max_d);
|
||||
#else
|
||||
static int levenshtein_internal(text *s, text *t,
|
||||
int ins_c, int del_c, int sub_c);
|
||||
|
@ -50,7 +50,7 @@ static int levenshtein_internal(text *s, text *t,
|
|||
* array.
|
||||
*
|
||||
* If max_d >= 0, we only need to provide an accurate answer when that answer
|
||||
* is less than or equal to the bound. From any cell in the matrix, there is
|
||||
* is less than or equal to the bound. From any cell in the matrix, there is
|
||||
* theoretical "minimum residual distance" from that cell to the last column
|
||||
* of the final row. This minimum residual distance is zero when the
|
||||
* untransformed portions of the strings are of equal length (because we might
|
||||
|
@ -87,11 +87,13 @@ levenshtein_internal(text *s, text *t,
|
|||
|
||||
/*
|
||||
* For levenshtein_less_equal_internal, we have real variables called
|
||||
* start_column and stop_column; otherwise it's just short-hand for 0
|
||||
* and m.
|
||||
* start_column and stop_column; otherwise it's just short-hand for 0 and
|
||||
* m.
|
||||
*/
|
||||
#ifdef LEVENSHTEIN_LESS_EQUAL
|
||||
int start_column, stop_column;
|
||||
int start_column,
|
||||
stop_column;
|
||||
|
||||
#undef START_COLUMN
|
||||
#undef STOP_COLUMN
|
||||
#define START_COLUMN start_column
|
||||
|
@ -139,16 +141,16 @@ levenshtein_internal(text *s, text *t,
|
|||
stop_column = m + 1;
|
||||
|
||||
/*
|
||||
* If max_d >= 0, determine whether the bound is impossibly tight. If so,
|
||||
* If max_d >= 0, determine whether the bound is impossibly tight. If so,
|
||||
* return max_d + 1 immediately. Otherwise, determine whether it's tight
|
||||
* enough to limit the computation we must perform. If so, figure out
|
||||
* initial stop column.
|
||||
*/
|
||||
if (max_d >= 0)
|
||||
{
|
||||
int min_theo_d; /* Theoretical minimum distance. */
|
||||
int max_theo_d; /* Theoretical maximum distance. */
|
||||
int net_inserts = n - m;
|
||||
int min_theo_d; /* Theoretical minimum distance. */
|
||||
int max_theo_d; /* Theoretical maximum distance. */
|
||||
int net_inserts = n - m;
|
||||
|
||||
min_theo_d = net_inserts < 0 ?
|
||||
-net_inserts * del_c : net_inserts * ins_c;
|
||||
|
@ -162,20 +164,20 @@ levenshtein_internal(text *s, text *t,
|
|||
else if (ins_c + del_c > 0)
|
||||
{
|
||||
/*
|
||||
* Figure out how much of the first row of the notional matrix
|
||||
* we need to fill in. If the string is growing, the theoretical
|
||||
* Figure out how much of the first row of the notional matrix we
|
||||
* need to fill in. If the string is growing, the theoretical
|
||||
* minimum distance already incorporates the cost of deleting the
|
||||
* number of characters necessary to make the two strings equal
|
||||
* in length. Each additional deletion forces another insertion,
|
||||
* so the best-case total cost increases by ins_c + del_c.
|
||||
* If the string is shrinking, the minimum theoretical cost
|
||||
* assumes no excess deletions; that is, we're starting no futher
|
||||
* right than column n - m. If we do start further right, the
|
||||
* best-case total cost increases by ins_c + del_c for each move
|
||||
* right.
|
||||
* number of characters necessary to make the two strings equal in
|
||||
* length. Each additional deletion forces another insertion, so
|
||||
* the best-case total cost increases by ins_c + del_c. If the
|
||||
* string is shrinking, the minimum theoretical cost assumes no
|
||||
* excess deletions; that is, we're starting no futher right than
|
||||
* column n - m. If we do start further right, the best-case
|
||||
* total cost increases by ins_c + del_c for each move right.
|
||||
*/
|
||||
int slack_d = max_d - min_theo_d;
|
||||
int best_column = net_inserts < 0 ? -net_inserts : 0;
|
||||
int slack_d = max_d - min_theo_d;
|
||||
int best_column = net_inserts < 0 ? -net_inserts : 0;
|
||||
|
||||
stop_column = best_column + (slack_d / (ins_c + del_c)) + 1;
|
||||
if (stop_column > m)
|
||||
stop_column = m + 1;
|
||||
|
@ -185,15 +187,15 @@ levenshtein_internal(text *s, text *t,
|
|||
|
||||
/*
|
||||
* In order to avoid calling pg_mblen() repeatedly on each character in s,
|
||||
* we cache all the lengths before starting the main loop -- but if all the
|
||||
* characters in both strings are single byte, then we skip this and use
|
||||
* a fast-path in the main loop. If only one string contains multi-byte
|
||||
* characters, we still build the array, so that the fast-path needn't
|
||||
* deal with the case where the array hasn't been initialized.
|
||||
* we cache all the lengths before starting the main loop -- but if all
|
||||
* the characters in both strings are single byte, then we skip this and
|
||||
* use a fast-path in the main loop. If only one string contains
|
||||
* multi-byte characters, we still build the array, so that the fast-path
|
||||
* needn't deal with the case where the array hasn't been initialized.
|
||||
*/
|
||||
if (m != s_bytes || n != t_bytes)
|
||||
{
|
||||
int i;
|
||||
int i;
|
||||
const char *cp = s_data;
|
||||
|
||||
s_char_len = (int *) palloc((m + 1) * sizeof(int));
|
||||
|
@ -214,8 +216,8 @@ levenshtein_internal(text *s, text *t,
|
|||
curr = prev + m;
|
||||
|
||||
/*
|
||||
* To transform the first i characters of s into the first 0 characters
|
||||
* of t, we must perform i deletions.
|
||||
* To transform the first i characters of s into the first 0 characters of
|
||||
* t, we must perform i deletions.
|
||||
*/
|
||||
for (i = START_COLUMN; i < STOP_COLUMN; i++)
|
||||
prev[i] = i * del_c;
|
||||
|
@ -228,6 +230,7 @@ levenshtein_internal(text *s, text *t,
|
|||
int y_char_len = n != t_bytes + 1 ? pg_mblen(y) : 1;
|
||||
|
||||
#ifdef LEVENSHTEIN_LESS_EQUAL
|
||||
|
||||
/*
|
||||
* In the best case, values percolate down the diagonal unchanged, so
|
||||
* we must increment stop_column unless it's already on the right end
|
||||
|
@ -241,10 +244,10 @@ levenshtein_internal(text *s, text *t,
|
|||
}
|
||||
|
||||
/*
|
||||
* The main loop fills in curr, but curr[0] needs a special case:
|
||||
* to transform the first 0 characters of s into the first j
|
||||
* characters of t, we must perform j insertions. However, if
|
||||
* start_column > 0, this special case does not apply.
|
||||
* The main loop fills in curr, but curr[0] needs a special case: to
|
||||
* transform the first 0 characters of s into the first j characters
|
||||
* of t, we must perform j insertions. However, if start_column > 0,
|
||||
* this special case does not apply.
|
||||
*/
|
||||
if (start_column == 0)
|
||||
{
|
||||
|
@ -285,7 +288,7 @@ levenshtein_internal(text *s, text *t,
|
|||
*/
|
||||
ins = prev[i] + ins_c;
|
||||
del = curr[i - 1] + del_c;
|
||||
if (x[x_char_len-1] == y[y_char_len-1]
|
||||
if (x[x_char_len - 1] == y[y_char_len - 1]
|
||||
&& x_char_len == y_char_len &&
|
||||
(x_char_len == 1 || rest_of_char_same(x, y, x_char_len)))
|
||||
sub = prev[i - 1];
|
||||
|
@ -331,6 +334,7 @@ levenshtein_internal(text *s, text *t,
|
|||
y += y_char_len;
|
||||
|
||||
#ifdef LEVENSHTEIN_LESS_EQUAL
|
||||
|
||||
/*
|
||||
* This chunk of code represents a significant performance hit if used
|
||||
* in the case where there is no max_d bound. This is probably not
|
||||
|
@ -348,15 +352,16 @@ levenshtein_internal(text *s, text *t,
|
|||
* string, so we want to find the value for zp where where (n - 1)
|
||||
* - j = (m - 1) - zp.
|
||||
*/
|
||||
int zp = j - (n - m);
|
||||
int zp = j - (n - m);
|
||||
|
||||
/* Check whether the stop column can slide left. */
|
||||
while (stop_column > 0)
|
||||
{
|
||||
int ii = stop_column - 1;
|
||||
int net_inserts = ii - zp;
|
||||
int ii = stop_column - 1;
|
||||
int net_inserts = ii - zp;
|
||||
|
||||
if (prev[ii] + (net_inserts > 0 ? net_inserts * ins_c :
|
||||
-net_inserts * del_c) <= max_d)
|
||||
-net_inserts * del_c) <= max_d)
|
||||
break;
|
||||
stop_column--;
|
||||
}
|
||||
|
@ -364,14 +369,16 @@ levenshtein_internal(text *s, text *t,
|
|||
/* Check whether the start column can slide right. */
|
||||
while (start_column < stop_column)
|
||||
{
|
||||
int net_inserts = start_column - zp;
|
||||
int net_inserts = start_column - zp;
|
||||
|
||||
if (prev[start_column] +
|
||||
(net_inserts > 0 ? net_inserts * ins_c :
|
||||
-net_inserts * del_c) <= max_d)
|
||||
-net_inserts * del_c) <= max_d)
|
||||
break;
|
||||
|
||||
/*
|
||||
* We'll never again update these values, so we must make
|
||||
* sure there's nothing here that could confuse any future
|
||||
* We'll never again update these values, so we must make sure
|
||||
* there's nothing here that could confuse any future
|
||||
* iteration of the outer loop.
|
||||
*/
|
||||
prev[start_column] = max_d + 1;
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
/*
|
||||
* When using a GIN index for hstore, we choose to index both keys and values.
|
||||
* The storage format is "text" values, with K, V, or N prepended to the string
|
||||
* to indicate key, value, or null values. (As of 9.1 it might be better to
|
||||
* to indicate key, value, or null values. (As of 9.1 it might be better to
|
||||
* store null values as nulls, but we'll keep it this way for on-disk
|
||||
* compatibility.)
|
||||
*/
|
||||
|
@ -168,7 +168,7 @@ gin_consistent_hstore(PG_FUNCTION_ARGS)
|
|||
{
|
||||
/*
|
||||
* Index doesn't have information about correspondence of keys and
|
||||
* values, so we need recheck. However, if not all the keys are
|
||||
* values, so we need recheck. However, if not all the keys are
|
||||
* present, we can fail at once.
|
||||
*/
|
||||
*recheck = true;
|
||||
|
|
|
@ -437,7 +437,7 @@ hstore_delete_hstore(PG_FUNCTION_ARGS)
|
|||
if (snullval != HS_VALISNULL(es2, j)
|
||||
|| (!snullval
|
||||
&& (svallen != HS_VALLEN(es2, j)
|
||||
|| memcmp(HS_VAL(es, ps, i), HS_VAL(es2, ps2, j), svallen) != 0)))
|
||||
|| memcmp(HS_VAL(es, ps, i), HS_VAL(es2, ps2, j), svallen) != 0)))
|
||||
{
|
||||
HS_COPYITEM(ed, bufd, pd,
|
||||
HS_KEY(es, ps, i), HS_KEYLEN(es, i),
|
||||
|
@ -1000,7 +1000,7 @@ hstore_contains(PG_FUNCTION_ARGS)
|
|||
if (nullval != HS_VALISNULL(ve, idx)
|
||||
|| (!nullval
|
||||
&& (vallen != HS_VALLEN(ve, idx)
|
||||
|| memcmp(HS_VAL(te, tstr, i), HS_VAL(ve, vstr, idx), vallen))))
|
||||
|| memcmp(HS_VAL(te, tstr, i), HS_VAL(ve, vstr, idx), vallen))))
|
||||
res = false;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -98,7 +98,7 @@ gettoken(WORKSTATE *state, int4 *val)
|
|||
}
|
||||
else
|
||||
{
|
||||
long lval;
|
||||
long lval;
|
||||
|
||||
nnn[innn] = '\0';
|
||||
errno = 0;
|
||||
|
@ -355,8 +355,8 @@ gin_bool_consistent(QUERYTYPE *query, bool *check)
|
|||
return FALSE;
|
||||
|
||||
/*
|
||||
* Set up data for checkcondition_gin. This must agree with the
|
||||
* query extraction code in ginint4_queryextract.
|
||||
* Set up data for checkcondition_gin. This must agree with the query
|
||||
* extraction code in ginint4_queryextract.
|
||||
*/
|
||||
gcv.first = items;
|
||||
gcv.mapped_check = (bool *) palloc(sizeof(bool) * query->size);
|
||||
|
|
|
@ -34,8 +34,8 @@ ginint4_queryextract(PG_FUNCTION_ARGS)
|
|||
|
||||
/*
|
||||
* If the query doesn't have any required primitive values (for
|
||||
* instance, it's something like '! 42'), we have to do a full
|
||||
* index scan.
|
||||
* instance, it's something like '! 42'), we have to do a full index
|
||||
* scan.
|
||||
*/
|
||||
if (query_has_required_values(query))
|
||||
*searchMode = GIN_SEARCH_MODE_DEFAULT;
|
||||
|
@ -95,7 +95,7 @@ ginint4_queryextract(PG_FUNCTION_ARGS)
|
|||
case RTOldContainsStrategyNumber:
|
||||
if (*nentries > 0)
|
||||
*searchMode = GIN_SEARCH_MODE_DEFAULT;
|
||||
else /* everything contains the empty set */
|
||||
else /* everything contains the empty set */
|
||||
*searchMode = GIN_SEARCH_MODE_ALL;
|
||||
break;
|
||||
default:
|
||||
|
@ -116,6 +116,7 @@ ginint4_consistent(PG_FUNCTION_ARGS)
|
|||
bool *check = (bool *) PG_GETARG_POINTER(0);
|
||||
StrategyNumber strategy = PG_GETARG_UINT16(1);
|
||||
int32 nkeys = PG_GETARG_INT32(3);
|
||||
|
||||
/* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
|
||||
bool *recheck = (bool *) PG_GETARG_POINTER(5);
|
||||
bool res = FALSE;
|
||||
|
|
|
@ -183,7 +183,7 @@ rt__int_size(ArrayType *a, float *size)
|
|||
*size = (float) ARRNELEMS(a);
|
||||
}
|
||||
|
||||
/* Sort the given data (len >= 2). Return true if any duplicates found */
|
||||
/* Sort the given data (len >= 2). Return true if any duplicates found */
|
||||
bool
|
||||
isort(int4 *a, int len)
|
||||
{
|
||||
|
@ -195,7 +195,7 @@ isort(int4 *a, int len)
|
|||
bool r = FALSE;
|
||||
|
||||
/*
|
||||
* We use a simple insertion sort. While this is O(N^2) in the worst
|
||||
* We use a simple insertion sort. While this is O(N^2) in the worst
|
||||
* case, it's quite fast if the input is already sorted or nearly so.
|
||||
* Also, for not-too-large inputs it's faster than more complex methods
|
||||
* anyhow.
|
||||
|
|
|
@ -988,4 +988,3 @@ const char *ISBN_range_new[][2] = {
|
|||
{"10-976000", "10-999999"},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
|
|
|
@ -25,9 +25,9 @@
|
|||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
#else /* WIN32 */
|
||||
#else /* WIN32 */
|
||||
extern int getopt(int argc, char *const argv[], const char *optstring);
|
||||
#endif /* ! WIN32 */
|
||||
#endif /* ! WIN32 */
|
||||
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
|
|
|
@ -137,7 +137,7 @@ typedef enum
|
|||
PGSS_TRACK_NONE, /* track no statements */
|
||||
PGSS_TRACK_TOP, /* only top level statements */
|
||||
PGSS_TRACK_ALL /* all statements, including nested ones */
|
||||
} PGSSTrackLevel;
|
||||
} PGSSTrackLevel;
|
||||
|
||||
static const struct config_enum_entry track_options[] =
|
||||
{
|
||||
|
|
|
@ -28,24 +28,28 @@
|
|||
|
||||
static const char *progname;
|
||||
|
||||
static int ops_per_test = 2000;
|
||||
static char full_buf[XLOG_SEG_SIZE], *buf, *filename = FSYNC_FILENAME;
|
||||
static struct timeval start_t, stop_t;
|
||||
static int ops_per_test = 2000;
|
||||
static char full_buf[XLOG_SEG_SIZE],
|
||||
*buf,
|
||||
*filename = FSYNC_FILENAME;
|
||||
static struct timeval start_t,
|
||||
stop_t;
|
||||
|
||||
|
||||
static void handle_args(int argc, char *argv[]);
|
||||
static void prepare_buf(void);
|
||||
static void test_open(void);
|
||||
static void test_non_sync(void);
|
||||
static void test_sync(int writes_per_op);
|
||||
static void test_open_syncs(void);
|
||||
static void test_open_sync(const char *msg, int writes_size);
|
||||
static void test_file_descriptor_sync(void);
|
||||
static void handle_args(int argc, char *argv[]);
|
||||
static void prepare_buf(void);
|
||||
static void test_open(void);
|
||||
static void test_non_sync(void);
|
||||
static void test_sync(int writes_per_op);
|
||||
static void test_open_syncs(void);
|
||||
static void test_open_sync(const char *msg, int writes_size);
|
||||
static void test_file_descriptor_sync(void);
|
||||
|
||||
#ifdef HAVE_FSYNC_WRITETHROUGH
|
||||
static int pg_fsync_writethrough(int fd);
|
||||
#endif
|
||||
static void print_elapse(struct timeval start_t, struct timeval stop_t);
|
||||
static void die(const char *str);
|
||||
static void print_elapse(struct timeval start_t, struct timeval stop_t);
|
||||
static void die(const char *str);
|
||||
|
||||
|
||||
int
|
||||
|
@ -103,7 +107,7 @@ handle_args(int argc, char *argv[])
|
|||
}
|
||||
|
||||
while ((option = getopt_long(argc, argv, "f:o:",
|
||||
long_options, &optindex)) != -1)
|
||||
long_options, &optindex)) != -1)
|
||||
{
|
||||
switch (option)
|
||||
{
|
||||
|
@ -176,7 +180,9 @@ test_open(void)
|
|||
static void
|
||||
test_sync(int writes_per_op)
|
||||
{
|
||||
int tmpfile, ops, writes;
|
||||
int tmpfile,
|
||||
ops,
|
||||
writes;
|
||||
bool fs_warning = false;
|
||||
|
||||
if (writes_per_op == 1)
|
||||
|
@ -353,7 +359,9 @@ test_open_syncs(void)
|
|||
static void
|
||||
test_open_sync(const char *msg, int writes_size)
|
||||
{
|
||||
int tmpfile, ops, writes;
|
||||
int tmpfile,
|
||||
ops,
|
||||
writes;
|
||||
|
||||
printf(LABEL_FORMAT, msg);
|
||||
fflush(stdout);
|
||||
|
@ -377,7 +385,6 @@ test_open_sync(const char *msg, int writes_size)
|
|||
close(tmpfile);
|
||||
print_elapse(start_t, stop_t);
|
||||
}
|
||||
|
||||
#else
|
||||
printf(NA_FORMAT, "n/a\n");
|
||||
#endif
|
||||
|
@ -386,22 +393,22 @@ test_open_sync(const char *msg, int writes_size)
|
|||
static void
|
||||
test_file_descriptor_sync(void)
|
||||
{
|
||||
int tmpfile, ops;
|
||||
int tmpfile,
|
||||
ops;
|
||||
|
||||
/*
|
||||
* Test whether fsync can sync data written on a different
|
||||
* descriptor for the same file. This checks the efficiency
|
||||
* of multi-process fsyncs against the same file.
|
||||
* Possibly this should be done with writethrough on platforms
|
||||
* which support it.
|
||||
* Test whether fsync can sync data written on a different descriptor for
|
||||
* the same file. This checks the efficiency of multi-process fsyncs
|
||||
* against the same file. Possibly this should be done with writethrough
|
||||
* on platforms which support it.
|
||||
*/
|
||||
printf("\nTest if fsync on non-write file descriptor is honored:\n");
|
||||
printf("(If the times are similar, fsync() can sync data written\n");
|
||||
printf("on a different descriptor.)\n");
|
||||
|
||||
/*
|
||||
* first write, fsync and close, which is the
|
||||
* normal behavior without multiple descriptors
|
||||
* first write, fsync and close, which is the normal behavior without
|
||||
* multiple descriptors
|
||||
*/
|
||||
printf(LABEL_FORMAT, "write, fsync, close");
|
||||
fflush(stdout);
|
||||
|
@ -416,9 +423,10 @@ test_file_descriptor_sync(void)
|
|||
if (fsync(tmpfile) != 0)
|
||||
die("fsync failed");
|
||||
close(tmpfile);
|
||||
|
||||
/*
|
||||
* open and close the file again to be consistent
|
||||
* with the following test
|
||||
* open and close the file again to be consistent with the following
|
||||
* test
|
||||
*/
|
||||
if ((tmpfile = open(filename, O_RDWR, 0)) == -1)
|
||||
die("could not open output file");
|
||||
|
@ -428,9 +436,8 @@ test_file_descriptor_sync(void)
|
|||
print_elapse(start_t, stop_t);
|
||||
|
||||
/*
|
||||
* Now open, write, close, open again and fsync
|
||||
* This simulates processes fsyncing each other's
|
||||
* writes.
|
||||
* Now open, write, close, open again and fsync This simulates processes
|
||||
* fsyncing each other's writes.
|
||||
*/
|
||||
printf(LABEL_FORMAT, "write, close, fsync");
|
||||
fflush(stdout);
|
||||
|
@ -458,7 +465,8 @@ test_file_descriptor_sync(void)
|
|||
static void
|
||||
test_non_sync(void)
|
||||
{
|
||||
int tmpfile, ops;
|
||||
int tmpfile,
|
||||
ops;
|
||||
|
||||
/*
|
||||
* Test a simple write without fsync
|
||||
|
@ -494,7 +502,6 @@ pg_fsync_writethrough(int fd)
|
|||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
|
@ -51,8 +51,9 @@ uint32 trgm2int(trgm *ptr);
|
|||
#endif
|
||||
#define ISPRINTABLETRGM(t) ( ISPRINTABLECHAR( ((char*)(t)) ) && ISPRINTABLECHAR( ((char*)(t))+1 ) && ISPRINTABLECHAR( ((char*)(t))+2 ) )
|
||||
|
||||
#define ISESCAPECHAR(x) (*(x) == '\\') /* Wildcard escape character */
|
||||
#define ISWILDCARDCHAR(x) (*(x) == '_' || *(x) == '%') /* Wildcard meta-character */
|
||||
#define ISESCAPECHAR(x) (*(x) == '\\') /* Wildcard escape character */
|
||||
#define ISWILDCARDCHAR(x) (*(x) == '_' || *(x) == '%') /* Wildcard
|
||||
* meta-character */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
@ -105,4 +106,4 @@ TRGM *generate_wildcard_trgm(const char *str, int slen);
|
|||
float4 cnt_sml(TRGM *trg1, TRGM *trg2);
|
||||
bool trgm_contained_by(TRGM *trg1, TRGM *trg2);
|
||||
|
||||
#endif /* __TRGM_H__ */
|
||||
#endif /* __TRGM_H__ */
|
||||
|
|
|
@ -67,7 +67,7 @@ gin_extract_value_trgm(PG_FUNCTION_ARGS)
|
|||
ptr = GETARR(trg);
|
||||
for (i = 0; i < trglen; i++)
|
||||
{
|
||||
int32 item = trgm2int(ptr);
|
||||
int32 item = trgm2int(ptr);
|
||||
|
||||
entries[i] = Int32GetDatum(item);
|
||||
ptr++;
|
||||
|
@ -83,10 +83,11 @@ gin_extract_query_trgm(PG_FUNCTION_ARGS)
|
|||
text *val = (text *) PG_GETARG_TEXT_P(0);
|
||||
int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
|
||||
StrategyNumber strategy = PG_GETARG_UINT16(2);
|
||||
/* bool **pmatch = (bool **) PG_GETARG_POINTER(3); */
|
||||
/* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
|
||||
/* bool **nullFlags = (bool **) PG_GETARG_POINTER(5); */
|
||||
int32 *searchMode = (int32 *) PG_GETARG_POINTER(6);
|
||||
|
||||
/* bool **pmatch = (bool **) PG_GETARG_POINTER(3); */
|
||||
/* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
|
||||
/* bool **nullFlags = (bool **) PG_GETARG_POINTER(5); */
|
||||
int32 *searchMode = (int32 *) PG_GETARG_POINTER(6);
|
||||
Datum *entries = NULL;
|
||||
TRGM *trg;
|
||||
int32 trglen;
|
||||
|
@ -104,6 +105,7 @@ gin_extract_query_trgm(PG_FUNCTION_ARGS)
|
|||
#endif
|
||||
/* FALL THRU */
|
||||
case LikeStrategyNumber:
|
||||
|
||||
/*
|
||||
* For wildcard search we extract all the trigrams that every
|
||||
* potentially-matching string must include.
|
||||
|
@ -112,7 +114,7 @@ gin_extract_query_trgm(PG_FUNCTION_ARGS)
|
|||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized strategy number: %d", strategy);
|
||||
trg = NULL; /* keep compiler quiet */
|
||||
trg = NULL; /* keep compiler quiet */
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -125,7 +127,7 @@ gin_extract_query_trgm(PG_FUNCTION_ARGS)
|
|||
ptr = GETARR(trg);
|
||||
for (i = 0; i < trglen; i++)
|
||||
{
|
||||
int32 item = trgm2int(ptr);
|
||||
int32 item = trgm2int(ptr);
|
||||
|
||||
entries[i] = Int32GetDatum(item);
|
||||
ptr++;
|
||||
|
@ -146,9 +148,11 @@ gin_trgm_consistent(PG_FUNCTION_ARGS)
|
|||
{
|
||||
bool *check = (bool *) PG_GETARG_POINTER(0);
|
||||
StrategyNumber strategy = PG_GETARG_UINT16(1);
|
||||
|
||||
/* text *query = PG_GETARG_TEXT_P(2); */
|
||||
int32 nkeys = PG_GETARG_INT32(3);
|
||||
/* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
|
||||
|
||||
/* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
|
||||
bool *recheck = (bool *) PG_GETARG_POINTER(5);
|
||||
bool res;
|
||||
int32 i,
|
||||
|
|
|
@ -190,17 +190,18 @@ gtrgm_consistent(PG_FUNCTION_ARGS)
|
|||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
text *query = PG_GETARG_TEXT_P(1);
|
||||
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
|
||||
|
||||
/* Oid subtype = PG_GETARG_OID(3); */
|
||||
bool *recheck = (bool *) PG_GETARG_POINTER(4);
|
||||
TRGM *key = (TRGM *) DatumGetPointer(entry->key);
|
||||
TRGM *qtrg;
|
||||
bool res;
|
||||
char *cache = (char *) fcinfo->flinfo->fn_extra,
|
||||
*cacheContents = cache + MAXALIGN(sizeof(StrategyNumber));
|
||||
*cacheContents = cache + MAXALIGN(sizeof(StrategyNumber));
|
||||
|
||||
/*
|
||||
* Store both the strategy number and extracted trigrams in cache, because
|
||||
* trigram extraction is relatively CPU-expensive. We must include
|
||||
* trigram extraction is relatively CPU-expensive. We must include
|
||||
* strategy number because trigram extraction depends on strategy.
|
||||
*/
|
||||
if (cache == NULL || strategy != *((StrategyNumber *) cache) ||
|
||||
|
@ -222,7 +223,7 @@ gtrgm_consistent(PG_FUNCTION_ARGS)
|
|||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized strategy number: %d", strategy);
|
||||
qtrg = NULL; /* keep compiler quiet */
|
||||
qtrg = NULL; /* keep compiler quiet */
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -251,20 +252,20 @@ gtrgm_consistent(PG_FUNCTION_ARGS)
|
|||
*recheck = false;
|
||||
|
||||
if (GIST_LEAF(entry))
|
||||
{ /* all leafs contains orig trgm */
|
||||
float4 tmpsml = cnt_sml(key, qtrg);
|
||||
{ /* all leafs contains orig trgm */
|
||||
float4 tmpsml = cnt_sml(key, qtrg);
|
||||
|
||||
/* strange bug at freebsd 5.2.1 and gcc 3.3.3 */
|
||||
res = (*(int *) &tmpsml == *(int *) &trgm_limit || tmpsml > trgm_limit) ? true : false;
|
||||
}
|
||||
else if (ISALLTRUE(key))
|
||||
{ /* non-leaf contains signature */
|
||||
{ /* non-leaf contains signature */
|
||||
res = true;
|
||||
}
|
||||
else
|
||||
{ /* non-leaf contains signature */
|
||||
int4 count = cnt_sml_sign_common(qtrg, GETSIGN(key));
|
||||
int4 len = ARRNELEM(qtrg);
|
||||
{ /* non-leaf contains signature */
|
||||
int4 count = cnt_sml_sign_common(qtrg, GETSIGN(key));
|
||||
int4 len = ARRNELEM(qtrg);
|
||||
|
||||
if (len == 0)
|
||||
res = false;
|
||||
|
@ -286,20 +287,20 @@ gtrgm_consistent(PG_FUNCTION_ARGS)
|
|||
* nodes.
|
||||
*/
|
||||
if (GIST_LEAF(entry))
|
||||
{ /* all leafs contains orig trgm */
|
||||
{ /* all leafs contains orig trgm */
|
||||
res = trgm_contained_by(qtrg, key);
|
||||
}
|
||||
else if (ISALLTRUE(key))
|
||||
{ /* non-leaf contains signature */
|
||||
{ /* non-leaf contains signature */
|
||||
res = true;
|
||||
}
|
||||
else
|
||||
{ /* non-leaf contains signature */
|
||||
int32 k,
|
||||
tmp = 0,
|
||||
len = ARRNELEM(qtrg);
|
||||
trgm *ptr = GETARR(qtrg);
|
||||
BITVECP sign = GETSIGN(key);
|
||||
{ /* non-leaf contains signature */
|
||||
int32 k,
|
||||
tmp = 0,
|
||||
len = ARRNELEM(qtrg);
|
||||
trgm *ptr = GETARR(qtrg);
|
||||
BITVECP sign = GETSIGN(key);
|
||||
|
||||
res = true;
|
||||
for (k = 0; k < len; k++)
|
||||
|
@ -328,6 +329,7 @@ gtrgm_distance(PG_FUNCTION_ARGS)
|
|||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
text *query = PG_GETARG_TEXT_P(1);
|
||||
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
|
||||
|
||||
/* Oid subtype = PG_GETARG_OID(3); */
|
||||
TRGM *key = (TRGM *) DatumGetPointer(entry->key);
|
||||
TRGM *qtrg;
|
||||
|
@ -355,17 +357,17 @@ gtrgm_distance(PG_FUNCTION_ARGS)
|
|||
{
|
||||
case DistanceStrategyNumber:
|
||||
if (GIST_LEAF(entry))
|
||||
{ /* all leafs contains orig trgm */
|
||||
{ /* all leafs contains orig trgm */
|
||||
res = 1.0 - cnt_sml(key, qtrg);
|
||||
}
|
||||
else if (ISALLTRUE(key))
|
||||
{ /* all leafs contains orig trgm */
|
||||
{ /* all leafs contains orig trgm */
|
||||
res = 0.0;
|
||||
}
|
||||
else
|
||||
{ /* non-leaf contains signature */
|
||||
int4 count = cnt_sml_sign_common(qtrg, GETSIGN(key));
|
||||
int4 len = ARRNELEM(qtrg);
|
||||
{ /* non-leaf contains signature */
|
||||
int4 count = cnt_sml_sign_common(qtrg, GETSIGN(key));
|
||||
int4 len = ARRNELEM(qtrg);
|
||||
|
||||
res = (len == 0) ? -1.0 : 1.0 - ((float8) count) / ((float8) len);
|
||||
}
|
||||
|
|
|
@ -273,9 +273,9 @@ get_wildcard_part(const char *str, int lenstr,
|
|||
const char *beginword = str;
|
||||
const char *endword;
|
||||
char *s = buf;
|
||||
bool in_wildcard_meta = false;
|
||||
bool in_escape = false;
|
||||
int clen;
|
||||
bool in_wildcard_meta = false;
|
||||
bool in_escape = false;
|
||||
int clen;
|
||||
|
||||
/*
|
||||
* Find the first word character remembering whether last character was
|
||||
|
@ -410,14 +410,14 @@ generate_wildcard_trgm(const char *str, int slen)
|
|||
{
|
||||
TRGM *trg;
|
||||
char *buf,
|
||||
*buf2;
|
||||
*buf2;
|
||||
trgm *tptr;
|
||||
int len,
|
||||
charlen,
|
||||
bytelen;
|
||||
const char *eword;
|
||||
|
||||
trg = (TRGM *) palloc(TRGMHDRSIZE + sizeof(trgm) * (slen / 2 + 1) * 3);
|
||||
trg = (TRGM *) palloc(TRGMHDRSIZE + sizeof(trgm) * (slen / 2 + 1) *3);
|
||||
trg->flag = ARRKEY;
|
||||
SET_VARSIZE(trg, TRGMHDRSIZE);
|
||||
|
||||
|
@ -638,6 +638,7 @@ similarity_dist(PG_FUNCTION_ARGS)
|
|||
float4 res = DatumGetFloat4(DirectFunctionCall2(similarity,
|
||||
PG_GETARG_DATUM(0),
|
||||
PG_GETARG_DATUM(1)));
|
||||
|
||||
PG_RETURN_FLOAT4(1.0 - res);
|
||||
}
|
||||
|
||||
|
|
|
@ -212,7 +212,10 @@ check_cluster_versions(void)
|
|||
old_cluster.major_version = get_major_server_version(&old_cluster);
|
||||
new_cluster.major_version = get_major_server_version(&new_cluster);
|
||||
|
||||
/* We allow upgrades from/to the same major version for alpha/beta upgrades */
|
||||
/*
|
||||
* We allow upgrades from/to the same major version for alpha/beta
|
||||
* upgrades
|
||||
*/
|
||||
|
||||
if (GET_MAJOR_VERSION(old_cluster.major_version) < 803)
|
||||
pg_log(PG_FATAL, "This utility can only upgrade from PostgreSQL version 8.3 and later.\n");
|
||||
|
@ -516,7 +519,7 @@ check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster)
|
|||
}
|
||||
|
||||
if (script)
|
||||
fclose(script);
|
||||
fclose(script);
|
||||
|
||||
if (found)
|
||||
{
|
||||
|
|
|
@ -505,8 +505,7 @@ check_control_data(ControlData *oldctrl,
|
|||
"\nOld and new pg_controldata date/time storage types do not match.\n");
|
||||
|
||||
/*
|
||||
* This is a common 8.3 -> 8.4 upgrade problem, so we are more
|
||||
* verbose
|
||||
* This is a common 8.3 -> 8.4 upgrade problem, so we are more verbose
|
||||
*/
|
||||
pg_log(PG_FATAL,
|
||||
"You will need to rebuild the new server with configure\n"
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
static void check_data_dir(const char *pg_data);
|
||||
static void check_bin_dir(ClusterInfo *cluster);
|
||||
static void validate_exec(const char *dir, const char *cmdName);
|
||||
static void validate_exec(const char *dir, const char *cmdName);
|
||||
|
||||
|
||||
/*
|
||||
|
|
|
@ -377,4 +377,5 @@ win32_pghardlink(const char *src, const char *dst)
|
|||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -21,13 +21,13 @@
|
|||
void
|
||||
install_support_functions_in_new_db(const char *db_name)
|
||||
{
|
||||
PGconn *conn = connectToServer(&new_cluster, db_name);
|
||||
|
||||
PGconn *conn = connectToServer(&new_cluster, db_name);
|
||||
|
||||
/* suppress NOTICE of dropped objects */
|
||||
PQclear(executeQueryOrDie(conn,
|
||||
"SET client_min_messages = warning;"));
|
||||
PQclear(executeQueryOrDie(conn,
|
||||
"DROP SCHEMA IF EXISTS binary_upgrade CASCADE;"));
|
||||
"DROP SCHEMA IF EXISTS binary_upgrade CASCADE;"));
|
||||
PQclear(executeQueryOrDie(conn,
|
||||
"RESET client_min_messages;"));
|
||||
|
||||
|
@ -42,31 +42,31 @@ install_support_functions_in_new_db(const char *db_name)
|
|||
"LANGUAGE C STRICT;"));
|
||||
PQclear(executeQueryOrDie(conn,
|
||||
"CREATE OR REPLACE FUNCTION "
|
||||
"binary_upgrade.set_next_array_pg_type_oid(OID) "
|
||||
"binary_upgrade.set_next_array_pg_type_oid(OID) "
|
||||
"RETURNS VOID "
|
||||
"AS '$libdir/pg_upgrade_support' "
|
||||
"LANGUAGE C STRICT;"));
|
||||
PQclear(executeQueryOrDie(conn,
|
||||
"CREATE OR REPLACE FUNCTION "
|
||||
"binary_upgrade.set_next_toast_pg_type_oid(OID) "
|
||||
"binary_upgrade.set_next_toast_pg_type_oid(OID) "
|
||||
"RETURNS VOID "
|
||||
"AS '$libdir/pg_upgrade_support' "
|
||||
"LANGUAGE C STRICT;"));
|
||||
PQclear(executeQueryOrDie(conn,
|
||||
"CREATE OR REPLACE FUNCTION "
|
||||
"binary_upgrade.set_next_heap_pg_class_oid(OID) "
|
||||
"binary_upgrade.set_next_heap_pg_class_oid(OID) "
|
||||
"RETURNS VOID "
|
||||
"AS '$libdir/pg_upgrade_support' "
|
||||
"LANGUAGE C STRICT;"));
|
||||
PQclear(executeQueryOrDie(conn,
|
||||
"CREATE OR REPLACE FUNCTION "
|
||||
"binary_upgrade.set_next_index_pg_class_oid(OID) "
|
||||
"binary_upgrade.set_next_index_pg_class_oid(OID) "
|
||||
"RETURNS VOID "
|
||||
"AS '$libdir/pg_upgrade_support' "
|
||||
"LANGUAGE C STRICT;"));
|
||||
PQclear(executeQueryOrDie(conn,
|
||||
"CREATE OR REPLACE FUNCTION "
|
||||
"binary_upgrade.set_next_toast_pg_class_oid(OID) "
|
||||
"binary_upgrade.set_next_toast_pg_class_oid(OID) "
|
||||
"RETURNS VOID "
|
||||
"AS '$libdir/pg_upgrade_support' "
|
||||
"LANGUAGE C STRICT;"));
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
|
||||
|
||||
static void create_rel_filename_map(const char *old_data, const char *new_data,
|
||||
const DbInfo *old_db, const DbInfo *new_db,
|
||||
const RelInfo *old_rel, const RelInfo *new_rel,
|
||||
FileNameMap *map);
|
||||
const DbInfo *old_db, const DbInfo *new_db,
|
||||
const RelInfo *old_rel, const RelInfo *new_rel,
|
||||
FileNameMap *map);
|
||||
static void get_db_infos(ClusterInfo *cluster);
|
||||
static void get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo);
|
||||
static void free_rel_infos(RelInfoArr *rel_arr);
|
||||
|
@ -40,7 +40,7 @@ gen_db_file_maps(DbInfo *old_db, DbInfo *new_db,
|
|||
|
||||
if (old_db->rel_arr.nrels != new_db->rel_arr.nrels)
|
||||
pg_log(PG_FATAL, "old and new databases \"%s\" have a different number of relations\n",
|
||||
old_db->db_name);
|
||||
old_db->db_name);
|
||||
|
||||
maps = (FileNameMap *) pg_malloc(sizeof(FileNameMap) *
|
||||
old_db->rel_arr.nrels);
|
||||
|
@ -52,24 +52,24 @@ gen_db_file_maps(DbInfo *old_db, DbInfo *new_db,
|
|||
|
||||
if (old_rel->reloid != new_rel->reloid)
|
||||
pg_log(PG_FATAL, "Mismatch of relation id: database \"%s\", old relid %d, new relid %d\n",
|
||||
old_db->db_name, old_rel->reloid, new_rel->reloid);
|
||||
old_db->db_name, old_rel->reloid, new_rel->reloid);
|
||||
|
||||
/*
|
||||
* In pre-8.4, TOAST table names change during CLUSTER; in >= 8.4
|
||||
* TOAST relation names always use heap table oids, hence we
|
||||
* cannot check relation names when upgrading from pre-8.4.
|
||||
* In pre-8.4, TOAST table names change during CLUSTER; in >= 8.4
|
||||
* TOAST relation names always use heap table oids, hence we cannot
|
||||
* check relation names when upgrading from pre-8.4.
|
||||
*/
|
||||
if (strcmp(old_rel->nspname, new_rel->nspname) != 0 ||
|
||||
((GET_MAJOR_VERSION(old_cluster.major_version) >= 804 ||
|
||||
strcmp(old_rel->nspname, "pg_toast") != 0) &&
|
||||
strcmp(old_rel->relname, new_rel->relname) != 0))
|
||||
pg_log(PG_FATAL, "Mismatch of relation names: database \"%s\", "
|
||||
"old rel %s.%s, new rel %s.%s\n",
|
||||
old_db->db_name, old_rel->nspname, old_rel->relname,
|
||||
new_rel->nspname, new_rel->relname);
|
||||
"old rel %s.%s, new rel %s.%s\n",
|
||||
old_db->db_name, old_rel->nspname, old_rel->relname,
|
||||
new_rel->nspname, new_rel->relname);
|
||||
|
||||
create_rel_filename_map(old_pgdata, new_pgdata, old_db, new_db,
|
||||
old_rel, new_rel, maps + num_maps);
|
||||
old_rel, new_rel, maps + num_maps);
|
||||
num_maps++;
|
||||
}
|
||||
|
||||
|
@ -85,9 +85,9 @@ gen_db_file_maps(DbInfo *old_db, DbInfo *new_db,
|
|||
*/
|
||||
static void
|
||||
create_rel_filename_map(const char *old_data, const char *new_data,
|
||||
const DbInfo *old_db, const DbInfo *new_db,
|
||||
const RelInfo *old_rel, const RelInfo *new_rel,
|
||||
FileNameMap *map)
|
||||
const DbInfo *old_db, const DbInfo *new_db,
|
||||
const RelInfo *old_rel, const RelInfo *new_rel,
|
||||
FileNameMap *map)
|
||||
{
|
||||
if (strlen(old_rel->tablespace) == 0)
|
||||
{
|
||||
|
@ -110,8 +110,8 @@ create_rel_filename_map(const char *old_data, const char *new_data,
|
|||
}
|
||||
|
||||
/*
|
||||
* old_relfilenode might differ from pg_class.oid (and hence
|
||||
* new_relfilenode) because of CLUSTER, REINDEX, or VACUUM FULL.
|
||||
* old_relfilenode might differ from pg_class.oid (and hence
|
||||
* new_relfilenode) because of CLUSTER, REINDEX, or VACUUM FULL.
|
||||
*/
|
||||
map->old_relfilenode = old_rel->relfilenode;
|
||||
|
||||
|
@ -185,7 +185,9 @@ get_db_infos(ClusterInfo *cluster)
|
|||
int ntups;
|
||||
int tupnum;
|
||||
DbInfo *dbinfos;
|
||||
int i_datname, i_oid, i_spclocation;
|
||||
int i_datname,
|
||||
i_oid,
|
||||
i_spclocation;
|
||||
|
||||
res = executeQueryOrDie(conn,
|
||||
"SELECT d.oid, d.datname, t.spclocation "
|
||||
|
@ -241,15 +243,19 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo)
|
|||
int num_rels = 0;
|
||||
char *nspname = NULL;
|
||||
char *relname = NULL;
|
||||
int i_spclocation, i_nspname, i_relname, i_oid, i_relfilenode;
|
||||
int i_spclocation,
|
||||
i_nspname,
|
||||
i_relname,
|
||||
i_oid,
|
||||
i_relfilenode;
|
||||
char query[QUERY_ALLOC];
|
||||
|
||||
/*
|
||||
* pg_largeobject contains user data that does not appear in pg_dumpall
|
||||
* --schema-only output, so we have to copy that system table heap and
|
||||
* index. We could grab the pg_largeobject oids from template1, but
|
||||
* it is easy to treat it as a normal table.
|
||||
* Order by oid so we can join old/new structures efficiently.
|
||||
* index. We could grab the pg_largeobject oids from template1, but it is
|
||||
* easy to treat it as a normal table. Order by oid so we can join old/new
|
||||
* structures efficiently.
|
||||
*/
|
||||
|
||||
snprintf(query, sizeof(query),
|
||||
|
@ -263,7 +269,7 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo)
|
|||
" ((n.nspname NOT IN ('pg_catalog', 'information_schema', 'binary_upgrade') AND "
|
||||
" c.oid >= %u) "
|
||||
" OR (n.nspname = 'pg_catalog' AND "
|
||||
" relname IN ('pg_largeobject', 'pg_largeobject_loid_pn_index'%s) )) "
|
||||
" relname IN ('pg_largeobject', 'pg_largeobject_loid_pn_index'%s) )) "
|
||||
/* we preserve pg_class.oid so we sort by it to match old/new */
|
||||
"ORDER BY 1;",
|
||||
/* see the comment at the top of old_8_3_create_sequence_script() */
|
||||
|
@ -273,7 +279,7 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo)
|
|||
FirstNormalObjectId,
|
||||
/* does pg_largeobject_metadata need to be migrated? */
|
||||
(GET_MAJOR_VERSION(old_cluster.major_version) <= 804) ?
|
||||
"" : ", 'pg_largeobject_metadata', 'pg_largeobject_metadata_oid_index'");
|
||||
"" : ", 'pg_largeobject_metadata', 'pg_largeobject_metadata_oid_index'");
|
||||
|
||||
res = executeQueryOrDie(conn, query);
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
* FYI, while pg_class.oid and pg_class.relfilenode are intially the same
|
||||
* in a cluster, but they can diverge due to CLUSTER, REINDEX, or VACUUM
|
||||
* FULL. The new cluster will have matching pg_class.oid and
|
||||
* pg_class.relfilenode values and be based on the old oid value. This can
|
||||
* pg_class.relfilenode values and be based on the old oid value. This can
|
||||
* cause the old and new pg_class.relfilenode values to differ. In summary,
|
||||
* old and new pg_class.oid and new pg_class.relfilenode will have the
|
||||
* same value, and old pg_class.relfilenode might differ.
|
||||
|
@ -34,7 +34,7 @@
|
|||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
#include "pg_upgrade.h"
|
||||
|
||||
#ifdef HAVE_LANGINFO_H
|
||||
|
@ -53,7 +53,8 @@ static void cleanup(void);
|
|||
/* This is the database used by pg_dumpall to restore global tables */
|
||||
#define GLOBAL_DUMP_DB "postgres"
|
||||
|
||||
ClusterInfo old_cluster, new_cluster;
|
||||
ClusterInfo old_cluster,
|
||||
new_cluster;
|
||||
OSInfo os_info;
|
||||
|
||||
int
|
||||
|
@ -192,7 +193,7 @@ prepare_new_cluster(void)
|
|||
exec_prog(true,
|
||||
SYSTEMQUOTE "\"%s/vacuumdb\" --port %d --username \"%s\" "
|
||||
"--all --analyze >> %s 2>&1" SYSTEMQUOTE,
|
||||
new_cluster.bindir, new_cluster.port, os_info.user, log_opts.filename);
|
||||
new_cluster.bindir, new_cluster.port, os_info.user, log_opts.filename);
|
||||
check_ok();
|
||||
|
||||
/*
|
||||
|
@ -205,7 +206,7 @@ prepare_new_cluster(void)
|
|||
exec_prog(true,
|
||||
SYSTEMQUOTE "\"%s/vacuumdb\" --port %d --username \"%s\" "
|
||||
"--all --freeze >> %s 2>&1" SYSTEMQUOTE,
|
||||
new_cluster.bindir, new_cluster.port, os_info.user, log_opts.filename);
|
||||
new_cluster.bindir, new_cluster.port, os_info.user, log_opts.filename);
|
||||
check_ok();
|
||||
|
||||
get_pg_database_relfilenode(&new_cluster);
|
||||
|
@ -229,16 +230,16 @@ prepare_new_databases(void)
|
|||
prep_status("Creating databases in the new cluster");
|
||||
|
||||
/*
|
||||
* Install support functions in the global-restore database
|
||||
* to preserve pg_authid.oid.
|
||||
* Install support functions in the global-restore database to preserve
|
||||
* pg_authid.oid.
|
||||
*/
|
||||
install_support_functions_in_new_db(GLOBAL_DUMP_DB);
|
||||
|
||||
/*
|
||||
* We have to create the databases first so we can install support
|
||||
* functions in all the other databases. Ideally we could create
|
||||
* the support functions in template1 but pg_dumpall creates database
|
||||
* using the template0 template.
|
||||
* functions in all the other databases. Ideally we could create the
|
||||
* support functions in template1 but pg_dumpall creates database using
|
||||
* the template0 template.
|
||||
*/
|
||||
exec_prog(true,
|
||||
SYSTEMQUOTE "\"%s/psql\" --set ON_ERROR_STOP=on "
|
||||
|
|
|
@ -85,6 +85,7 @@ typedef struct
|
|||
{
|
||||
char old_dir[MAXPGPATH];
|
||||
char new_dir[MAXPGPATH];
|
||||
|
||||
/*
|
||||
* old/new relfilenodes might differ for pg_largeobject(_metadata) indexes
|
||||
* due to VACUUM FULL or REINDEX. Other relfilenodes are preserved.
|
||||
|
@ -92,7 +93,7 @@ typedef struct
|
|||
Oid old_relfilenode;
|
||||
Oid new_relfilenode;
|
||||
/* the rest are used only for logging and error reporting */
|
||||
char nspname[NAMEDATALEN]; /* namespaces */
|
||||
char nspname[NAMEDATALEN]; /* namespaces */
|
||||
char relname[NAMEDATALEN];
|
||||
} FileNameMap;
|
||||
|
||||
|
@ -180,7 +181,7 @@ typedef struct
|
|||
char *bindir; /* pathname for cluster's executable directory */
|
||||
unsigned short port; /* port number where postmaster is waiting */
|
||||
uint32 major_version; /* PG_VERSION of cluster */
|
||||
char major_version_str[64]; /* string PG_VERSION of cluster */
|
||||
char major_version_str[64]; /* string PG_VERSION of cluster */
|
||||
Oid pg_database_oid; /* OID of pg_database relation */
|
||||
char *libpath; /* pathname for cluster's pkglibdir */
|
||||
char *tablespace_suffix; /* directory specification */
|
||||
|
@ -232,9 +233,10 @@ typedef struct
|
|||
/*
|
||||
* Global variables
|
||||
*/
|
||||
extern LogOpts log_opts;
|
||||
extern LogOpts log_opts;
|
||||
extern UserOpts user_opts;
|
||||
extern ClusterInfo old_cluster, new_cluster;
|
||||
extern ClusterInfo old_cluster,
|
||||
new_cluster;
|
||||
extern OSInfo os_info;
|
||||
extern char scandir_file_pattern[];
|
||||
|
||||
|
@ -246,8 +248,8 @@ void check_old_cluster(bool live_check,
|
|||
char **sequence_script_file_name);
|
||||
void check_new_cluster(void);
|
||||
void report_clusters_compatible(void);
|
||||
void issue_warnings(char *sequence_script_file_name);
|
||||
void output_completion_banner(char *deletion_script_file_name);
|
||||
void issue_warnings(char *sequence_script_file_name);
|
||||
void output_completion_banner(char *deletion_script_file_name);
|
||||
void check_cluster_versions(void);
|
||||
void check_cluster_compatibility(bool live_check);
|
||||
void create_script_for_old_cluster_deletion(char **deletion_script_file_name);
|
||||
|
@ -309,11 +311,11 @@ typedef void *pageCnvCtx;
|
|||
|
||||
int dir_matching_filenames(const struct dirent * scan_ent);
|
||||
int pg_scandir(const char *dirname, struct dirent *** namelist,
|
||||
int (*selector) (const struct dirent *));
|
||||
int (*selector) (const struct dirent *));
|
||||
const char *copyAndUpdateFile(pageCnvCtx *pageConverter, const char *src,
|
||||
const char *dst, bool force);
|
||||
const char *linkAndUpdateFile(pageCnvCtx *pageConverter, const char *src,
|
||||
const char *dst);
|
||||
const char *dst);
|
||||
|
||||
void check_hard_link(void);
|
||||
|
||||
|
@ -329,10 +331,10 @@ void check_loadable_libraries(void);
|
|||
FileNameMap *gen_db_file_maps(DbInfo *old_db,
|
||||
DbInfo *new_db, int *nmaps, const char *old_pgdata,
|
||||
const char *new_pgdata);
|
||||
void get_db_and_rel_infos(ClusterInfo *cluster);
|
||||
void get_db_and_rel_infos(ClusterInfo *cluster);
|
||||
void free_db_and_rel_infos(DbInfoArr *db_arr);
|
||||
void print_maps(FileNameMap *maps, int n,
|
||||
const char *db_name);
|
||||
void print_maps(FileNameMap *maps, int n,
|
||||
const char *db_name);
|
||||
|
||||
/* option.c */
|
||||
|
||||
|
@ -352,12 +354,12 @@ void init_tablespaces(void);
|
|||
|
||||
/* server.c */
|
||||
|
||||
PGconn *connectToServer(ClusterInfo *cluster, const char *db_name);
|
||||
PGresult *executeQueryOrDie(PGconn *conn, const char *fmt,...);
|
||||
PGconn *connectToServer(ClusterInfo *cluster, const char *db_name);
|
||||
PGresult *executeQueryOrDie(PGconn *conn, const char *fmt,...);
|
||||
|
||||
void start_postmaster(ClusterInfo *cluster, bool quiet);
|
||||
void stop_postmaster(bool fast, bool quiet);
|
||||
uint32 get_major_server_version(ClusterInfo *cluster);
|
||||
uint32 get_major_server_version(ClusterInfo *cluster);
|
||||
void check_for_libpq_envvars(void);
|
||||
|
||||
|
||||
|
@ -380,14 +382,14 @@ unsigned int str2uint(const char *str);
|
|||
/* version.c */
|
||||
|
||||
void new_9_0_populate_pg_largeobject_metadata(ClusterInfo *cluster,
|
||||
bool check_mode);
|
||||
bool check_mode);
|
||||
|
||||
/* version_old_8_3.c */
|
||||
|
||||
void old_8_3_check_for_name_data_type_usage(ClusterInfo *cluster);
|
||||
void old_8_3_check_for_tsquery_usage(ClusterInfo *cluster);
|
||||
void old_8_3_rebuild_tsvector_tables(ClusterInfo *cluster, bool check_mode);
|
||||
void old_8_3_invalidate_hash_gin_indexes(ClusterInfo *cluster, bool check_mode);
|
||||
void old_8_3_rebuild_tsvector_tables(ClusterInfo *cluster, bool check_mode);
|
||||
void old_8_3_invalidate_hash_gin_indexes(ClusterInfo *cluster, bool check_mode);
|
||||
void old_8_3_invalidate_bpchar_pattern_ops_indexes(ClusterInfo *cluster,
|
||||
bool check_mode);
|
||||
bool check_mode);
|
||||
char *old_8_3_create_sequence_script(ClusterInfo *cluster);
|
||||
|
|
|
@ -30,7 +30,7 @@ char scandir_file_pattern[MAXPGPATH];
|
|||
*/
|
||||
const char *
|
||||
transfer_all_new_dbs(DbInfoArr *old_db_arr,
|
||||
DbInfoArr *new_db_arr, char *old_pgdata, char *new_pgdata)
|
||||
DbInfoArr *new_db_arr, char *old_pgdata, char *new_pgdata)
|
||||
{
|
||||
int dbnum;
|
||||
const char *msg = NULL;
|
||||
|
@ -39,7 +39,7 @@ transfer_all_new_dbs(DbInfoArr *old_db_arr,
|
|||
|
||||
if (old_db_arr->ndbs != new_db_arr->ndbs)
|
||||
pg_log(PG_FATAL, "old and new clusters have a different number of databases\n");
|
||||
|
||||
|
||||
for (dbnum = 0; dbnum < old_db_arr->ndbs; dbnum++)
|
||||
{
|
||||
DbInfo *old_db = &old_db_arr->dbs[dbnum];
|
||||
|
@ -50,8 +50,8 @@ transfer_all_new_dbs(DbInfoArr *old_db_arr,
|
|||
|
||||
if (strcmp(old_db->db_name, new_db->db_name) != 0)
|
||||
pg_log(PG_FATAL, "old and new databases have different names: old \"%s\", new \"%s\"\n",
|
||||
old_db->db_name, new_db->db_name);
|
||||
|
||||
old_db->db_name, new_db->db_name);
|
||||
|
||||
n_maps = 0;
|
||||
mappings = gen_db_file_maps(old_db, new_db, &n_maps, old_pgdata,
|
||||
new_pgdata);
|
||||
|
@ -169,7 +169,7 @@ transfer_single_new_db(pageCnvCtx *pageConverter,
|
|||
for (fileno = 0; fileno < numFiles; fileno++)
|
||||
{
|
||||
if (strncmp(namelist[fileno]->d_name, scandir_file_pattern,
|
||||
strlen(scandir_file_pattern)) == 0)
|
||||
strlen(scandir_file_pattern)) == 0)
|
||||
{
|
||||
snprintf(old_file, sizeof(old_file), "%s/%s", maps[mapnum].old_dir,
|
||||
namelist[fileno]->d_name);
|
||||
|
@ -178,7 +178,7 @@ transfer_single_new_db(pageCnvCtx *pageConverter,
|
|||
|
||||
unlink(new_file);
|
||||
transfer_relfile(pageConverter, old_file, new_file,
|
||||
maps[mapnum].nspname, maps[mapnum].relname);
|
||||
maps[mapnum].nspname, maps[mapnum].relname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -196,7 +196,7 @@ transfer_single_new_db(pageCnvCtx *pageConverter,
|
|||
for (fileno = 0; fileno < numFiles; fileno++)
|
||||
{
|
||||
if (strncmp(namelist[fileno]->d_name, scandir_file_pattern,
|
||||
strlen(scandir_file_pattern)) == 0)
|
||||
strlen(scandir_file_pattern)) == 0)
|
||||
{
|
||||
snprintf(old_file, sizeof(old_file), "%s/%s", maps[mapnum].old_dir,
|
||||
namelist[fileno]->d_name);
|
||||
|
@ -205,7 +205,7 @@ transfer_single_new_db(pageCnvCtx *pageConverter,
|
|||
|
||||
unlink(new_file);
|
||||
transfer_relfile(pageConverter, old_file, new_file,
|
||||
maps[mapnum].nspname, maps[mapnum].relname);
|
||||
maps[mapnum].nspname, maps[mapnum].relname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -227,7 +227,7 @@ transfer_single_new_db(pageCnvCtx *pageConverter,
|
|||
*/
|
||||
static void
|
||||
transfer_relfile(pageCnvCtx *pageConverter, const char *old_file,
|
||||
const char *new_file, const char *nspname, const char *relname)
|
||||
const char *new_file, const char *nspname, const char *relname)
|
||||
{
|
||||
const char *msg;
|
||||
|
||||
|
@ -249,7 +249,7 @@ transfer_relfile(pageCnvCtx *pageConverter, const char *old_file,
|
|||
|
||||
if ((msg = linkAndUpdateFile(pageConverter, old_file, new_file)) != NULL)
|
||||
pg_log(PG_FATAL,
|
||||
"error while creating link from %s.%s (%s to %s): %s\n",
|
||||
"error while creating link from %s.%s (%s to %s): %s\n",
|
||||
nspname, relname, old_file, new_file, msg);
|
||||
}
|
||||
return;
|
||||
|
|
|
@ -194,12 +194,12 @@ start_postmaster(ClusterInfo *cluster, bool quiet)
|
|||
* because it is being used by another process." so we have to send all
|
||||
* other output to 'nul'.
|
||||
*
|
||||
* Using autovacuum=off disables cleanup vacuum and analyze, but
|
||||
* freeze vacuums can still happen, so we set
|
||||
* autovacuum_freeze_max_age to its maximum. We assume all datfrozenxid
|
||||
* and relfrozen values are less than a gap of 2000000000 from the current
|
||||
* xid counter, so autovacuum will not touch them.
|
||||
*/
|
||||
* Using autovacuum=off disables cleanup vacuum and analyze, but freeze
|
||||
* vacuums can still happen, so we set autovacuum_freeze_max_age to its
|
||||
* maximum. We assume all datfrozenxid and relfrozen values are less than
|
||||
* a gap of 2000000000 from the current xid counter, so autovacuum will
|
||||
* not touch them.
|
||||
*/
|
||||
snprintf(cmd, sizeof(cmd),
|
||||
SYSTEMQUOTE "\"%s/pg_ctl\" -l \"%s\" -D \"%s\" "
|
||||
"-o \"-p %d -c autovacuum=off "
|
||||
|
@ -251,7 +251,7 @@ stop_postmaster(bool fast, bool quiet)
|
|||
"\"%s\" 2>&1" SYSTEMQUOTE,
|
||||
bindir,
|
||||
#ifndef WIN32
|
||||
log_opts.filename, datadir, fast ? "-m fast" : "", log_opts.filename);
|
||||
log_opts.filename, datadir, fast ? "-m fast" : "", log_opts.filename);
|
||||
#else
|
||||
DEVNULL, datadir, fast ? "-m fast" : "", DEVNULL);
|
||||
#endif
|
||||
|
|
|
@ -78,8 +78,8 @@ set_tablespace_directory_suffix(ClusterInfo *cluster)
|
|||
{
|
||||
/* This cluster has a version-specific subdirectory */
|
||||
cluster->tablespace_suffix = pg_malloc(4 +
|
||||
strlen(cluster->major_version_str) +
|
||||
10 /* OIDCHARS */ + 1);
|
||||
strlen(cluster->major_version_str) +
|
||||
10 /* OIDCHARS */ + 1);
|
||||
|
||||
/* The leading slash is needed to start a new directory. */
|
||||
sprintf(cluster->tablespace_suffix, "/PG_%s_%d", cluster->major_version_str,
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include <signal.h>
|
||||
|
||||
|
||||
LogOpts log_opts;
|
||||
LogOpts log_opts;
|
||||
|
||||
/*
|
||||
* report_status()
|
||||
|
|
|
@ -288,7 +288,7 @@ old_8_3_rebuild_tsvector_tables(ClusterInfo *cluster, bool check_mode)
|
|||
|
||||
/* Rebuild all tsvector collumns with one ALTER TABLE command */
|
||||
if (strcmp(PQgetvalue(res, rowno, i_nspname), nspname) != 0 ||
|
||||
strcmp(PQgetvalue(res, rowno, i_relname), relname) != 0)
|
||||
strcmp(PQgetvalue(res, rowno, i_relname), relname) != 0)
|
||||
{
|
||||
if (strlen(nspname) != 0 || strlen(relname) != 0)
|
||||
fprintf(script, ";\n\n");
|
||||
|
|
|
@ -178,9 +178,9 @@ create_empty_extension(PG_FUNCTION_ARGS)
|
|||
&textDatums, NULL, &ndatums);
|
||||
for (i = 0; i < ndatums; i++)
|
||||
{
|
||||
text *txtname = DatumGetTextPP(textDatums[i]);
|
||||
char *extName = text_to_cstring(txtname);
|
||||
Oid extOid = get_extension_oid(extName, false);
|
||||
text *txtname = DatumGetTextPP(textDatums[i]);
|
||||
char *extName = text_to_cstring(txtname);
|
||||
Oid extOid = get_extension_oid(extName, false);
|
||||
|
||||
requiredExtensions = lappend_oid(requiredExtensions, extOid);
|
||||
}
|
||||
|
@ -188,7 +188,7 @@ create_empty_extension(PG_FUNCTION_ARGS)
|
|||
|
||||
InsertExtensionTuple(text_to_cstring(extName),
|
||||
GetUserId(),
|
||||
get_namespace_oid(text_to_cstring(schemaName), false),
|
||||
get_namespace_oid(text_to_cstring(schemaName), false),
|
||||
relocatable,
|
||||
text_to_cstring(extVersion),
|
||||
extConfig,
|
||||
|
|
|
@ -69,7 +69,7 @@
|
|||
typedef struct win32_pthread *pthread_t;
|
||||
typedef int pthread_attr_t;
|
||||
|
||||
static int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
|
||||
static int pthread_create(pthread_t *thread, pthread_attr_t * attr, void *(*start_routine) (void *), void *arg);
|
||||
static int pthread_join(pthread_t th, void **thread_return);
|
||||
#elif defined(ENABLE_THREAD_SAFETY)
|
||||
/* Use platform-dependent pthread capability */
|
||||
|
@ -87,7 +87,7 @@ static int pthread_join(pthread_t th, void **thread_return);
|
|||
typedef struct fork_pthread *pthread_t;
|
||||
typedef int pthread_attr_t;
|
||||
|
||||
static int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
|
||||
static int pthread_create(pthread_t *thread, pthread_attr_t * attr, void *(*start_routine) (void *), void *arg);
|
||||
static int pthread_join(pthread_t th, void **thread_return);
|
||||
#endif
|
||||
|
||||
|
@ -817,7 +817,7 @@ top:
|
|||
|
||||
INSTR_TIME_SET_CURRENT(now);
|
||||
INSTR_TIME_ACCUM_DIFF(thread->exec_elapsed[cnum],
|
||||
now, st->stmt_begin);
|
||||
now, st->stmt_begin);
|
||||
thread->exec_count[cnum]++;
|
||||
}
|
||||
|
||||
|
@ -850,8 +850,8 @@ top:
|
|||
if (commands[st->state]->type == SQL_COMMAND)
|
||||
{
|
||||
/*
|
||||
* Read and discard the query result; note this is not included
|
||||
* in the statement latency numbers.
|
||||
* Read and discard the query result; note this is not included in
|
||||
* the statement latency numbers.
|
||||
*/
|
||||
res = PQgetResult(st->con);
|
||||
switch (PQresultStatus(res))
|
||||
|
@ -1716,16 +1716,16 @@ printResults(int ttype, int normal_xacts, int nclients,
|
|||
|
||||
for (i = 0; i < num_files; i++)
|
||||
{
|
||||
Command **commands;
|
||||
Command **commands;
|
||||
|
||||
if (num_files > 1)
|
||||
printf("statement latencies in milliseconds, file %d:\n", i+1);
|
||||
printf("statement latencies in milliseconds, file %d:\n", i + 1);
|
||||
else
|
||||
printf("statement latencies in milliseconds:\n");
|
||||
|
||||
for (commands = sql_files[i]; *commands != NULL; commands++)
|
||||
{
|
||||
Command *command = *commands;
|
||||
Command *command = *commands;
|
||||
int cnum = command->command_num;
|
||||
double total_time;
|
||||
instr_time total_exec_elapsed;
|
||||
|
@ -1737,7 +1737,7 @@ printResults(int ttype, int normal_xacts, int nclients,
|
|||
total_exec_count = 0;
|
||||
for (t = 0; t < nthreads; t++)
|
||||
{
|
||||
TState *thread = &threads[t];
|
||||
TState *thread = &threads[t];
|
||||
|
||||
INSTR_TIME_ADD(total_exec_elapsed,
|
||||
thread->exec_elapsed[cnum]);
|
||||
|
@ -2014,9 +2014,9 @@ main(int argc, char **argv)
|
|||
* is_latencies only works with multiple threads in thread-based
|
||||
* implementations, not fork-based ones, because it supposes that the
|
||||
* parent can see changes made to the per-thread execution stats by child
|
||||
* threads. It seems useful enough to accept despite this limitation,
|
||||
* but perhaps we should FIXME someday (by passing the stats data back
|
||||
* up through the parent-to-child pipes).
|
||||
* threads. It seems useful enough to accept despite this limitation, but
|
||||
* perhaps we should FIXME someday (by passing the stats data back up
|
||||
* through the parent-to-child pipes).
|
||||
*/
|
||||
#ifndef ENABLE_THREAD_SAFETY
|
||||
if (is_latencies && nthreads > 1)
|
||||
|
@ -2161,7 +2161,7 @@ main(int argc, char **argv)
|
|||
threads = (TState *) xmalloc(sizeof(TState) * nthreads);
|
||||
for (i = 0; i < nthreads; i++)
|
||||
{
|
||||
TState *thread = &threads[i];
|
||||
TState *thread = &threads[i];
|
||||
|
||||
thread->tid = i;
|
||||
thread->state = &state[nclients / nthreads * i];
|
||||
|
@ -2170,7 +2170,7 @@ main(int argc, char **argv)
|
|||
if (is_latencies)
|
||||
{
|
||||
/* Reserve memory for the thread to store per-command latencies */
|
||||
int t;
|
||||
int t;
|
||||
|
||||
thread->exec_elapsed = (instr_time *)
|
||||
xmalloc(sizeof(instr_time) * num_commands);
|
||||
|
@ -2200,7 +2200,7 @@ main(int argc, char **argv)
|
|||
/* start threads */
|
||||
for (i = 0; i < nthreads; i++)
|
||||
{
|
||||
TState *thread = &threads[i];
|
||||
TState *thread = &threads[i];
|
||||
|
||||
INSTR_TIME_SET_CURRENT(thread->start_time);
|
||||
|
||||
|
@ -2472,7 +2472,7 @@ typedef struct fork_pthread
|
|||
|
||||
static int
|
||||
pthread_create(pthread_t *thread,
|
||||
pthread_attr_t *attr,
|
||||
pthread_attr_t * attr,
|
||||
void *(*start_routine) (void *),
|
||||
void *arg)
|
||||
{
|
||||
|
@ -2586,7 +2586,7 @@ typedef struct win32_pthread
|
|||
void *(*routine) (void *);
|
||||
void *arg;
|
||||
void *result;
|
||||
} win32_pthread;
|
||||
} win32_pthread;
|
||||
|
||||
static unsigned __stdcall
|
||||
win32_pthread_run(void *arg)
|
||||
|
@ -2600,7 +2600,7 @@ win32_pthread_run(void *arg)
|
|||
|
||||
static int
|
||||
pthread_create(pthread_t *thread,
|
||||
pthread_attr_t *attr,
|
||||
pthread_attr_t * attr,
|
||||
void *(*start_routine) (void *),
|
||||
void *arg)
|
||||
{
|
||||
|
|
|
@ -356,7 +356,7 @@ gseg_picksplit(GistEntryVector *entryvec,
|
|||
{
|
||||
seg = (SEG *) DatumGetPointer(entryvec->vector[i].key);
|
||||
/* center calculation is done this way to avoid possible overflow */
|
||||
sort_items[i - 1].center = seg->lower*0.5f + seg->upper*0.5f;
|
||||
sort_items[i - 1].center = seg->lower * 0.5f + seg->upper * 0.5f;
|
||||
sort_items[i - 1].index = i;
|
||||
sort_items[i - 1].data = seg;
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ fixup_whole_row_references(Oid relOid, Bitmapset *columns)
|
|||
result = bms_copy(columns);
|
||||
result = bms_del_member(result, index);
|
||||
|
||||
for (attno=1; attno <= natts; attno++)
|
||||
for (attno = 1; attno <= natts; attno++)
|
||||
{
|
||||
tuple = SearchSysCache2(ATTNUM,
|
||||
ObjectIdGetDatum(relOid),
|
||||
|
@ -108,6 +108,7 @@ fixup_inherited_columns(Oid parentId, Oid childId, Bitmapset *columns)
|
|||
while ((index = bms_first_member(tmpset)) > 0)
|
||||
{
|
||||
attno = index + FirstLowInvalidHeapAttributeNumber;
|
||||
|
||||
/*
|
||||
* whole-row-reference shall be fixed-up later
|
||||
*/
|
||||
|
@ -158,14 +159,13 @@ check_relation_privileges(Oid relOid,
|
|||
bool result = true;
|
||||
|
||||
/*
|
||||
* Hardwired Policies:
|
||||
* SE-PostgreSQL enforces
|
||||
* - clients cannot modify system catalogs using DMLs
|
||||
* - clients cannot reference/modify toast relations using DMLs
|
||||
* Hardwired Policies: SE-PostgreSQL enforces - clients cannot modify
|
||||
* system catalogs using DMLs - clients cannot reference/modify toast
|
||||
* relations using DMLs
|
||||
*/
|
||||
if (sepgsql_getenforce() > 0)
|
||||
{
|
||||
Oid relnamespace = get_rel_namespace(relOid);
|
||||
Oid relnamespace = get_rel_namespace(relOid);
|
||||
|
||||
if (IsSystemNamespace(relnamespace) &&
|
||||
(required & (SEPG_DB_TABLE__UPDATE |
|
||||
|
@ -242,7 +242,7 @@ check_relation_privileges(Oid relOid,
|
|||
{
|
||||
AttrNumber attnum;
|
||||
uint32 column_perms = 0;
|
||||
ObjectAddress object;
|
||||
ObjectAddress object;
|
||||
|
||||
if (bms_is_member(index, selected))
|
||||
column_perms |= SEPG_DB_COLUMN__SELECT;
|
||||
|
@ -290,12 +290,12 @@ sepgsql_dml_privileges(List *rangeTabls, bool abort)
|
|||
{
|
||||
ListCell *lr;
|
||||
|
||||
foreach (lr, rangeTabls)
|
||||
foreach(lr, rangeTabls)
|
||||
{
|
||||
RangeTblEntry *rte = lfirst(lr);
|
||||
uint32 required = 0;
|
||||
List *tableIds;
|
||||
ListCell *li;
|
||||
RangeTblEntry *rte = lfirst(lr);
|
||||
uint32 required = 0;
|
||||
List *tableIds;
|
||||
ListCell *li;
|
||||
|
||||
/*
|
||||
* Only regular relations shall be checked
|
||||
|
@ -328,25 +328,24 @@ sepgsql_dml_privileges(List *rangeTabls, bool abort)
|
|||
|
||||
/*
|
||||
* If this RangeTblEntry is also supposed to reference inherited
|
||||
* tables, we need to check security label of the child tables.
|
||||
* So, we expand rte->relid into list of OIDs of inheritance
|
||||
* hierarchy, then checker routine will be invoked for each
|
||||
* relations.
|
||||
* tables, we need to check security label of the child tables. So, we
|
||||
* expand rte->relid into list of OIDs of inheritance hierarchy, then
|
||||
* checker routine will be invoked for each relations.
|
||||
*/
|
||||
if (!rte->inh)
|
||||
tableIds = list_make1_oid(rte->relid);
|
||||
else
|
||||
tableIds = find_all_inheritors(rte->relid, NoLock, NULL);
|
||||
|
||||
foreach (li, tableIds)
|
||||
foreach(li, tableIds)
|
||||
{
|
||||
Oid tableOid = lfirst_oid(li);
|
||||
Bitmapset *selectedCols;
|
||||
Bitmapset *modifiedCols;
|
||||
|
||||
/*
|
||||
* child table has different attribute numbers, so we need
|
||||
* to fix up them.
|
||||
* child table has different attribute numbers, so we need to fix
|
||||
* up them.
|
||||
*/
|
||||
selectedCols = fixup_inherited_columns(rte->relid, tableOid,
|
||||
rte->selectedCols);
|
||||
|
|
|
@ -29,17 +29,17 @@ PG_MODULE_MAGIC;
|
|||
/*
|
||||
* Declarations
|
||||
*/
|
||||
void _PG_init(void);
|
||||
void _PG_init(void);
|
||||
|
||||
/*
|
||||
* Saved hook entries (if stacked)
|
||||
*/
|
||||
static object_access_hook_type next_object_access_hook = NULL;
|
||||
static ClientAuthentication_hook_type next_client_auth_hook = NULL;
|
||||
static ExecutorCheckPerms_hook_type next_exec_check_perms_hook = NULL;
|
||||
static needs_fmgr_hook_type next_needs_fmgr_hook = NULL;
|
||||
static fmgr_hook_type next_fmgr_hook = NULL;
|
||||
static ProcessUtility_hook_type next_ProcessUtility_hook = NULL;
|
||||
static object_access_hook_type next_object_access_hook = NULL;
|
||||
static ClientAuthentication_hook_type next_client_auth_hook = NULL;
|
||||
static ExecutorCheckPerms_hook_type next_exec_check_perms_hook = NULL;
|
||||
static needs_fmgr_hook_type next_needs_fmgr_hook = NULL;
|
||||
static fmgr_hook_type next_fmgr_hook = NULL;
|
||||
static ProcessUtility_hook_type next_ProcessUtility_hook = NULL;
|
||||
|
||||
/*
|
||||
* GUC: sepgsql.permissive = (on|off)
|
||||
|
@ -73,14 +73,14 @@ sepgsql_get_debug_audit(void)
|
|||
static void
|
||||
sepgsql_client_auth(Port *port, int status)
|
||||
{
|
||||
char *context;
|
||||
char *context;
|
||||
|
||||
if (next_client_auth_hook)
|
||||
(*next_client_auth_hook)(port, status);
|
||||
(*next_client_auth_hook) (port, status);
|
||||
|
||||
/*
|
||||
* In the case when authentication failed, the supplied socket
|
||||
* shall be closed soon, so we don't need to do anything here.
|
||||
* In the case when authentication failed, the supplied socket shall be
|
||||
* closed soon, so we don't need to do anything here.
|
||||
*/
|
||||
if (status != STATUS_OK)
|
||||
return;
|
||||
|
@ -96,8 +96,8 @@ sepgsql_client_auth(Port *port, int status)
|
|||
sepgsql_set_client_label(context);
|
||||
|
||||
/*
|
||||
* Switch the current performing mode from INTERNAL to either
|
||||
* DEFAULT or PERMISSIVE.
|
||||
* Switch the current performing mode from INTERNAL to either DEFAULT or
|
||||
* PERMISSIVE.
|
||||
*/
|
||||
if (sepgsql_permissive)
|
||||
sepgsql_set_mode(SEPGSQL_MODE_PERMISSIVE);
|
||||
|
@ -113,12 +113,12 @@ sepgsql_client_auth(Port *port, int status)
|
|||
*/
|
||||
static void
|
||||
sepgsql_object_access(ObjectAccessType access,
|
||||
Oid classId,
|
||||
Oid objectId,
|
||||
int subId)
|
||||
Oid classId,
|
||||
Oid objectId,
|
||||
int subId)
|
||||
{
|
||||
if (next_object_access_hook)
|
||||
(*next_object_access_hook)(access, classId, objectId, subId);
|
||||
(*next_object_access_hook) (access, classId, objectId, subId);
|
||||
|
||||
switch (access)
|
||||
{
|
||||
|
@ -147,7 +147,7 @@ sepgsql_object_access(ObjectAccessType access,
|
|||
break;
|
||||
|
||||
default:
|
||||
elog(ERROR, "unexpected object access type: %d", (int)access);
|
||||
elog(ERROR, "unexpected object access type: %d", (int) access);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -161,11 +161,11 @@ static bool
|
|||
sepgsql_exec_check_perms(List *rangeTabls, bool abort)
|
||||
{
|
||||
/*
|
||||
* If security provider is stacking and one of them replied 'false'
|
||||
* at least, we don't need to check any more.
|
||||
* If security provider is stacking and one of them replied 'false' at
|
||||
* least, we don't need to check any more.
|
||||
*/
|
||||
if (next_exec_check_perms_hook &&
|
||||
!(*next_exec_check_perms_hook)(rangeTabls, abort))
|
||||
!(*next_exec_check_perms_hook) (rangeTabls, abort))
|
||||
return false;
|
||||
|
||||
if (!sepgsql_dml_privileges(rangeTabls, abort))
|
||||
|
@ -184,20 +184,19 @@ sepgsql_exec_check_perms(List *rangeTabls, bool abort)
|
|||
static bool
|
||||
sepgsql_needs_fmgr_hook(Oid functionId)
|
||||
{
|
||||
char *old_label;
|
||||
char *new_label;
|
||||
char *function_label;
|
||||
char *old_label;
|
||||
char *new_label;
|
||||
char *function_label;
|
||||
|
||||
if (next_needs_fmgr_hook &&
|
||||
(*next_needs_fmgr_hook)(functionId))
|
||||
(*next_needs_fmgr_hook) (functionId))
|
||||
return true;
|
||||
|
||||
/*
|
||||
* SELinux needs the function to be called via security_definer
|
||||
* wrapper, if this invocation will take a domain-transition.
|
||||
* We call these functions as trusted-procedure, if the security
|
||||
* policy has a rule that switches security label of the client
|
||||
* on execution.
|
||||
* SELinux needs the function to be called via security_definer wrapper,
|
||||
* if this invocation will take a domain-transition. We call these
|
||||
* functions as trusted-procedure, if the security policy has a rule that
|
||||
* switches security label of the client on execution.
|
||||
*/
|
||||
old_label = sepgsql_get_client_label();
|
||||
new_label = sepgsql_proc_get_domtrans(functionId);
|
||||
|
@ -210,9 +209,9 @@ sepgsql_needs_fmgr_hook(Oid functionId)
|
|||
|
||||
/*
|
||||
* Even if not a trusted-procedure, this function should not be inlined
|
||||
* unless the client has db_procedure:{execute} permission.
|
||||
* Please note that it shall be actually failed later because of same
|
||||
* reason with ACL_EXECUTE.
|
||||
* unless the client has db_procedure:{execute} permission. Please note
|
||||
* that it shall be actually failed later because of same reason with
|
||||
* ACL_EXECUTE.
|
||||
*/
|
||||
function_label = sepgsql_get_label(ProcedureRelationId, functionId, 0);
|
||||
if (sepgsql_check_perms(sepgsql_get_client_label(),
|
||||
|
@ -238,20 +237,21 @@ static void
|
|||
sepgsql_fmgr_hook(FmgrHookEventType event,
|
||||
FmgrInfo *flinfo, Datum *private)
|
||||
{
|
||||
struct {
|
||||
char *old_label;
|
||||
char *new_label;
|
||||
Datum next_private;
|
||||
} *stack;
|
||||
struct
|
||||
{
|
||||
char *old_label;
|
||||
char *new_label;
|
||||
Datum next_private;
|
||||
} *stack;
|
||||
|
||||
switch (event)
|
||||
{
|
||||
case FHET_START:
|
||||
stack = (void *)DatumGetPointer(*private);
|
||||
stack = (void *) DatumGetPointer(*private);
|
||||
if (!stack)
|
||||
{
|
||||
MemoryContext oldcxt;
|
||||
const char *cur_label = sepgsql_get_client_label();
|
||||
MemoryContext oldcxt;
|
||||
const char *cur_label = sepgsql_get_client_label();
|
||||
|
||||
oldcxt = MemoryContextSwitchTo(flinfo->fn_mcxt);
|
||||
stack = palloc(sizeof(*stack));
|
||||
|
@ -265,8 +265,8 @@ sepgsql_fmgr_hook(FmgrHookEventType event,
|
|||
{
|
||||
/*
|
||||
* process:transition permission between old and new
|
||||
* label, when user tries to switch security label of
|
||||
* the client on execution of trusted procedure.
|
||||
* label, when user tries to switch security label of the
|
||||
* client on execution of trusted procedure.
|
||||
*/
|
||||
sepgsql_check_perms(cur_label, stack->new_label,
|
||||
SEPG_CLASS_PROCESS,
|
||||
|
@ -280,22 +280,22 @@ sepgsql_fmgr_hook(FmgrHookEventType event,
|
|||
stack->old_label = sepgsql_set_client_label(stack->new_label);
|
||||
|
||||
if (next_fmgr_hook)
|
||||
(*next_fmgr_hook)(event, flinfo, &stack->next_private);
|
||||
(*next_fmgr_hook) (event, flinfo, &stack->next_private);
|
||||
break;
|
||||
|
||||
case FHET_END:
|
||||
case FHET_ABORT:
|
||||
stack = (void *)DatumGetPointer(*private);
|
||||
stack = (void *) DatumGetPointer(*private);
|
||||
|
||||
if (next_fmgr_hook)
|
||||
(*next_fmgr_hook)(event, flinfo, &stack->next_private);
|
||||
(*next_fmgr_hook) (event, flinfo, &stack->next_private);
|
||||
|
||||
sepgsql_set_client_label(stack->old_label);
|
||||
stack->old_label = NULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(ERROR, "unexpected event type: %d", (int)event);
|
||||
elog(ERROR, "unexpected event type: %d", (int) event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -315,8 +315,8 @@ sepgsql_utility_command(Node *parsetree,
|
|||
char *completionTag)
|
||||
{
|
||||
if (next_ProcessUtility_hook)
|
||||
(*next_ProcessUtility_hook)(parsetree, queryString, params,
|
||||
isTopLevel, dest, completionTag);
|
||||
(*next_ProcessUtility_hook) (parsetree, queryString, params,
|
||||
isTopLevel, dest, completionTag);
|
||||
|
||||
/*
|
||||
* Check command tag to avoid nefarious operations
|
||||
|
@ -324,6 +324,7 @@ sepgsql_utility_command(Node *parsetree,
|
|||
switch (nodeTag(parsetree))
|
||||
{
|
||||
case T_LoadStmt:
|
||||
|
||||
/*
|
||||
* We reject LOAD command across the board on enforcing mode,
|
||||
* because a binary module can arbitrarily override hooks.
|
||||
|
@ -336,11 +337,12 @@ sepgsql_utility_command(Node *parsetree,
|
|||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
/*
|
||||
* Right now we don't check any other utility commands,
|
||||
* because it needs more detailed information to make
|
||||
* access control decision here, but we don't want to
|
||||
* have two parse and analyze routines individually.
|
||||
* Right now we don't check any other utility commands, because it
|
||||
* needs more detailed information to make access control decision
|
||||
* here, but we don't want to have two parse and analyze routines
|
||||
* individually.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
@ -358,7 +360,7 @@ sepgsql_utility_command(Node *parsetree,
|
|||
void
|
||||
_PG_init(void)
|
||||
{
|
||||
char *context;
|
||||
char *context;
|
||||
|
||||
/*
|
||||
* We allow to load the SE-PostgreSQL module on single-user-mode or
|
||||
|
@ -367,12 +369,12 @@ _PG_init(void)
|
|||
if (IsUnderPostmaster)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
errmsg("sepgsql must be loaded via shared_preload_libraries")));
|
||||
errmsg("sepgsql must be loaded via shared_preload_libraries")));
|
||||
|
||||
/*
|
||||
* Check availability of SELinux on the platform.
|
||||
* If disabled, we cannot activate any SE-PostgreSQL features,
|
||||
* and we have to skip rest of initialization.
|
||||
* Check availability of SELinux on the platform. If disabled, we cannot
|
||||
* activate any SE-PostgreSQL features, and we have to skip rest of
|
||||
* initialization.
|
||||
*/
|
||||
if (is_selinux_enabled() < 1)
|
||||
{
|
||||
|
@ -383,8 +385,8 @@ _PG_init(void)
|
|||
/*
|
||||
* sepgsql.permissive = (on|off)
|
||||
*
|
||||
* This variable controls performing mode of SE-PostgreSQL
|
||||
* on user's session.
|
||||
* This variable controls performing mode of SE-PostgreSQL on user's
|
||||
* session.
|
||||
*/
|
||||
DefineCustomBoolVariable("sepgsql.permissive",
|
||||
"Turn on/off permissive mode in SE-PostgreSQL",
|
||||
|
@ -400,10 +402,9 @@ _PG_init(void)
|
|||
/*
|
||||
* sepgsql.debug_audit = (on|off)
|
||||
*
|
||||
* This variable allows users to turn on/off audit logs on access
|
||||
* control decisions, independent from auditallow/auditdeny setting
|
||||
* in the security policy.
|
||||
* We intend to use this option for debugging purpose.
|
||||
* This variable allows users to turn on/off audit logs on access control
|
||||
* decisions, independent from auditallow/auditdeny setting in the
|
||||
* security policy. We intend to use this option for debugging purpose.
|
||||
*/
|
||||
DefineCustomBoolVariable("sepgsql.debug_audit",
|
||||
"Turn on/off debug audit messages",
|
||||
|
@ -419,13 +420,12 @@ _PG_init(void)
|
|||
/*
|
||||
* Set up dummy client label.
|
||||
*
|
||||
* XXX - note that PostgreSQL launches background worker process
|
||||
* like autovacuum without authentication steps. So, we initialize
|
||||
* sepgsql_mode with SEPGSQL_MODE_INTERNAL, and client_label with
|
||||
* the security context of server process.
|
||||
* Later, it also launches background of user session. In this case,
|
||||
* the process is always hooked on post-authentication, and we can
|
||||
* initialize the sepgsql_mode and client_label correctly.
|
||||
* XXX - note that PostgreSQL launches background worker process like
|
||||
* autovacuum without authentication steps. So, we initialize sepgsql_mode
|
||||
* with SEPGSQL_MODE_INTERNAL, and client_label with the security context
|
||||
* of server process. Later, it also launches background of user session.
|
||||
* In this case, the process is always hooked on post-authentication, and
|
||||
* we can initialize the sepgsql_mode and client_label correctly.
|
||||
*/
|
||||
if (getcon_raw(&context) < 0)
|
||||
ereport(ERROR,
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
*
|
||||
* security label of the client process
|
||||
*/
|
||||
static char *client_label = NULL;
|
||||
static char *client_label = NULL;
|
||||
|
||||
char *
|
||||
sepgsql_get_client_label(void)
|
||||
|
@ -49,7 +49,7 @@ sepgsql_get_client_label(void)
|
|||
char *
|
||||
sepgsql_set_client_label(char *new_label)
|
||||
{
|
||||
char *old_label = client_label;
|
||||
char *old_label = client_label;
|
||||
|
||||
client_label = new_label;
|
||||
|
||||
|
@ -66,22 +66,22 @@ sepgsql_set_client_label(char *new_label)
|
|||
char *
|
||||
sepgsql_get_label(Oid classId, Oid objectId, int32 subId)
|
||||
{
|
||||
ObjectAddress object;
|
||||
char *label;
|
||||
ObjectAddress object;
|
||||
char *label;
|
||||
|
||||
object.classId = classId;
|
||||
object.objectId = objectId;
|
||||
object.objectSubId = subId;
|
||||
object.classId = classId;
|
||||
object.objectId = objectId;
|
||||
object.objectSubId = subId;
|
||||
|
||||
label = GetSecurityLabel(&object, SEPGSQL_LABEL_TAG);
|
||||
if (!label || security_check_context_raw((security_context_t)label))
|
||||
if (!label || security_check_context_raw((security_context_t) label))
|
||||
{
|
||||
security_context_t unlabeled;
|
||||
security_context_t unlabeled;
|
||||
|
||||
if (security_get_initial_context_raw("unlabeled", &unlabeled) < 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INTERNAL_ERROR),
|
||||
errmsg("SELinux: failed to get initial security label: %m")));
|
||||
errmsg("SELinux: failed to get initial security label: %m")));
|
||||
PG_TRY();
|
||||
{
|
||||
label = pstrdup(unlabeled);
|
||||
|
@ -107,21 +107,22 @@ void
|
|||
sepgsql_object_relabel(const ObjectAddress *object, const char *seclabel)
|
||||
{
|
||||
/*
|
||||
* validate format of the supplied security label,
|
||||
* if it is security context of selinux.
|
||||
* validate format of the supplied security label, if it is security
|
||||
* context of selinux.
|
||||
*/
|
||||
if (seclabel &&
|
||||
security_check_context_raw((security_context_t) seclabel) < 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_NAME),
|
||||
errmsg("SELinux: invalid security label: \"%s\"", seclabel)));
|
||||
errmsg("SELinux: invalid security label: \"%s\"", seclabel)));
|
||||
|
||||
/*
|
||||
* Do actual permission checks for each object classes
|
||||
*/
|
||||
switch (object->classId)
|
||||
{
|
||||
case NamespaceRelationId:
|
||||
sepgsql_schema_relabel(object->objectId, seclabel);
|
||||
sepgsql_schema_relabel(object->objectId, seclabel);
|
||||
break;
|
||||
case RelationRelationId:
|
||||
if (object->objectSubId == 0)
|
||||
|
@ -151,7 +152,7 @@ PG_FUNCTION_INFO_V1(sepgsql_getcon);
|
|||
Datum
|
||||
sepgsql_getcon(PG_FUNCTION_ARGS)
|
||||
{
|
||||
char *client_label;
|
||||
char *client_label;
|
||||
|
||||
if (!sepgsql_is_enabled())
|
||||
PG_RETURN_NULL();
|
||||
|
@ -171,9 +172,9 @@ PG_FUNCTION_INFO_V1(sepgsql_mcstrans_in);
|
|||
Datum
|
||||
sepgsql_mcstrans_in(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *label = PG_GETARG_TEXT_P(0);
|
||||
char *raw_label;
|
||||
char *result;
|
||||
text *label = PG_GETARG_TEXT_P(0);
|
||||
char *raw_label;
|
||||
char *result;
|
||||
|
||||
if (!sepgsql_is_enabled())
|
||||
ereport(ERROR,
|
||||
|
@ -211,9 +212,9 @@ PG_FUNCTION_INFO_V1(sepgsql_mcstrans_out);
|
|||
Datum
|
||||
sepgsql_mcstrans_out(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *label = PG_GETARG_TEXT_P(0);
|
||||
char *qual_label;
|
||||
char *result;
|
||||
text *label = PG_GETARG_TEXT_P(0);
|
||||
char *qual_label;
|
||||
char *result;
|
||||
|
||||
if (!sepgsql_is_enabled())
|
||||
ereport(ERROR,
|
||||
|
@ -250,8 +251,8 @@ static char *
|
|||
quote_object_name(const char *src1, const char *src2,
|
||||
const char *src3, const char *src4)
|
||||
{
|
||||
StringInfoData result;
|
||||
const char *temp;
|
||||
StringInfoData result;
|
||||
const char *temp;
|
||||
|
||||
initStringInfo(&result);
|
||||
|
||||
|
@ -260,28 +261,28 @@ quote_object_name(const char *src1, const char *src2,
|
|||
temp = quote_identifier(src1);
|
||||
appendStringInfo(&result, "%s", temp);
|
||||
if (src1 != temp)
|
||||
pfree((void *)temp);
|
||||
pfree((void *) temp);
|
||||
}
|
||||
if (src2)
|
||||
{
|
||||
temp = quote_identifier(src2);
|
||||
appendStringInfo(&result, ".%s", temp);
|
||||
if (src2 != temp)
|
||||
pfree((void *)temp);
|
||||
pfree((void *) temp);
|
||||
}
|
||||
if (src3)
|
||||
{
|
||||
temp = quote_identifier(src3);
|
||||
appendStringInfo(&result, ".%s", temp);
|
||||
if (src3 != temp)
|
||||
pfree((void *)temp);
|
||||
pfree((void *) temp);
|
||||
}
|
||||
if (src4)
|
||||
{
|
||||
temp = quote_identifier(src4);
|
||||
appendStringInfo(&result, ".%s", temp);
|
||||
if (src4 != temp)
|
||||
pfree((void *)temp);
|
||||
pfree((void *) temp);
|
||||
}
|
||||
return result.data;
|
||||
}
|
||||
|
@ -294,19 +295,19 @@ quote_object_name(const char *src1, const char *src2,
|
|||
* catalog OID.
|
||||
*/
|
||||
static void
|
||||
exec_object_restorecon(struct selabel_handle *sehnd, Oid catalogId)
|
||||
exec_object_restorecon(struct selabel_handle * sehnd, Oid catalogId)
|
||||
{
|
||||
Relation rel;
|
||||
SysScanDesc sscan;
|
||||
HeapTuple tuple;
|
||||
char *database_name = get_database_name(MyDatabaseId);
|
||||
char *namespace_name;
|
||||
Oid namespace_id;
|
||||
char *relation_name;
|
||||
Relation rel;
|
||||
SysScanDesc sscan;
|
||||
HeapTuple tuple;
|
||||
char *database_name = get_database_name(MyDatabaseId);
|
||||
char *namespace_name;
|
||||
Oid namespace_id;
|
||||
char *relation_name;
|
||||
|
||||
/*
|
||||
* Open the target catalog. We don't want to allow writable
|
||||
* accesses by other session during initial labeling.
|
||||
* Open the target catalog. We don't want to allow writable accesses by
|
||||
* other session during initial labeling.
|
||||
*/
|
||||
rel = heap_open(catalogId, AccessShareLock);
|
||||
|
||||
|
@ -314,18 +315,18 @@ exec_object_restorecon(struct selabel_handle *sehnd, Oid catalogId)
|
|||
SnapshotNow, 0, NULL);
|
||||
while (HeapTupleIsValid(tuple = systable_getnext(sscan)))
|
||||
{
|
||||
Form_pg_namespace nspForm;
|
||||
Form_pg_class relForm;
|
||||
Form_pg_attribute attForm;
|
||||
Form_pg_proc proForm;
|
||||
char *objname;
|
||||
int objtype = 1234;
|
||||
ObjectAddress object;
|
||||
security_context_t context;
|
||||
Form_pg_namespace nspForm;
|
||||
Form_pg_class relForm;
|
||||
Form_pg_attribute attForm;
|
||||
Form_pg_proc proForm;
|
||||
char *objname;
|
||||
int objtype = 1234;
|
||||
ObjectAddress object;
|
||||
security_context_t context;
|
||||
|
||||
/*
|
||||
* The way to determine object name depends on object classes.
|
||||
* So, any branches set up `objtype', `objname' and `object' here.
|
||||
* The way to determine object name depends on object classes. So, any
|
||||
* branches set up `objtype', `objname' and `object' here.
|
||||
*/
|
||||
switch (catalogId)
|
||||
{
|
||||
|
@ -409,7 +410,7 @@ exec_object_restorecon(struct selabel_handle *sehnd, Oid catalogId)
|
|||
|
||||
default:
|
||||
elog(ERROR, "unexpected catalog id: %u", catalogId);
|
||||
objname = NULL; /* for compiler quiet */
|
||||
objname = NULL; /* for compiler quiet */
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -464,8 +465,8 @@ PG_FUNCTION_INFO_V1(sepgsql_restorecon);
|
|||
Datum
|
||||
sepgsql_restorecon(PG_FUNCTION_ARGS)
|
||||
{
|
||||
struct selabel_handle *sehnd;
|
||||
struct selinux_opt seopts;
|
||||
struct selabel_handle *sehnd;
|
||||
struct selinux_opt seopts;
|
||||
|
||||
/*
|
||||
* SELinux has to be enabled on the running platform.
|
||||
|
@ -474,19 +475,19 @@ sepgsql_restorecon(PG_FUNCTION_ARGS)
|
|||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
errmsg("sepgsql is not currently enabled")));
|
||||
|
||||
/*
|
||||
* Check DAC permission. Only superuser can set up initial
|
||||
* security labels, like root-user in filesystems
|
||||
* Check DAC permission. Only superuser can set up initial security
|
||||
* labels, like root-user in filesystems
|
||||
*/
|
||||
if (!superuser())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("SELinux: must be superuser to restore initial contexts")));
|
||||
errmsg("SELinux: must be superuser to restore initial contexts")));
|
||||
|
||||
/*
|
||||
* Open selabel_lookup(3) stuff. It provides a set of mapping
|
||||
* between an initial security label and object class/name due
|
||||
* to the system setting.
|
||||
* Open selabel_lookup(3) stuff. It provides a set of mapping between an
|
||||
* initial security label and object class/name due to the system setting.
|
||||
*/
|
||||
if (PG_ARGISNULL(0))
|
||||
{
|
||||
|
@ -502,12 +503,12 @@ sepgsql_restorecon(PG_FUNCTION_ARGS)
|
|||
if (!sehnd)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INTERNAL_ERROR),
|
||||
errmsg("SELinux: failed to initialize labeling handle: %m")));
|
||||
errmsg("SELinux: failed to initialize labeling handle: %m")));
|
||||
PG_TRY();
|
||||
{
|
||||
/*
|
||||
* Right now, we have no support labeling on the shared
|
||||
* database objects, such as database, role, or tablespace.
|
||||
* Right now, we have no support labeling on the shared database
|
||||
* objects, such as database, role, or tablespace.
|
||||
*/
|
||||
exec_object_restorecon(sehnd, NamespaceRelationId);
|
||||
exec_object_restorecon(sehnd, RelationRelationId);
|
||||
|
@ -519,7 +520,7 @@ sepgsql_restorecon(PG_FUNCTION_ARGS)
|
|||
selabel_close(sehnd);
|
||||
PG_RE_THROW();
|
||||
}
|
||||
PG_END_TRY();
|
||||
PG_END_TRY();
|
||||
|
||||
selabel_close(sehnd);
|
||||
|
||||
|
|
|
@ -33,15 +33,15 @@
|
|||
void
|
||||
sepgsql_proc_post_create(Oid functionId)
|
||||
{
|
||||
Relation rel;
|
||||
ScanKeyData skey;
|
||||
SysScanDesc sscan;
|
||||
HeapTuple tuple;
|
||||
Oid namespaceId;
|
||||
ObjectAddress object;
|
||||
char *scontext;
|
||||
char *tcontext;
|
||||
char *ncontext;
|
||||
Relation rel;
|
||||
ScanKeyData skey;
|
||||
SysScanDesc sscan;
|
||||
HeapTuple tuple;
|
||||
Oid namespaceId;
|
||||
ObjectAddress object;
|
||||
char *scontext;
|
||||
char *tcontext;
|
||||
char *ncontext;
|
||||
|
||||
/*
|
||||
* Fetch namespace of the new procedure. Because pg_proc entry is not
|
||||
|
@ -67,8 +67,8 @@ sepgsql_proc_post_create(Oid functionId)
|
|||
heap_close(rel, AccessShareLock);
|
||||
|
||||
/*
|
||||
* Compute a default security label when we create a new procedure
|
||||
* object under the specified namespace.
|
||||
* Compute a default security label when we create a new procedure object
|
||||
* under the specified namespace.
|
||||
*/
|
||||
scontext = sepgsql_get_client_label();
|
||||
tcontext = sepgsql_get_label(NamespaceRelationId, namespaceId, 0);
|
||||
|
@ -144,9 +144,9 @@ sepgsql_proc_relabel(Oid functionId, const char *seclabel)
|
|||
char *
|
||||
sepgsql_proc_get_domtrans(Oid functionId)
|
||||
{
|
||||
char *scontext = sepgsql_get_client_label();
|
||||
char *tcontext;
|
||||
char *ncontext;
|
||||
char *scontext = sepgsql_get_client_label();
|
||||
char *tcontext;
|
||||
char *ncontext;
|
||||
|
||||
tcontext = sepgsql_get_label(ProcedureRelationId, functionId, 0);
|
||||
|
||||
|
|
|
@ -36,26 +36,27 @@
|
|||
void
|
||||
sepgsql_attribute_post_create(Oid relOid, AttrNumber attnum)
|
||||
{
|
||||
char *scontext = sepgsql_get_client_label();
|
||||
char *tcontext;
|
||||
char *ncontext;
|
||||
ObjectAddress object;
|
||||
char *scontext = sepgsql_get_client_label();
|
||||
char *tcontext;
|
||||
char *ncontext;
|
||||
ObjectAddress object;
|
||||
|
||||
/*
|
||||
* Only attributes within regular relation have individual
|
||||
* security labels.
|
||||
* Only attributes within regular relation have individual security
|
||||
* labels.
|
||||
*/
|
||||
if (get_rel_relkind(relOid) != RELKIND_RELATION)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Compute a default security label when we create a new procedure
|
||||
* object under the specified namespace.
|
||||
* Compute a default security label when we create a new procedure object
|
||||
* under the specified namespace.
|
||||
*/
|
||||
scontext = sepgsql_get_client_label();
|
||||
tcontext = sepgsql_get_label(RelationRelationId, relOid, 0);
|
||||
ncontext = sepgsql_compute_create(scontext, tcontext,
|
||||
SEPG_CLASS_DB_COLUMN);
|
||||
|
||||
/*
|
||||
* Assign the default security label on a new procedure
|
||||
*/
|
||||
|
@ -81,7 +82,7 @@ sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum,
|
|||
char *scontext = sepgsql_get_client_label();
|
||||
char *tcontext;
|
||||
char *audit_name;
|
||||
ObjectAddress object;
|
||||
ObjectAddress object;
|
||||
|
||||
if (get_rel_relkind(relOid) != RELKIND_RELATION)
|
||||
ereport(ERROR,
|
||||
|
@ -127,21 +128,21 @@ sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum,
|
|||
void
|
||||
sepgsql_relation_post_create(Oid relOid)
|
||||
{
|
||||
Relation rel;
|
||||
ScanKeyData skey;
|
||||
SysScanDesc sscan;
|
||||
HeapTuple tuple;
|
||||
Form_pg_class classForm;
|
||||
ObjectAddress object;
|
||||
uint16 tclass;
|
||||
char *scontext; /* subject */
|
||||
char *tcontext; /* schema */
|
||||
char *rcontext; /* relation */
|
||||
char *ccontext; /* column */
|
||||
Relation rel;
|
||||
ScanKeyData skey;
|
||||
SysScanDesc sscan;
|
||||
HeapTuple tuple;
|
||||
Form_pg_class classForm;
|
||||
ObjectAddress object;
|
||||
uint16 tclass;
|
||||
char *scontext; /* subject */
|
||||
char *tcontext; /* schema */
|
||||
char *rcontext; /* relation */
|
||||
char *ccontext; /* column */
|
||||
|
||||
/*
|
||||
* Fetch catalog record of the new relation. Because pg_class entry is
|
||||
* not visible right now, we need to scan the catalog using SnapshotSelf.
|
||||
* Fetch catalog record of the new relation. Because pg_class entry is not
|
||||
* visible right now, we need to scan the catalog using SnapshotSelf.
|
||||
*/
|
||||
rel = heap_open(RelationRelationId, AccessShareLock);
|
||||
|
||||
|
@ -166,11 +167,11 @@ sepgsql_relation_post_create(Oid relOid)
|
|||
else if (classForm->relkind == RELKIND_VIEW)
|
||||
tclass = SEPG_CLASS_DB_VIEW;
|
||||
else
|
||||
goto out; /* No need to assign individual labels */
|
||||
goto out; /* No need to assign individual labels */
|
||||
|
||||
/*
|
||||
* Compute a default security label when we create a new relation
|
||||
* object under the specified namespace.
|
||||
* Compute a default security label when we create a new relation object
|
||||
* under the specified namespace.
|
||||
*/
|
||||
scontext = sepgsql_get_client_label();
|
||||
tcontext = sepgsql_get_label(NamespaceRelationId,
|
||||
|
@ -186,8 +187,8 @@ sepgsql_relation_post_create(Oid relOid)
|
|||
SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, rcontext);
|
||||
|
||||
/*
|
||||
* We also assigns a default security label on columns of the new
|
||||
* regular tables.
|
||||
* We also assigns a default security label on columns of the new regular
|
||||
* tables.
|
||||
*/
|
||||
if (classForm->relkind == RELKIND_RELATION)
|
||||
{
|
||||
|
|
|
@ -26,21 +26,21 @@
|
|||
void
|
||||
sepgsql_schema_post_create(Oid namespaceId)
|
||||
{
|
||||
char *scontext = sepgsql_get_client_label();
|
||||
char *tcontext;
|
||||
char *ncontext;
|
||||
ObjectAddress object;
|
||||
char *scontext = sepgsql_get_client_label();
|
||||
char *tcontext;
|
||||
char *ncontext;
|
||||
ObjectAddress object;
|
||||
|
||||
/*
|
||||
* FIXME: Right now, we assume pg_database object has a fixed
|
||||
* security label, because pg_seclabel does not support to store
|
||||
* label of shared database objects.
|
||||
* FIXME: Right now, we assume pg_database object has a fixed security
|
||||
* label, because pg_seclabel does not support to store label of shared
|
||||
* database objects.
|
||||
*/
|
||||
tcontext = "system_u:object_r:sepgsql_db_t:s0";
|
||||
|
||||
/*
|
||||
* Compute a default security label when we create a new schema
|
||||
* object under the working database.
|
||||
* Compute a default security label when we create a new schema object
|
||||
* under the working database.
|
||||
*/
|
||||
ncontext = sepgsql_compute_create(scontext, tcontext,
|
||||
SEPG_CLASS_DB_SCHEMA);
|
||||
|
|
|
@ -29,255 +29,563 @@
|
|||
*/
|
||||
static struct
|
||||
{
|
||||
const char *class_name;
|
||||
uint16 class_code;
|
||||
const char *class_name;
|
||||
uint16 class_code;
|
||||
struct
|
||||
{
|
||||
const char *av_name;
|
||||
uint32 av_code;
|
||||
} av[32];
|
||||
} selinux_catalog[] = {
|
||||
const char *av_name;
|
||||
uint32 av_code;
|
||||
} av[32];
|
||||
} selinux_catalog[] =
|
||||
|
||||
{
|
||||
{
|
||||
"process", SEPG_CLASS_PROCESS,
|
||||
"process", SEPG_CLASS_PROCESS,
|
||||
{
|
||||
{ "transition", SEPG_PROCESS__TRANSITION },
|
||||
{ NULL, 0UL }
|
||||
{
|
||||
"transition", SEPG_PROCESS__TRANSITION
|
||||
},
|
||||
{
|
||||
NULL, 0UL
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"file", SEPG_CLASS_FILE,
|
||||
"file", SEPG_CLASS_FILE,
|
||||
{
|
||||
{ "read", SEPG_FILE__READ },
|
||||
{ "write", SEPG_FILE__WRITE },
|
||||
{ "create", SEPG_FILE__CREATE },
|
||||
{ "getattr", SEPG_FILE__GETATTR },
|
||||
{ "unlink", SEPG_FILE__UNLINK },
|
||||
{ "rename", SEPG_FILE__RENAME },
|
||||
{ "append", SEPG_FILE__APPEND },
|
||||
{ NULL, 0UL }
|
||||
{
|
||||
"read", SEPG_FILE__READ
|
||||
},
|
||||
{
|
||||
"write", SEPG_FILE__WRITE
|
||||
},
|
||||
{
|
||||
"create", SEPG_FILE__CREATE
|
||||
},
|
||||
{
|
||||
"getattr", SEPG_FILE__GETATTR
|
||||
},
|
||||
{
|
||||
"unlink", SEPG_FILE__UNLINK
|
||||
},
|
||||
{
|
||||
"rename", SEPG_FILE__RENAME
|
||||
},
|
||||
{
|
||||
"append", SEPG_FILE__APPEND
|
||||
},
|
||||
{
|
||||
NULL, 0UL
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"dir", SEPG_CLASS_DIR,
|
||||
"dir", SEPG_CLASS_DIR,
|
||||
{
|
||||
{ "read", SEPG_DIR__READ },
|
||||
{ "write", SEPG_DIR__WRITE },
|
||||
{ "create", SEPG_DIR__CREATE },
|
||||
{ "getattr", SEPG_DIR__GETATTR },
|
||||
{ "unlink", SEPG_DIR__UNLINK },
|
||||
{ "rename", SEPG_DIR__RENAME },
|
||||
{ "search", SEPG_DIR__SEARCH },
|
||||
{ "add_name", SEPG_DIR__ADD_NAME },
|
||||
{ "remove_name", SEPG_DIR__REMOVE_NAME },
|
||||
{ "rmdir", SEPG_DIR__RMDIR },
|
||||
{ "reparent", SEPG_DIR__REPARENT },
|
||||
{ NULL, 0UL }
|
||||
{
|
||||
"read", SEPG_DIR__READ
|
||||
},
|
||||
{
|
||||
"write", SEPG_DIR__WRITE
|
||||
},
|
||||
{
|
||||
"create", SEPG_DIR__CREATE
|
||||
},
|
||||
{
|
||||
"getattr", SEPG_DIR__GETATTR
|
||||
},
|
||||
{
|
||||
"unlink", SEPG_DIR__UNLINK
|
||||
},
|
||||
{
|
||||
"rename", SEPG_DIR__RENAME
|
||||
},
|
||||
{
|
||||
"search", SEPG_DIR__SEARCH
|
||||
},
|
||||
{
|
||||
"add_name", SEPG_DIR__ADD_NAME
|
||||
},
|
||||
{
|
||||
"remove_name", SEPG_DIR__REMOVE_NAME
|
||||
},
|
||||
{
|
||||
"rmdir", SEPG_DIR__RMDIR
|
||||
},
|
||||
{
|
||||
"reparent", SEPG_DIR__REPARENT
|
||||
},
|
||||
{
|
||||
NULL, 0UL
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"lnk_file", SEPG_CLASS_LNK_FILE,
|
||||
"lnk_file", SEPG_CLASS_LNK_FILE,
|
||||
{
|
||||
{ "read", SEPG_LNK_FILE__READ },
|
||||
{ "write", SEPG_LNK_FILE__WRITE },
|
||||
{ "create", SEPG_LNK_FILE__CREATE },
|
||||
{ "getattr", SEPG_LNK_FILE__GETATTR },
|
||||
{ "unlink", SEPG_LNK_FILE__UNLINK },
|
||||
{ "rename", SEPG_LNK_FILE__RENAME },
|
||||
{ NULL, 0UL }
|
||||
{
|
||||
"read", SEPG_LNK_FILE__READ
|
||||
},
|
||||
{
|
||||
"write", SEPG_LNK_FILE__WRITE
|
||||
},
|
||||
{
|
||||
"create", SEPG_LNK_FILE__CREATE
|
||||
},
|
||||
{
|
||||
"getattr", SEPG_LNK_FILE__GETATTR
|
||||
},
|
||||
{
|
||||
"unlink", SEPG_LNK_FILE__UNLINK
|
||||
},
|
||||
{
|
||||
"rename", SEPG_LNK_FILE__RENAME
|
||||
},
|
||||
{
|
||||
NULL, 0UL
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"chr_file", SEPG_CLASS_CHR_FILE,
|
||||
"chr_file", SEPG_CLASS_CHR_FILE,
|
||||
{
|
||||
{ "read", SEPG_CHR_FILE__READ },
|
||||
{ "write", SEPG_CHR_FILE__WRITE },
|
||||
{ "create", SEPG_CHR_FILE__CREATE },
|
||||
{ "getattr", SEPG_CHR_FILE__GETATTR },
|
||||
{ "unlink", SEPG_CHR_FILE__UNLINK },
|
||||
{ "rename", SEPG_CHR_FILE__RENAME },
|
||||
{ NULL, 0UL }
|
||||
{
|
||||
"read", SEPG_CHR_FILE__READ
|
||||
},
|
||||
{
|
||||
"write", SEPG_CHR_FILE__WRITE
|
||||
},
|
||||
{
|
||||
"create", SEPG_CHR_FILE__CREATE
|
||||
},
|
||||
{
|
||||
"getattr", SEPG_CHR_FILE__GETATTR
|
||||
},
|
||||
{
|
||||
"unlink", SEPG_CHR_FILE__UNLINK
|
||||
},
|
||||
{
|
||||
"rename", SEPG_CHR_FILE__RENAME
|
||||
},
|
||||
{
|
||||
NULL, 0UL
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"blk_file", SEPG_CLASS_BLK_FILE,
|
||||
"blk_file", SEPG_CLASS_BLK_FILE,
|
||||
{
|
||||
{ "read", SEPG_BLK_FILE__READ },
|
||||
{ "write", SEPG_BLK_FILE__WRITE },
|
||||
{ "create", SEPG_BLK_FILE__CREATE },
|
||||
{ "getattr", SEPG_BLK_FILE__GETATTR },
|
||||
{ "unlink", SEPG_BLK_FILE__UNLINK },
|
||||
{ "rename", SEPG_BLK_FILE__RENAME },
|
||||
{ NULL, 0UL }
|
||||
{
|
||||
"read", SEPG_BLK_FILE__READ
|
||||
},
|
||||
{
|
||||
"write", SEPG_BLK_FILE__WRITE
|
||||
},
|
||||
{
|
||||
"create", SEPG_BLK_FILE__CREATE
|
||||
},
|
||||
{
|
||||
"getattr", SEPG_BLK_FILE__GETATTR
|
||||
},
|
||||
{
|
||||
"unlink", SEPG_BLK_FILE__UNLINK
|
||||
},
|
||||
{
|
||||
"rename", SEPG_BLK_FILE__RENAME
|
||||
},
|
||||
{
|
||||
NULL, 0UL
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"sock_file", SEPG_CLASS_SOCK_FILE,
|
||||
"sock_file", SEPG_CLASS_SOCK_FILE,
|
||||
{
|
||||
{ "read", SEPG_SOCK_FILE__READ },
|
||||
{ "write", SEPG_SOCK_FILE__WRITE },
|
||||
{ "create", SEPG_SOCK_FILE__CREATE },
|
||||
{ "getattr", SEPG_SOCK_FILE__GETATTR },
|
||||
{ "unlink", SEPG_SOCK_FILE__UNLINK },
|
||||
{ "rename", SEPG_SOCK_FILE__RENAME },
|
||||
{ NULL, 0UL }
|
||||
{
|
||||
"read", SEPG_SOCK_FILE__READ
|
||||
},
|
||||
{
|
||||
"write", SEPG_SOCK_FILE__WRITE
|
||||
},
|
||||
{
|
||||
"create", SEPG_SOCK_FILE__CREATE
|
||||
},
|
||||
{
|
||||
"getattr", SEPG_SOCK_FILE__GETATTR
|
||||
},
|
||||
{
|
||||
"unlink", SEPG_SOCK_FILE__UNLINK
|
||||
},
|
||||
{
|
||||
"rename", SEPG_SOCK_FILE__RENAME
|
||||
},
|
||||
{
|
||||
NULL, 0UL
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"fifo_file", SEPG_CLASS_FIFO_FILE,
|
||||
"fifo_file", SEPG_CLASS_FIFO_FILE,
|
||||
{
|
||||
{ "read", SEPG_FIFO_FILE__READ },
|
||||
{ "write", SEPG_FIFO_FILE__WRITE },
|
||||
{ "create", SEPG_FIFO_FILE__CREATE },
|
||||
{ "getattr", SEPG_FIFO_FILE__GETATTR },
|
||||
{ "unlink", SEPG_FIFO_FILE__UNLINK },
|
||||
{ "rename", SEPG_FIFO_FILE__RENAME },
|
||||
{ NULL, 0UL }
|
||||
{
|
||||
"read", SEPG_FIFO_FILE__READ
|
||||
},
|
||||
{
|
||||
"write", SEPG_FIFO_FILE__WRITE
|
||||
},
|
||||
{
|
||||
"create", SEPG_FIFO_FILE__CREATE
|
||||
},
|
||||
{
|
||||
"getattr", SEPG_FIFO_FILE__GETATTR
|
||||
},
|
||||
{
|
||||
"unlink", SEPG_FIFO_FILE__UNLINK
|
||||
},
|
||||
{
|
||||
"rename", SEPG_FIFO_FILE__RENAME
|
||||
},
|
||||
{
|
||||
NULL, 0UL
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"db_database", SEPG_CLASS_DB_DATABASE,
|
||||
"db_database", SEPG_CLASS_DB_DATABASE,
|
||||
{
|
||||
{ "create", SEPG_DB_DATABASE__CREATE },
|
||||
{ "drop", SEPG_DB_DATABASE__DROP },
|
||||
{ "getattr", SEPG_DB_DATABASE__GETATTR },
|
||||
{ "setattr", SEPG_DB_DATABASE__SETATTR },
|
||||
{ "relabelfrom", SEPG_DB_DATABASE__RELABELFROM },
|
||||
{ "relabelto", SEPG_DB_DATABASE__RELABELTO },
|
||||
{ "access", SEPG_DB_DATABASE__ACCESS },
|
||||
{ "load_module", SEPG_DB_DATABASE__LOAD_MODULE },
|
||||
{ NULL, 0UL },
|
||||
{
|
||||
"create", SEPG_DB_DATABASE__CREATE
|
||||
},
|
||||
{
|
||||
"drop", SEPG_DB_DATABASE__DROP
|
||||
},
|
||||
{
|
||||
"getattr", SEPG_DB_DATABASE__GETATTR
|
||||
},
|
||||
{
|
||||
"setattr", SEPG_DB_DATABASE__SETATTR
|
||||
},
|
||||
{
|
||||
"relabelfrom", SEPG_DB_DATABASE__RELABELFROM
|
||||
},
|
||||
{
|
||||
"relabelto", SEPG_DB_DATABASE__RELABELTO
|
||||
},
|
||||
{
|
||||
"access", SEPG_DB_DATABASE__ACCESS
|
||||
},
|
||||
{
|
||||
"load_module", SEPG_DB_DATABASE__LOAD_MODULE
|
||||
},
|
||||
{
|
||||
NULL, 0UL
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
"db_schema", SEPG_CLASS_DB_SCHEMA,
|
||||
"db_schema", SEPG_CLASS_DB_SCHEMA,
|
||||
{
|
||||
{ "create", SEPG_DB_SCHEMA__CREATE },
|
||||
{ "drop", SEPG_DB_SCHEMA__DROP },
|
||||
{ "getattr", SEPG_DB_SCHEMA__GETATTR },
|
||||
{ "setattr", SEPG_DB_SCHEMA__SETATTR },
|
||||
{ "relabelfrom", SEPG_DB_SCHEMA__RELABELFROM },
|
||||
{ "relabelto", SEPG_DB_SCHEMA__RELABELTO },
|
||||
{ "search", SEPG_DB_SCHEMA__SEARCH },
|
||||
{ "add_name", SEPG_DB_SCHEMA__ADD_NAME },
|
||||
{ "remove_name", SEPG_DB_SCHEMA__REMOVE_NAME },
|
||||
{ NULL, 0UL },
|
||||
{
|
||||
"create", SEPG_DB_SCHEMA__CREATE
|
||||
},
|
||||
{
|
||||
"drop", SEPG_DB_SCHEMA__DROP
|
||||
},
|
||||
{
|
||||
"getattr", SEPG_DB_SCHEMA__GETATTR
|
||||
},
|
||||
{
|
||||
"setattr", SEPG_DB_SCHEMA__SETATTR
|
||||
},
|
||||
{
|
||||
"relabelfrom", SEPG_DB_SCHEMA__RELABELFROM
|
||||
},
|
||||
{
|
||||
"relabelto", SEPG_DB_SCHEMA__RELABELTO
|
||||
},
|
||||
{
|
||||
"search", SEPG_DB_SCHEMA__SEARCH
|
||||
},
|
||||
{
|
||||
"add_name", SEPG_DB_SCHEMA__ADD_NAME
|
||||
},
|
||||
{
|
||||
"remove_name", SEPG_DB_SCHEMA__REMOVE_NAME
|
||||
},
|
||||
{
|
||||
NULL, 0UL
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
"db_table", SEPG_CLASS_DB_TABLE,
|
||||
"db_table", SEPG_CLASS_DB_TABLE,
|
||||
{
|
||||
{ "create", SEPG_DB_TABLE__CREATE },
|
||||
{ "drop", SEPG_DB_TABLE__DROP },
|
||||
{ "getattr", SEPG_DB_TABLE__GETATTR },
|
||||
{ "setattr", SEPG_DB_TABLE__SETATTR },
|
||||
{ "relabelfrom", SEPG_DB_TABLE__RELABELFROM },
|
||||
{ "relabelto", SEPG_DB_TABLE__RELABELTO },
|
||||
{ "select", SEPG_DB_TABLE__SELECT },
|
||||
{ "update", SEPG_DB_TABLE__UPDATE },
|
||||
{ "insert", SEPG_DB_TABLE__INSERT },
|
||||
{ "delete", SEPG_DB_TABLE__DELETE },
|
||||
{ "lock", SEPG_DB_TABLE__LOCK },
|
||||
{ NULL, 0UL },
|
||||
{
|
||||
"create", SEPG_DB_TABLE__CREATE
|
||||
},
|
||||
{
|
||||
"drop", SEPG_DB_TABLE__DROP
|
||||
},
|
||||
{
|
||||
"getattr", SEPG_DB_TABLE__GETATTR
|
||||
},
|
||||
{
|
||||
"setattr", SEPG_DB_TABLE__SETATTR
|
||||
},
|
||||
{
|
||||
"relabelfrom", SEPG_DB_TABLE__RELABELFROM
|
||||
},
|
||||
{
|
||||
"relabelto", SEPG_DB_TABLE__RELABELTO
|
||||
},
|
||||
{
|
||||
"select", SEPG_DB_TABLE__SELECT
|
||||
},
|
||||
{
|
||||
"update", SEPG_DB_TABLE__UPDATE
|
||||
},
|
||||
{
|
||||
"insert", SEPG_DB_TABLE__INSERT
|
||||
},
|
||||
{
|
||||
"delete", SEPG_DB_TABLE__DELETE
|
||||
},
|
||||
{
|
||||
"lock", SEPG_DB_TABLE__LOCK
|
||||
},
|
||||
{
|
||||
NULL, 0UL
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
"db_sequence", SEPG_CLASS_DB_SEQUENCE,
|
||||
"db_sequence", SEPG_CLASS_DB_SEQUENCE,
|
||||
{
|
||||
{ "create", SEPG_DB_SEQUENCE__CREATE },
|
||||
{ "drop", SEPG_DB_SEQUENCE__DROP },
|
||||
{ "getattr", SEPG_DB_SEQUENCE__GETATTR },
|
||||
{ "setattr", SEPG_DB_SEQUENCE__SETATTR },
|
||||
{ "relabelfrom", SEPG_DB_SEQUENCE__RELABELFROM },
|
||||
{ "relabelto", SEPG_DB_SEQUENCE__RELABELTO },
|
||||
{ "get_value", SEPG_DB_SEQUENCE__GET_VALUE },
|
||||
{ "next_value", SEPG_DB_SEQUENCE__NEXT_VALUE },
|
||||
{ "set_value", SEPG_DB_SEQUENCE__SET_VALUE },
|
||||
{ NULL, 0UL },
|
||||
{
|
||||
"create", SEPG_DB_SEQUENCE__CREATE
|
||||
},
|
||||
{
|
||||
"drop", SEPG_DB_SEQUENCE__DROP
|
||||
},
|
||||
{
|
||||
"getattr", SEPG_DB_SEQUENCE__GETATTR
|
||||
},
|
||||
{
|
||||
"setattr", SEPG_DB_SEQUENCE__SETATTR
|
||||
},
|
||||
{
|
||||
"relabelfrom", SEPG_DB_SEQUENCE__RELABELFROM
|
||||
},
|
||||
{
|
||||
"relabelto", SEPG_DB_SEQUENCE__RELABELTO
|
||||
},
|
||||
{
|
||||
"get_value", SEPG_DB_SEQUENCE__GET_VALUE
|
||||
},
|
||||
{
|
||||
"next_value", SEPG_DB_SEQUENCE__NEXT_VALUE
|
||||
},
|
||||
{
|
||||
"set_value", SEPG_DB_SEQUENCE__SET_VALUE
|
||||
},
|
||||
{
|
||||
NULL, 0UL
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
"db_procedure", SEPG_CLASS_DB_PROCEDURE,
|
||||
"db_procedure", SEPG_CLASS_DB_PROCEDURE,
|
||||
{
|
||||
{ "create", SEPG_DB_PROCEDURE__CREATE },
|
||||
{ "drop", SEPG_DB_PROCEDURE__DROP },
|
||||
{ "getattr", SEPG_DB_PROCEDURE__GETATTR },
|
||||
{ "setattr", SEPG_DB_PROCEDURE__SETATTR },
|
||||
{ "relabelfrom", SEPG_DB_PROCEDURE__RELABELFROM },
|
||||
{ "relabelto", SEPG_DB_PROCEDURE__RELABELTO },
|
||||
{ "execute", SEPG_DB_PROCEDURE__EXECUTE },
|
||||
{ "entrypoint", SEPG_DB_PROCEDURE__ENTRYPOINT },
|
||||
{ "install", SEPG_DB_PROCEDURE__INSTALL },
|
||||
{ NULL, 0UL },
|
||||
{
|
||||
"create", SEPG_DB_PROCEDURE__CREATE
|
||||
},
|
||||
{
|
||||
"drop", SEPG_DB_PROCEDURE__DROP
|
||||
},
|
||||
{
|
||||
"getattr", SEPG_DB_PROCEDURE__GETATTR
|
||||
},
|
||||
{
|
||||
"setattr", SEPG_DB_PROCEDURE__SETATTR
|
||||
},
|
||||
{
|
||||
"relabelfrom", SEPG_DB_PROCEDURE__RELABELFROM
|
||||
},
|
||||
{
|
||||
"relabelto", SEPG_DB_PROCEDURE__RELABELTO
|
||||
},
|
||||
{
|
||||
"execute", SEPG_DB_PROCEDURE__EXECUTE
|
||||
},
|
||||
{
|
||||
"entrypoint", SEPG_DB_PROCEDURE__ENTRYPOINT
|
||||
},
|
||||
{
|
||||
"install", SEPG_DB_PROCEDURE__INSTALL
|
||||
},
|
||||
{
|
||||
NULL, 0UL
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
"db_column", SEPG_CLASS_DB_COLUMN,
|
||||
"db_column", SEPG_CLASS_DB_COLUMN,
|
||||
{
|
||||
{ "create", SEPG_DB_COLUMN__CREATE },
|
||||
{ "drop", SEPG_DB_COLUMN__DROP },
|
||||
{ "getattr", SEPG_DB_COLUMN__GETATTR },
|
||||
{ "setattr", SEPG_DB_COLUMN__SETATTR },
|
||||
{ "relabelfrom", SEPG_DB_COLUMN__RELABELFROM },
|
||||
{ "relabelto", SEPG_DB_COLUMN__RELABELTO },
|
||||
{ "select", SEPG_DB_COLUMN__SELECT },
|
||||
{ "update", SEPG_DB_COLUMN__UPDATE },
|
||||
{ "insert", SEPG_DB_COLUMN__INSERT },
|
||||
{ NULL, 0UL },
|
||||
{
|
||||
"create", SEPG_DB_COLUMN__CREATE
|
||||
},
|
||||
{
|
||||
"drop", SEPG_DB_COLUMN__DROP
|
||||
},
|
||||
{
|
||||
"getattr", SEPG_DB_COLUMN__GETATTR
|
||||
},
|
||||
{
|
||||
"setattr", SEPG_DB_COLUMN__SETATTR
|
||||
},
|
||||
{
|
||||
"relabelfrom", SEPG_DB_COLUMN__RELABELFROM
|
||||
},
|
||||
{
|
||||
"relabelto", SEPG_DB_COLUMN__RELABELTO
|
||||
},
|
||||
{
|
||||
"select", SEPG_DB_COLUMN__SELECT
|
||||
},
|
||||
{
|
||||
"update", SEPG_DB_COLUMN__UPDATE
|
||||
},
|
||||
{
|
||||
"insert", SEPG_DB_COLUMN__INSERT
|
||||
},
|
||||
{
|
||||
NULL, 0UL
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
"db_tuple", SEPG_CLASS_DB_TUPLE,
|
||||
"db_tuple", SEPG_CLASS_DB_TUPLE,
|
||||
{
|
||||
{ "relabelfrom", SEPG_DB_TUPLE__RELABELFROM },
|
||||
{ "relabelto", SEPG_DB_TUPLE__RELABELTO },
|
||||
{ "select", SEPG_DB_TUPLE__SELECT },
|
||||
{ "update", SEPG_DB_TUPLE__UPDATE },
|
||||
{ "insert", SEPG_DB_TUPLE__INSERT },
|
||||
{ "delete", SEPG_DB_TUPLE__DELETE },
|
||||
{ NULL, 0UL },
|
||||
{
|
||||
"relabelfrom", SEPG_DB_TUPLE__RELABELFROM
|
||||
},
|
||||
{
|
||||
"relabelto", SEPG_DB_TUPLE__RELABELTO
|
||||
},
|
||||
{
|
||||
"select", SEPG_DB_TUPLE__SELECT
|
||||
},
|
||||
{
|
||||
"update", SEPG_DB_TUPLE__UPDATE
|
||||
},
|
||||
{
|
||||
"insert", SEPG_DB_TUPLE__INSERT
|
||||
},
|
||||
{
|
||||
"delete", SEPG_DB_TUPLE__DELETE
|
||||
},
|
||||
{
|
||||
NULL, 0UL
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
"db_blob", SEPG_CLASS_DB_BLOB,
|
||||
"db_blob", SEPG_CLASS_DB_BLOB,
|
||||
{
|
||||
{ "create", SEPG_DB_BLOB__CREATE },
|
||||
{ "drop", SEPG_DB_BLOB__DROP },
|
||||
{ "getattr", SEPG_DB_BLOB__GETATTR },
|
||||
{ "setattr", SEPG_DB_BLOB__SETATTR },
|
||||
{ "relabelfrom", SEPG_DB_BLOB__RELABELFROM },
|
||||
{ "relabelto", SEPG_DB_BLOB__RELABELTO },
|
||||
{ "read", SEPG_DB_BLOB__READ },
|
||||
{ "write", SEPG_DB_BLOB__WRITE },
|
||||
{ "import", SEPG_DB_BLOB__IMPORT },
|
||||
{ "export", SEPG_DB_BLOB__EXPORT },
|
||||
{ NULL, 0UL },
|
||||
{
|
||||
"create", SEPG_DB_BLOB__CREATE
|
||||
},
|
||||
{
|
||||
"drop", SEPG_DB_BLOB__DROP
|
||||
},
|
||||
{
|
||||
"getattr", SEPG_DB_BLOB__GETATTR
|
||||
},
|
||||
{
|
||||
"setattr", SEPG_DB_BLOB__SETATTR
|
||||
},
|
||||
{
|
||||
"relabelfrom", SEPG_DB_BLOB__RELABELFROM
|
||||
},
|
||||
{
|
||||
"relabelto", SEPG_DB_BLOB__RELABELTO
|
||||
},
|
||||
{
|
||||
"read", SEPG_DB_BLOB__READ
|
||||
},
|
||||
{
|
||||
"write", SEPG_DB_BLOB__WRITE
|
||||
},
|
||||
{
|
||||
"import", SEPG_DB_BLOB__IMPORT
|
||||
},
|
||||
{
|
||||
"export", SEPG_DB_BLOB__EXPORT
|
||||
},
|
||||
{
|
||||
NULL, 0UL
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
"db_language", SEPG_CLASS_DB_LANGUAGE,
|
||||
"db_language", SEPG_CLASS_DB_LANGUAGE,
|
||||
{
|
||||
{ "create", SEPG_DB_LANGUAGE__CREATE },
|
||||
{ "drop", SEPG_DB_LANGUAGE__DROP },
|
||||
{ "getattr", SEPG_DB_LANGUAGE__GETATTR },
|
||||
{ "setattr", SEPG_DB_LANGUAGE__SETATTR },
|
||||
{ "relabelfrom", SEPG_DB_LANGUAGE__RELABELFROM },
|
||||
{ "relabelto", SEPG_DB_LANGUAGE__RELABELTO },
|
||||
{ "implement", SEPG_DB_LANGUAGE__IMPLEMENT },
|
||||
{ "execute", SEPG_DB_LANGUAGE__EXECUTE },
|
||||
{ NULL, 0UL },
|
||||
{
|
||||
"create", SEPG_DB_LANGUAGE__CREATE
|
||||
},
|
||||
{
|
||||
"drop", SEPG_DB_LANGUAGE__DROP
|
||||
},
|
||||
{
|
||||
"getattr", SEPG_DB_LANGUAGE__GETATTR
|
||||
},
|
||||
{
|
||||
"setattr", SEPG_DB_LANGUAGE__SETATTR
|
||||
},
|
||||
{
|
||||
"relabelfrom", SEPG_DB_LANGUAGE__RELABELFROM
|
||||
},
|
||||
{
|
||||
"relabelto", SEPG_DB_LANGUAGE__RELABELTO
|
||||
},
|
||||
{
|
||||
"implement", SEPG_DB_LANGUAGE__IMPLEMENT
|
||||
},
|
||||
{
|
||||
"execute", SEPG_DB_LANGUAGE__EXECUTE
|
||||
},
|
||||
{
|
||||
NULL, 0UL
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
"db_view", SEPG_CLASS_DB_VIEW,
|
||||
"db_view", SEPG_CLASS_DB_VIEW,
|
||||
{
|
||||
{ "create", SEPG_DB_VIEW__CREATE },
|
||||
{ "drop", SEPG_DB_VIEW__DROP },
|
||||
{ "getattr", SEPG_DB_VIEW__GETATTR },
|
||||
{ "setattr", SEPG_DB_VIEW__SETATTR },
|
||||
{ "relabelfrom", SEPG_DB_VIEW__RELABELFROM },
|
||||
{ "relabelto", SEPG_DB_VIEW__RELABELTO },
|
||||
{ "expand", SEPG_DB_VIEW__EXPAND },
|
||||
{ NULL, 0UL },
|
||||
{
|
||||
"create", SEPG_DB_VIEW__CREATE
|
||||
},
|
||||
{
|
||||
"drop", SEPG_DB_VIEW__DROP
|
||||
},
|
||||
{
|
||||
"getattr", SEPG_DB_VIEW__GETATTR
|
||||
},
|
||||
{
|
||||
"setattr", SEPG_DB_VIEW__SETATTR
|
||||
},
|
||||
{
|
||||
"relabelfrom", SEPG_DB_VIEW__RELABELFROM
|
||||
},
|
||||
{
|
||||
"relabelto", SEPG_DB_VIEW__RELABELTO
|
||||
},
|
||||
{
|
||||
"expand", SEPG_DB_VIEW__EXPAND
|
||||
},
|
||||
{
|
||||
NULL, 0UL
|
||||
},
|
||||
}
|
||||
},
|
||||
};
|
||||
|
@ -316,7 +624,7 @@ sepgsql_get_mode(void)
|
|||
int
|
||||
sepgsql_set_mode(int new_mode)
|
||||
{
|
||||
int old_mode = sepgsql_mode;
|
||||
int old_mode = sepgsql_mode;
|
||||
|
||||
sepgsql_mode = new_mode;
|
||||
|
||||
|
@ -367,10 +675,10 @@ sepgsql_audit_log(bool denied,
|
|||
uint32 audited,
|
||||
const char *audit_name)
|
||||
{
|
||||
StringInfoData buf;
|
||||
const char *class_name;
|
||||
const char *av_name;
|
||||
int i;
|
||||
StringInfoData buf;
|
||||
const char *class_name;
|
||||
const char *av_name;
|
||||
int i;
|
||||
|
||||
/* lookup name of the object class */
|
||||
Assert(tclass < SEPG_CLASS_MAX);
|
||||
|
@ -380,7 +688,7 @@ sepgsql_audit_log(bool denied,
|
|||
initStringInfo(&buf);
|
||||
appendStringInfo(&buf, "%s {",
|
||||
(denied ? "denied" : "allowed"));
|
||||
for (i=0; selinux_catalog[tclass].av[i].av_name; i++)
|
||||
for (i = 0; selinux_catalog[tclass].av[i].av_name; i++)
|
||||
{
|
||||
if (audited & (1UL << i))
|
||||
{
|
||||
|
@ -418,14 +726,15 @@ void
|
|||
sepgsql_compute_avd(const char *scontext,
|
||||
const char *tcontext,
|
||||
uint16 tclass,
|
||||
struct av_decision *avd)
|
||||
struct av_decision * avd)
|
||||
{
|
||||
const char *tclass_name;
|
||||
security_class_t tclass_ex;
|
||||
struct av_decision avd_ex;
|
||||
int i, deny_unknown = security_deny_unknown();
|
||||
const char *tclass_name;
|
||||
security_class_t tclass_ex;
|
||||
struct av_decision avd_ex;
|
||||
int i,
|
||||
deny_unknown = security_deny_unknown();
|
||||
|
||||
/* Get external code of the object class*/
|
||||
/* Get external code of the object class */
|
||||
Assert(tclass < SEPG_CLASS_MAX);
|
||||
Assert(tclass == selinux_catalog[tclass].class_code);
|
||||
|
||||
|
@ -436,14 +745,13 @@ sepgsql_compute_avd(const char *scontext,
|
|||
{
|
||||
/*
|
||||
* If the current security policy does not support permissions
|
||||
* corresponding to database objects, we fill up them with dummy
|
||||
* data.
|
||||
* corresponding to database objects, we fill up them with dummy data.
|
||||
* If security_deny_unknown() returns positive value, undefined
|
||||
* permissions should be denied. Otherwise, allowed
|
||||
*/
|
||||
avd->allowed = (security_deny_unknown() > 0 ? 0 : ~0);
|
||||
avd->auditallow = 0U;
|
||||
avd->auditdeny = ~0U;
|
||||
avd->auditdeny = ~0U;
|
||||
avd->flags = 0;
|
||||
|
||||
return;
|
||||
|
@ -453,8 +761,8 @@ sepgsql_compute_avd(const char *scontext,
|
|||
* Ask SELinux what is allowed set of permissions on a pair of the
|
||||
* security contexts and the given object class.
|
||||
*/
|
||||
if (security_compute_av_flags_raw((security_context_t)scontext,
|
||||
(security_context_t)tcontext,
|
||||
if (security_compute_av_flags_raw((security_context_t) scontext,
|
||||
(security_context_t) tcontext,
|
||||
tclass_ex, 0, &avd_ex) < 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INTERNAL_ERROR),
|
||||
|
@ -464,17 +772,17 @@ sepgsql_compute_avd(const char *scontext,
|
|||
|
||||
/*
|
||||
* SELinux returns its access control decision as a set of permissions
|
||||
* represented in external code which depends on run-time environment.
|
||||
* So, we need to translate it to the internal representation before
|
||||
* returning results for the caller.
|
||||
* represented in external code which depends on run-time environment. So,
|
||||
* we need to translate it to the internal representation before returning
|
||||
* results for the caller.
|
||||
*/
|
||||
memset(avd, 0, sizeof(struct av_decision));
|
||||
|
||||
for (i=0; selinux_catalog[tclass].av[i].av_name; i++)
|
||||
for (i = 0; selinux_catalog[tclass].av[i].av_name; i++)
|
||||
{
|
||||
access_vector_t av_code_ex;
|
||||
const char *av_name = selinux_catalog[tclass].av[i].av_name;
|
||||
uint32 av_code = selinux_catalog[tclass].av[i].av_code;
|
||||
access_vector_t av_code_ex;
|
||||
const char *av_name = selinux_catalog[tclass].av[i].av_name;
|
||||
uint32 av_code = selinux_catalog[tclass].av[i].av_code;
|
||||
|
||||
av_code_ex = string_to_av_perm(tclass_ex, av_name);
|
||||
if (av_code_ex == 0)
|
||||
|
@ -524,23 +832,23 @@ sepgsql_compute_create(const char *scontext,
|
|||
const char *tcontext,
|
||||
uint16 tclass)
|
||||
{
|
||||
security_context_t ncontext;
|
||||
security_class_t tclass_ex;
|
||||
const char *tclass_name;
|
||||
char *result;
|
||||
security_context_t ncontext;
|
||||
security_class_t tclass_ex;
|
||||
const char *tclass_name;
|
||||
char *result;
|
||||
|
||||
/* Get external code of the object class*/
|
||||
/* Get external code of the object class */
|
||||
Assert(tclass < SEPG_CLASS_MAX);
|
||||
|
||||
tclass_name = selinux_catalog[tclass].class_name;
|
||||
tclass_ex = string_to_security_class(tclass_name);
|
||||
|
||||
/*
|
||||
* Ask SELinux what is the default context for the given object class
|
||||
* on a pair of security contexts
|
||||
* Ask SELinux what is the default context for the given object class on a
|
||||
* pair of security contexts
|
||||
*/
|
||||
if (security_compute_create_raw((security_context_t)scontext,
|
||||
(security_context_t)tcontext,
|
||||
if (security_compute_create_raw((security_context_t) scontext,
|
||||
(security_context_t) tcontext,
|
||||
tclass_ex, &ncontext) < 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INTERNAL_ERROR),
|
||||
|
@ -549,8 +857,8 @@ sepgsql_compute_create(const char *scontext,
|
|||
scontext, tcontext, tclass_name)));
|
||||
|
||||
/*
|
||||
* libselinux returns malloc()'ed string, so we need to copy it
|
||||
* on the palloc()'ed region.
|
||||
* libselinux returns malloc()'ed string, so we need to copy it on the
|
||||
* palloc()'ed region.
|
||||
*/
|
||||
PG_TRY();
|
||||
{
|
||||
|
@ -589,7 +897,7 @@ sepgsql_check_perms(const char *scontext,
|
|||
const char *audit_name,
|
||||
bool abort)
|
||||
{
|
||||
struct av_decision avd;
|
||||
struct av_decision avd;
|
||||
uint32 denied;
|
||||
uint32 audited;
|
||||
bool result = true;
|
||||
|
@ -602,7 +910,7 @@ sepgsql_check_perms(const char *scontext,
|
|||
audited = (denied ? denied : required);
|
||||
else
|
||||
audited = (denied ? (denied & avd.auditdeny)
|
||||
: (required & avd.auditallow));
|
||||
: (required & avd.auditallow));
|
||||
|
||||
if (denied &&
|
||||
sepgsql_getenforce() > 0 &&
|
||||
|
@ -610,8 +918,8 @@ sepgsql_check_perms(const char *scontext,
|
|||
result = false;
|
||||
|
||||
/*
|
||||
* It records a security audit for the request, if needed.
|
||||
* But, when SE-PgSQL performs 'internal' mode, it needs to keep silent.
|
||||
* It records a security audit for the request, if needed. But, when
|
||||
* SE-PgSQL performs 'internal' mode, it needs to keep silent.
|
||||
*/
|
||||
if (audited && sepgsql_mode != SEPGSQL_MODE_INTERNAL)
|
||||
{
|
||||
|
|
|
@ -218,33 +218,34 @@ extern bool sepgsql_get_debug_audit(void);
|
|||
/*
|
||||
* selinux.c
|
||||
*/
|
||||
extern bool sepgsql_is_enabled(void);
|
||||
extern bool sepgsql_is_enabled(void);
|
||||
extern int sepgsql_get_mode(void);
|
||||
extern int sepgsql_set_mode(int new_mode);
|
||||
extern bool sepgsql_getenforce(void);
|
||||
|
||||
extern void sepgsql_audit_log(bool denied,
|
||||
const char *scontext,
|
||||
const char *tcontext,
|
||||
uint16 tclass,
|
||||
uint32 audited,
|
||||
const char *audit_name);
|
||||
const char *scontext,
|
||||
const char *tcontext,
|
||||
uint16 tclass,
|
||||
uint32 audited,
|
||||
const char *audit_name);
|
||||
|
||||
extern void sepgsql_compute_avd(const char *scontext,
|
||||
const char *tcontext,
|
||||
uint16 tclass,
|
||||
struct av_decision *avd);
|
||||
const char *tcontext,
|
||||
uint16 tclass,
|
||||
struct av_decision * avd);
|
||||
|
||||
extern char *sepgsql_compute_create(const char *scontext,
|
||||
const char *tcontext,
|
||||
uint16 tclass);
|
||||
const char *tcontext,
|
||||
uint16 tclass);
|
||||
|
||||
extern bool sepgsql_check_perms(const char *scontext,
|
||||
const char *tcontext,
|
||||
uint16 tclass,
|
||||
uint32 required,
|
||||
const char *audit_name,
|
||||
bool abort);
|
||||
const char *tcontext,
|
||||
uint16 tclass,
|
||||
uint32 required,
|
||||
const char *audit_name,
|
||||
bool abort);
|
||||
|
||||
/*
|
||||
* label.c
|
||||
*/
|
||||
|
@ -252,8 +253,8 @@ extern char *sepgsql_get_client_label(void);
|
|||
extern char *sepgsql_set_client_label(char *new_label);
|
||||
extern char *sepgsql_get_label(Oid relOid, Oid objOid, int32 subId);
|
||||
|
||||
extern void sepgsql_object_relabel(const ObjectAddress *object,
|
||||
const char *seclabel);
|
||||
extern void sepgsql_object_relabel(const ObjectAddress *object,
|
||||
const char *seclabel);
|
||||
|
||||
extern Datum sepgsql_getcon(PG_FUNCTION_ARGS);
|
||||
extern Datum sepgsql_mcstrans_in(PG_FUNCTION_ARGS);
|
||||
|
@ -276,7 +277,7 @@ extern void sepgsql_schema_relabel(Oid namespaceId, const char *seclabel);
|
|||
*/
|
||||
extern void sepgsql_attribute_post_create(Oid relOid, AttrNumber attnum);
|
||||
extern void sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum,
|
||||
const char *seclabel);
|
||||
const char *seclabel);
|
||||
extern void sepgsql_relation_post_create(Oid relOid);
|
||||
extern void sepgsql_relation_relabel(Oid relOid, const char *seclabel);
|
||||
|
||||
|
@ -287,4 +288,4 @@ extern void sepgsql_proc_post_create(Oid functionId);
|
|||
extern void sepgsql_proc_relabel(Oid functionId, const char *seclabel);
|
||||
extern char *sepgsql_proc_get_domtrans(Oid functionId);
|
||||
|
||||
#endif /* SEPGSQL_H */
|
||||
#endif /* SEPGSQL_H */
|
||||
|
|
|
@ -84,7 +84,7 @@ moddatetime(PG_FUNCTION_ARGS)
|
|||
|
||||
/*
|
||||
* This is where we check to see if the field we are supposed to update
|
||||
* even exists. The above function must return -1 if name not found?
|
||||
* even exists. The above function must return -1 if name not found?
|
||||
*/
|
||||
if (attnum < 0)
|
||||
ereport(ERROR,
|
||||
|
|
|
@ -61,7 +61,7 @@ static text *pgxml_result_to_text(xmlXPathObjectPtr res, xmlChar *toptag,
|
|||
static xmlChar *pgxml_texttoxmlchar(text *textstring);
|
||||
|
||||
static xmlXPathObjectPtr pgxml_xpath(text *document, xmlChar *xpath,
|
||||
xpath_workspace *workspace);
|
||||
xpath_workspace *workspace);
|
||||
|
||||
static void cleanup_workspace(xpath_workspace *workspace);
|
||||
|
||||
|
@ -234,7 +234,7 @@ Datum
|
|||
xpath_nodeset(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *document = PG_GETARG_TEXT_P(0);
|
||||
text *xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
|
||||
text *xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
|
||||
xmlChar *toptag = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(2));
|
||||
xmlChar *septag = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(3));
|
||||
xmlChar *xpath;
|
||||
|
@ -267,7 +267,7 @@ Datum
|
|||
xpath_list(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *document = PG_GETARG_TEXT_P(0);
|
||||
text *xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
|
||||
text *xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
|
||||
xmlChar *plainsep = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(2));
|
||||
xmlChar *xpath;
|
||||
text *xpres;
|
||||
|
@ -296,7 +296,7 @@ Datum
|
|||
xpath_string(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *document = PG_GETARG_TEXT_P(0);
|
||||
text *xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
|
||||
text *xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
|
||||
xmlChar *xpath;
|
||||
int32 pathsize;
|
||||
text *xpres;
|
||||
|
@ -337,7 +337,7 @@ Datum
|
|||
xpath_number(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *document = PG_GETARG_TEXT_P(0);
|
||||
text *xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
|
||||
text *xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
|
||||
xmlChar *xpath;
|
||||
float4 fRes;
|
||||
xmlXPathObjectPtr res;
|
||||
|
@ -369,7 +369,7 @@ Datum
|
|||
xpath_bool(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *document = PG_GETARG_TEXT_P(0);
|
||||
text *xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
|
||||
text *xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
|
||||
xmlChar *xpath;
|
||||
int bRes;
|
||||
xmlXPathObjectPtr res;
|
||||
|
|
|
@ -42,7 +42,6 @@ extern void pgxml_parser_init(void);
|
|||
|
||||
/* local defs */
|
||||
static const char **parse_params(text *paramstr);
|
||||
|
||||
#endif /* USE_LIBXSLT */
|
||||
|
||||
|
||||
|
@ -166,7 +165,7 @@ parse_params(text *paramstr)
|
|||
{
|
||||
max_params *= 2;
|
||||
params = (const char **) repalloc(params,
|
||||
(max_params + 1) * sizeof(char *));
|
||||
(max_params + 1) * sizeof(char *));
|
||||
}
|
||||
params[nparams++] = pos;
|
||||
pos = strstr(pos, nvsep);
|
||||
|
|
|
@ -350,7 +350,7 @@ nocachegetattr(HeapTuple tuple,
|
|||
*
|
||||
* check to see if any preceding bits are null...
|
||||
*/
|
||||
int byte = attnum >> 3;
|
||||
int byte = attnum >> 3;
|
||||
int finalbit = attnum & 0x07;
|
||||
|
||||
/* check for nulls "before" final bit of last byte */
|
||||
|
|
|
@ -237,7 +237,7 @@ nocache_index_getattr(IndexTuple tup,
|
|||
* Now check to see if any preceding bits are null...
|
||||
*/
|
||||
{
|
||||
int byte = attnum >> 3;
|
||||
int byte = attnum >> 3;
|
||||
int finalbit = attnum & 0x07;
|
||||
|
||||
/* check for nulls "before" final bit of last byte */
|
||||
|
|
|
@ -82,7 +82,8 @@ ginqueryarrayextract(PG_FUNCTION_ARGS)
|
|||
ArrayType *array = PG_GETARG_ARRAYTYPE_P_COPY(0);
|
||||
int32 *nkeys = (int32 *) PG_GETARG_POINTER(1);
|
||||
StrategyNumber strategy = PG_GETARG_UINT16(2);
|
||||
/* bool **pmatch = (bool **) PG_GETARG_POINTER(3); */
|
||||
|
||||
/* bool **pmatch = (bool **) PG_GETARG_POINTER(3); */
|
||||
/* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
|
||||
bool **nullFlags = (bool **) PG_GETARG_POINTER(5);
|
||||
int32 *searchMode = (int32 *) PG_GETARG_POINTER(6);
|
||||
|
@ -112,7 +113,7 @@ ginqueryarrayextract(PG_FUNCTION_ARGS)
|
|||
case GinContainsStrategy:
|
||||
if (nelems > 0)
|
||||
*searchMode = GIN_SEARCH_MODE_DEFAULT;
|
||||
else /* everything contains the empty set */
|
||||
else /* everything contains the empty set */
|
||||
*searchMode = GIN_SEARCH_MODE_ALL;
|
||||
break;
|
||||
case GinContainedStrategy:
|
||||
|
@ -142,10 +143,13 @@ ginarrayconsistent(PG_FUNCTION_ARGS)
|
|||
{
|
||||
bool *check = (bool *) PG_GETARG_POINTER(0);
|
||||
StrategyNumber strategy = PG_GETARG_UINT16(1);
|
||||
|
||||
/* ArrayType *query = PG_GETARG_ARRAYTYPE_P(2); */
|
||||
int32 nkeys = PG_GETARG_INT32(3);
|
||||
|
||||
/* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
|
||||
bool *recheck = (bool *) PG_GETARG_POINTER(5);
|
||||
|
||||
/* Datum *queryKeys = (Datum *) PG_GETARG_POINTER(6); */
|
||||
bool *nullFlags = (bool *) PG_GETARG_POINTER(7);
|
||||
bool res;
|
||||
|
@ -190,10 +194,11 @@ ginarrayconsistent(PG_FUNCTION_ARGS)
|
|||
case GinEqualStrategy:
|
||||
/* we will need recheck */
|
||||
*recheck = true;
|
||||
|
||||
/*
|
||||
* Must have all elements in check[] true; no discrimination
|
||||
* against nulls here. This is because array_contain_compare
|
||||
* and array_eq handle nulls differently ...
|
||||
* against nulls here. This is because array_contain_compare and
|
||||
* array_eq handle nulls differently ...
|
||||
*/
|
||||
res = true;
|
||||
for (i = 0; i < nkeys; i++)
|
||||
|
|
|
@ -80,8 +80,8 @@ ginAllocEntryAccumulator(void *arg)
|
|||
GinEntryAccumulator *ea;
|
||||
|
||||
/*
|
||||
* Allocate memory by rather big chunks to decrease overhead. We have
|
||||
* no need to reclaim RBNodes individually, so this costs nothing.
|
||||
* Allocate memory by rather big chunks to decrease overhead. We have no
|
||||
* need to reclaim RBNodes individually, so this costs nothing.
|
||||
*/
|
||||
if (accum->entryallocator == NULL || accum->eas_used >= DEF_NENTRY)
|
||||
{
|
||||
|
@ -108,7 +108,7 @@ ginInitBA(BuildAccumulator *accum)
|
|||
cmpEntryAccumulator,
|
||||
ginCombineData,
|
||||
ginAllocEntryAccumulator,
|
||||
NULL, /* no freefunc needed */
|
||||
NULL, /* no freefunc needed */
|
||||
(void *) accum);
|
||||
}
|
||||
|
||||
|
@ -145,8 +145,8 @@ ginInsertBAEntry(BuildAccumulator *accum,
|
|||
bool isNew;
|
||||
|
||||
/*
|
||||
* For the moment, fill only the fields of eatmp that will be looked at
|
||||
* by cmpEntryAccumulator or ginCombineData.
|
||||
* For the moment, fill only the fields of eatmp that will be looked at by
|
||||
* cmpEntryAccumulator or ginCombineData.
|
||||
*/
|
||||
eatmp.attnum = attnum;
|
||||
eatmp.key = key;
|
||||
|
|
|
@ -21,13 +21,13 @@
|
|||
int
|
||||
ginCompareItemPointers(ItemPointer a, ItemPointer b)
|
||||
{
|
||||
BlockNumber ba = GinItemPointerGetBlockNumber(a);
|
||||
BlockNumber bb = GinItemPointerGetBlockNumber(b);
|
||||
BlockNumber ba = GinItemPointerGetBlockNumber(a);
|
||||
BlockNumber bb = GinItemPointerGetBlockNumber(b);
|
||||
|
||||
if (ba == bb)
|
||||
{
|
||||
OffsetNumber oa = GinItemPointerGetOffsetNumber(a);
|
||||
OffsetNumber ob = GinItemPointerGetOffsetNumber(b);
|
||||
OffsetNumber oa = GinItemPointerGetOffsetNumber(a);
|
||||
OffsetNumber ob = GinItemPointerGetOffsetNumber(b);
|
||||
|
||||
if (oa == ob)
|
||||
return 0;
|
||||
|
@ -383,6 +383,7 @@ dataPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prda
|
|||
Page page = BufferGetPage(buf);
|
||||
int sizeofitem = GinSizeOfDataPageItem(page);
|
||||
int cnt = 0;
|
||||
|
||||
/* these must be static so they can be returned to caller */
|
||||
static XLogRecData rdata[3];
|
||||
static ginxlogInsert data;
|
||||
|
@ -474,6 +475,7 @@ dataSplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogRe
|
|||
Size pageSize = PageGetPageSize(lpage);
|
||||
Size freeSpace;
|
||||
uint32 nCopied = 1;
|
||||
|
||||
/* these must be static so they can be returned to caller */
|
||||
static ginxlogSplit data;
|
||||
static XLogRecData rdata[4];
|
||||
|
|
|
@ -98,11 +98,11 @@ GinFormTuple(GinState *ginstate,
|
|||
if (errorTooBig)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
||||
errmsg("index row size %lu exceeds maximum %lu for index \"%s\"",
|
||||
(unsigned long) newsize,
|
||||
(unsigned long) Min(INDEX_SIZE_MASK,
|
||||
GinMaxItemSize),
|
||||
RelationGetRelationName(ginstate->index))));
|
||||
errmsg("index row size %lu exceeds maximum %lu for index \"%s\"",
|
||||
(unsigned long) newsize,
|
||||
(unsigned long) Min(INDEX_SIZE_MASK,
|
||||
GinMaxItemSize),
|
||||
RelationGetRelationName(ginstate->index))));
|
||||
pfree(itup);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ GinShortenTuple(IndexTuple itup, uint32 nipd)
|
|||
* Form a non-leaf entry tuple by copying the key data from the given tuple,
|
||||
* which can be either a leaf or non-leaf entry tuple.
|
||||
*
|
||||
* Any posting list in the source tuple is not copied. The specified child
|
||||
* Any posting list in the source tuple is not copied. The specified child
|
||||
* block number is inserted into t_tid.
|
||||
*/
|
||||
static IndexTuple
|
||||
|
@ -225,7 +225,7 @@ entryIsMoveRight(GinBtree btree, Page page)
|
|||
key = gintuple_get_key(btree->ginstate, itup, &category);
|
||||
|
||||
if (ginCompareAttEntries(btree->ginstate,
|
||||
btree->entryAttnum, btree->entryKey, btree->entryCategory,
|
||||
btree->entryAttnum, btree->entryKey, btree->entryCategory,
|
||||
attnum, key, category) > 0)
|
||||
return TRUE;
|
||||
|
||||
|
@ -488,6 +488,7 @@ entryPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prd
|
|||
Page page = BufferGetPage(buf);
|
||||
OffsetNumber placed;
|
||||
int cnt = 0;
|
||||
|
||||
/* these must be static so they can be returned to caller */
|
||||
static XLogRecData rdata[3];
|
||||
static ginxlogInsert data;
|
||||
|
@ -561,6 +562,7 @@ entrySplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogR
|
|||
Page lpage = PageGetTempPageCopy(BufferGetPage(lbuf));
|
||||
Page rpage = BufferGetPage(rbuf);
|
||||
Size pageSize = PageGetPageSize(lpage);
|
||||
|
||||
/* these must be static so they can be returned to caller */
|
||||
static XLogRecData rdata[2];
|
||||
static ginxlogSplit data;
|
||||
|
|
|
@ -88,9 +88,9 @@ writeListPage(Relation index, Buffer buffer,
|
|||
GinPageGetOpaque(page)->rightlink = rightlink;
|
||||
|
||||
/*
|
||||
* tail page may contain only whole row(s) or final part of row placed
|
||||
* on previous pages (a "row" here meaning all the index tuples generated
|
||||
* for one heap tuple)
|
||||
* tail page may contain only whole row(s) or final part of row placed on
|
||||
* previous pages (a "row" here meaning all the index tuples generated for
|
||||
* one heap tuple)
|
||||
*/
|
||||
if (rightlink == InvalidBlockNumber)
|
||||
{
|
||||
|
@ -437,7 +437,7 @@ ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)
|
|||
* Create temporary index tuples for a single indexable item (one index column
|
||||
* for the heap tuple specified by ht_ctid), and append them to the array
|
||||
* in *collector. They will subsequently be written out using
|
||||
* ginHeapTupleFastInsert. Note that to guarantee consistent state, all
|
||||
* ginHeapTupleFastInsert. Note that to guarantee consistent state, all
|
||||
* temp tuples for a given heap tuple must be written in one call to
|
||||
* ginHeapTupleFastInsert.
|
||||
*/
|
||||
|
@ -475,8 +475,8 @@ ginHeapTupleFastCollect(GinState *ginstate,
|
|||
}
|
||||
|
||||
/*
|
||||
* Build an index tuple for each key value, and add to array. In
|
||||
* pending tuples we just stick the heap TID into t_tid.
|
||||
* Build an index tuple for each key value, and add to array. In pending
|
||||
* tuples we just stick the heap TID into t_tid.
|
||||
*/
|
||||
for (i = 0; i < nentries; i++)
|
||||
{
|
||||
|
@ -665,7 +665,7 @@ processPendingPage(BuildAccumulator *accum, KeyArray *ka,
|
|||
{
|
||||
IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
|
||||
OffsetNumber curattnum;
|
||||
Datum curkey;
|
||||
Datum curkey;
|
||||
GinNullCategory curcategory;
|
||||
|
||||
/* Check for change of heap TID or attnum */
|
||||
|
@ -830,7 +830,7 @@ ginInsertCleanup(GinState *ginstate,
|
|||
*/
|
||||
ginBeginBAScan(&accum);
|
||||
while ((list = ginGetBAEntry(&accum,
|
||||
&attnum, &key, &category, &nlist)) != NULL)
|
||||
&attnum, &key, &category, &nlist)) != NULL)
|
||||
{
|
||||
ginEntryInsert(ginstate, attnum, key, category,
|
||||
list, nlist, NULL);
|
||||
|
@ -867,7 +867,7 @@ ginInsertCleanup(GinState *ginstate,
|
|||
|
||||
ginBeginBAScan(&accum);
|
||||
while ((list = ginGetBAEntry(&accum,
|
||||
&attnum, &key, &category, &nlist)) != NULL)
|
||||
&attnum, &key, &category, &nlist)) != NULL)
|
||||
ginEntryInsert(ginstate, attnum, key, category,
|
||||
list, nlist, NULL);
|
||||
}
|
||||
|
|
|
@ -40,8 +40,8 @@ static bool
|
|||
callConsistentFn(GinState *ginstate, GinScanKey key)
|
||||
{
|
||||
/*
|
||||
* If we're dealing with a dummy EVERYTHING key, we don't want to call
|
||||
* the consistentFn; just claim it matches.
|
||||
* If we're dealing with a dummy EVERYTHING key, we don't want to call the
|
||||
* consistentFn; just claim it matches.
|
||||
*/
|
||||
if (key->searchMode == GIN_SEARCH_MODE_EVERYTHING)
|
||||
{
|
||||
|
@ -174,14 +174,14 @@ scanPostingTree(Relation index, GinScanEntry scanEntry,
|
|||
|
||||
/*
|
||||
* Collects TIDs into scanEntry->matchBitmap for all heap tuples that
|
||||
* match the search entry. This supports three different match modes:
|
||||
* match the search entry. This supports three different match modes:
|
||||
*
|
||||
* 1. Partial-match support: scan from current point until the
|
||||
* comparePartialFn says we're done.
|
||||
* comparePartialFn says we're done.
|
||||
* 2. SEARCH_MODE_ALL: scan from current point (which should be first
|
||||
* key for the current attnum) until we hit null items or end of attnum
|
||||
* key for the current attnum) until we hit null items or end of attnum
|
||||
* 3. SEARCH_MODE_EVERYTHING: scan from current point (which should be first
|
||||
* key for the current attnum) until we hit end of attnum
|
||||
* key for the current attnum) until we hit end of attnum
|
||||
*
|
||||
* Returns true if done, false if it's necessary to restart scan from scratch
|
||||
*/
|
||||
|
@ -189,7 +189,7 @@ static bool
|
|||
collectMatchBitmap(GinBtreeData *btree, GinBtreeStack *stack,
|
||||
GinScanEntry scanEntry)
|
||||
{
|
||||
OffsetNumber attnum;
|
||||
OffsetNumber attnum;
|
||||
Form_pg_attribute attr;
|
||||
|
||||
/* Initialize empty bitmap result */
|
||||
|
@ -253,8 +253,8 @@ collectMatchBitmap(GinBtreeData *btree, GinBtreeStack *stack,
|
|||
cmp = DatumGetInt32(FunctionCall4(&btree->ginstate->comparePartialFn[attnum - 1],
|
||||
scanEntry->queryKey,
|
||||
idatum,
|
||||
UInt16GetDatum(scanEntry->strategy),
|
||||
PointerGetDatum(scanEntry->extra_data)));
|
||||
UInt16GetDatum(scanEntry->strategy),
|
||||
PointerGetDatum(scanEntry->extra_data)));
|
||||
|
||||
if (cmp > 0)
|
||||
return true;
|
||||
|
@ -269,7 +269,7 @@ collectMatchBitmap(GinBtreeData *btree, GinBtreeStack *stack,
|
|||
/*
|
||||
* In ALL mode, we are not interested in null items, so we can
|
||||
* stop if we get to a null-item placeholder (which will be the
|
||||
* last entry for a given attnum). We do want to include NULL_KEY
|
||||
* last entry for a given attnum). We do want to include NULL_KEY
|
||||
* and EMPTY_ITEM entries, though.
|
||||
*/
|
||||
if (icategory == GIN_CAT_NULL_ITEM)
|
||||
|
@ -287,8 +287,8 @@ collectMatchBitmap(GinBtreeData *btree, GinBtreeStack *stack,
|
|||
* We should unlock current page (but not unpin) during tree scan
|
||||
* to prevent deadlock with vacuum processes.
|
||||
*
|
||||
* We save current entry value (idatum) to be able to re-find
|
||||
* our tuple after re-locking
|
||||
* We save current entry value (idatum) to be able to re-find our
|
||||
* tuple after re-locking
|
||||
*/
|
||||
if (icategory == GIN_CAT_NORM_KEY)
|
||||
idatum = datumCopy(idatum, attr->attbyval, attr->attlen);
|
||||
|
@ -442,11 +442,11 @@ restartScanEntry:
|
|||
Page page;
|
||||
|
||||
/*
|
||||
* We should unlock entry page before touching posting tree
|
||||
* to prevent deadlocks with vacuum processes. Because entry is
|
||||
* never deleted from page and posting tree is never reduced to
|
||||
* the posting list, we can unlock page after getting BlockNumber
|
||||
* of root of posting tree.
|
||||
* We should unlock entry page before touching posting tree to
|
||||
* prevent deadlocks with vacuum processes. Because entry is never
|
||||
* deleted from page and posting tree is never reduced to the
|
||||
* posting list, we can unlock page after getting BlockNumber of
|
||||
* root of posting tree.
|
||||
*/
|
||||
LockBuffer(stackEntry->buffer, GIN_UNLOCK);
|
||||
needUnlock = FALSE;
|
||||
|
@ -596,7 +596,7 @@ entryGetNextItem(GinState *ginstate, GinScanEntry entry)
|
|||
|
||||
if (!ItemPointerIsValid(&entry->curItem) ||
|
||||
ginCompareItemPointers(&entry->curItem,
|
||||
entry->list + entry->offset - 1) == 0)
|
||||
entry->list + entry->offset - 1) == 0)
|
||||
{
|
||||
/*
|
||||
* First pages are deleted or empty, or we found exact
|
||||
|
@ -656,10 +656,10 @@ entryGetItem(GinState *ginstate, GinScanEntry entry)
|
|||
}
|
||||
|
||||
/*
|
||||
* Reset counter to the beginning of entry->matchResult.
|
||||
* Note: entry->offset is still greater than
|
||||
* matchResult->ntuples if matchResult is lossy. So, on next
|
||||
* call we will get next result from TIDBitmap.
|
||||
* Reset counter to the beginning of entry->matchResult. Note:
|
||||
* entry->offset is still greater than matchResult->ntuples if
|
||||
* matchResult is lossy. So, on next call we will get next
|
||||
* result from TIDBitmap.
|
||||
*/
|
||||
entry->offset = 0;
|
||||
}
|
||||
|
@ -745,10 +745,10 @@ keyGetItem(GinState *ginstate, MemoryContext tempCtx, GinScanKey key)
|
|||
/*
|
||||
* Find the minimum of the active entry curItems.
|
||||
*
|
||||
* Note: a lossy-page entry is encoded by a ItemPointer with max value
|
||||
* for offset (0xffff), so that it will sort after any exact entries
|
||||
* for the same page. So we'll prefer to return exact pointers not
|
||||
* lossy pointers, which is good.
|
||||
* Note: a lossy-page entry is encoded by a ItemPointer with max value for
|
||||
* offset (0xffff), so that it will sort after any exact entries for the
|
||||
* same page. So we'll prefer to return exact pointers not lossy
|
||||
* pointers, which is good.
|
||||
*/
|
||||
ItemPointerSetMax(&minItem);
|
||||
|
||||
|
@ -782,28 +782,27 @@ keyGetItem(GinState *ginstate, MemoryContext tempCtx, GinScanKey key)
|
|||
|
||||
/*
|
||||
* Lossy-page entries pose a problem, since we don't know the correct
|
||||
* entryRes state to pass to the consistentFn, and we also don't know
|
||||
* what its combining logic will be (could be AND, OR, or even NOT).
|
||||
* If the logic is OR then the consistentFn might succeed for all
|
||||
* items in the lossy page even when none of the other entries match.
|
||||
* entryRes state to pass to the consistentFn, and we also don't know what
|
||||
* its combining logic will be (could be AND, OR, or even NOT). If the
|
||||
* logic is OR then the consistentFn might succeed for all items in the
|
||||
* lossy page even when none of the other entries match.
|
||||
*
|
||||
* If we have a single lossy-page entry then we check to see if the
|
||||
* consistentFn will succeed with only that entry TRUE. If so,
|
||||
* we return a lossy-page pointer to indicate that the whole heap
|
||||
* page must be checked. (On subsequent calls, we'll do nothing until
|
||||
* minItem is past the page altogether, thus ensuring that we never return
|
||||
* both regular and lossy pointers for the same page.)
|
||||
* consistentFn will succeed with only that entry TRUE. If so, we return
|
||||
* a lossy-page pointer to indicate that the whole heap page must be
|
||||
* checked. (On subsequent calls, we'll do nothing until minItem is past
|
||||
* the page altogether, thus ensuring that we never return both regular
|
||||
* and lossy pointers for the same page.)
|
||||
*
|
||||
* This idea could be generalized to more than one lossy-page entry,
|
||||
* but ideally lossy-page entries should be infrequent so it would
|
||||
* seldom be the case that we have more than one at once. So it
|
||||
* doesn't seem worth the extra complexity to optimize that case.
|
||||
* If we do find more than one, we just punt and return a lossy-page
|
||||
* pointer always.
|
||||
* This idea could be generalized to more than one lossy-page entry, but
|
||||
* ideally lossy-page entries should be infrequent so it would seldom be
|
||||
* the case that we have more than one at once. So it doesn't seem worth
|
||||
* the extra complexity to optimize that case. If we do find more than
|
||||
* one, we just punt and return a lossy-page pointer always.
|
||||
*
|
||||
* Note that only lossy-page entries pointing to the current item's
|
||||
* page should trigger this processing; we might have future lossy
|
||||
* pages in the entry array, but they aren't relevant yet.
|
||||
* Note that only lossy-page entries pointing to the current item's page
|
||||
* should trigger this processing; we might have future lossy pages in the
|
||||
* entry array, but they aren't relevant yet.
|
||||
*/
|
||||
ItemPointerSetLossyPage(&curPageLossy,
|
||||
GinItemPointerGetBlockNumber(&key->curItem));
|
||||
|
@ -853,15 +852,14 @@ keyGetItem(GinState *ginstate, MemoryContext tempCtx, GinScanKey key)
|
|||
}
|
||||
|
||||
/*
|
||||
* At this point we know that we don't need to return a lossy
|
||||
* whole-page pointer, but we might have matches for individual exact
|
||||
* item pointers, possibly in combination with a lossy pointer. Our
|
||||
* strategy if there's a lossy pointer is to try the consistentFn both
|
||||
* ways and return a hit if it accepts either one (forcing the hit to
|
||||
* be marked lossy so it will be rechecked). An exception is that
|
||||
* we don't need to try it both ways if the lossy pointer is in a
|
||||
* "hidden" entry, because the consistentFn's result can't depend on
|
||||
* that.
|
||||
* At this point we know that we don't need to return a lossy whole-page
|
||||
* pointer, but we might have matches for individual exact item pointers,
|
||||
* possibly in combination with a lossy pointer. Our strategy if there's
|
||||
* a lossy pointer is to try the consistentFn both ways and return a hit
|
||||
* if it accepts either one (forcing the hit to be marked lossy so it will
|
||||
* be rechecked). An exception is that we don't need to try it both ways
|
||||
* if the lossy pointer is in a "hidden" entry, because the consistentFn's
|
||||
* result can't depend on that.
|
||||
*
|
||||
* Prepare entryRes array to be passed to consistentFn.
|
||||
*/
|
||||
|
@ -960,7 +958,7 @@ scanGetItem(IndexScanDesc scan, ItemPointer advancePast,
|
|||
keyGetItem(&so->ginstate, so->tempCtx, key);
|
||||
|
||||
if (key->isFinished)
|
||||
return false; /* finished one of keys */
|
||||
return false; /* finished one of keys */
|
||||
|
||||
if (ginCompareItemPointers(&key->curItem, item) < 0)
|
||||
*item = key->curItem;
|
||||
|
@ -975,7 +973,7 @@ scanGetItem(IndexScanDesc scan, ItemPointer advancePast,
|
|||
* that exact TID, or a lossy reference to the same page.
|
||||
*
|
||||
* This logic works only if a keyGetItem stream can never contain both
|
||||
* exact and lossy pointers for the same page. Else we could have a
|
||||
* exact and lossy pointers for the same page. Else we could have a
|
||||
* case like
|
||||
*
|
||||
* stream 1 stream 2
|
||||
|
@ -1011,8 +1009,8 @@ scanGetItem(IndexScanDesc scan, ItemPointer advancePast,
|
|||
break;
|
||||
|
||||
/*
|
||||
* No hit. Update myAdvancePast to this TID, so that on the next
|
||||
* pass we'll move to the next possible entry.
|
||||
* No hit. Update myAdvancePast to this TID, so that on the next pass
|
||||
* we'll move to the next possible entry.
|
||||
*/
|
||||
myAdvancePast = *item;
|
||||
}
|
||||
|
@ -1118,8 +1116,8 @@ scanGetCandidate(IndexScanDesc scan, pendingPosition *pos)
|
|||
|
||||
/*
|
||||
* Now pos->firstOffset points to the first tuple of current heap
|
||||
* row, pos->lastOffset points to the first tuple of next heap
|
||||
* row (or to the end of page)
|
||||
* row, pos->lastOffset points to the first tuple of next heap row
|
||||
* (or to the end of page)
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
@ -1181,7 +1179,7 @@ matchPartialInPendingList(GinState *ginstate, Page page,
|
|||
entry->queryKey,
|
||||
datum[off - 1],
|
||||
UInt16GetDatum(entry->strategy),
|
||||
PointerGetDatum(entry->extra_data)));
|
||||
PointerGetDatum(entry->extra_data)));
|
||||
if (cmp == 0)
|
||||
return true;
|
||||
else if (cmp > 0)
|
||||
|
@ -1227,8 +1225,8 @@ collectMatchesForHeapRow(IndexScanDesc scan, pendingPosition *pos)
|
|||
memset(pos->hasMatchKey, FALSE, so->nkeys);
|
||||
|
||||
/*
|
||||
* Outer loop iterates over multiple pending-list pages when a single
|
||||
* heap row has entries spanning those pages.
|
||||
* Outer loop iterates over multiple pending-list pages when a single heap
|
||||
* row has entries spanning those pages.
|
||||
*/
|
||||
for (;;)
|
||||
{
|
||||
|
@ -1322,11 +1320,11 @@ collectMatchesForHeapRow(IndexScanDesc scan, pendingPosition *pos)
|
|||
if (res == 0)
|
||||
{
|
||||
/*
|
||||
* Found exact match (there can be only one, except
|
||||
* in EMPTY_QUERY mode).
|
||||
* Found exact match (there can be only one, except in
|
||||
* EMPTY_QUERY mode).
|
||||
*
|
||||
* If doing partial match, scan forward from
|
||||
* here to end of page to check for matches.
|
||||
* If doing partial match, scan forward from here to
|
||||
* end of page to check for matches.
|
||||
*
|
||||
* See comment above about tuple's ordering.
|
||||
*/
|
||||
|
@ -1355,13 +1353,12 @@ collectMatchesForHeapRow(IndexScanDesc scan, pendingPosition *pos)
|
|||
if (StopLow >= StopHigh && entry->isPartialMatch)
|
||||
{
|
||||
/*
|
||||
* No exact match on this page. If doing partial
|
||||
* match, scan from the first tuple greater than
|
||||
* target value to end of page. Note that since we
|
||||
* don't remember whether the comparePartialFn told us
|
||||
* to stop early on a previous page, we will uselessly
|
||||
* apply comparePartialFn to the first tuple on each
|
||||
* subsequent page.
|
||||
* No exact match on this page. If doing partial match,
|
||||
* scan from the first tuple greater than target value to
|
||||
* end of page. Note that since we don't remember whether
|
||||
* the comparePartialFn told us to stop early on a
|
||||
* previous page, we will uselessly apply comparePartialFn
|
||||
* to the first tuple on each subsequent page.
|
||||
*/
|
||||
key->entryRes[j] =
|
||||
matchPartialInPendingList(&so->ginstate,
|
||||
|
|
|
@ -97,7 +97,7 @@ createPostingTree(Relation index, ItemPointerData *items, uint32 nitems)
|
|||
* Adds array of item pointers to tuple's posting list, or
|
||||
* creates posting tree and tuple pointing to tree in case
|
||||
* of not enough space. Max size of tuple is defined in
|
||||
* GinFormTuple(). Returns a new, modified index tuple.
|
||||
* GinFormTuple(). Returns a new, modified index tuple.
|
||||
* items[] must be in sorted order with no duplicates.
|
||||
*/
|
||||
static IndexTuple
|
||||
|
@ -195,14 +195,14 @@ buildFreshLeafTuple(GinState *ginstate,
|
|||
BlockNumber postingRoot;
|
||||
|
||||
/*
|
||||
* Build posting-tree-only result tuple. We do this first so as
|
||||
* to fail quickly if the key is too big.
|
||||
* Build posting-tree-only result tuple. We do this first so as to
|
||||
* fail quickly if the key is too big.
|
||||
*/
|
||||
res = GinFormTuple(ginstate, attnum, key, category, NULL, 0, true);
|
||||
|
||||
/*
|
||||
* Initialize posting tree with as many TIDs as will fit on the
|
||||
* first page.
|
||||
* Initialize posting tree with as many TIDs as will fit on the first
|
||||
* page.
|
||||
*/
|
||||
postingRoot = createPostingTree(ginstate->index,
|
||||
items,
|
||||
|
@ -361,7 +361,7 @@ ginBuildCallback(Relation index, HeapTuple htup, Datum *values,
|
|||
|
||||
ginBeginBAScan(&buildstate->accum);
|
||||
while ((list = ginGetBAEntry(&buildstate->accum,
|
||||
&attnum, &key, &category, &nlist)) != NULL)
|
||||
&attnum, &key, &category, &nlist)) != NULL)
|
||||
{
|
||||
/* there could be many entries, so be willing to abort here */
|
||||
CHECK_FOR_INTERRUPTS();
|
||||
|
|
|
@ -199,7 +199,7 @@ ginFillScanKey(GinScanOpaque so, OffsetNumber attnum,
|
|||
break;
|
||||
default:
|
||||
elog(ERROR, "unexpected searchMode: %d", searchMode);
|
||||
queryCategory = 0; /* keep compiler quiet */
|
||||
queryCategory = 0; /* keep compiler quiet */
|
||||
break;
|
||||
}
|
||||
isPartialMatch = false;
|
||||
|
@ -294,8 +294,8 @@ ginNewScanKey(IndexScanDesc scan)
|
|||
int32 searchMode = GIN_SEARCH_MODE_DEFAULT;
|
||||
|
||||
/*
|
||||
* We assume that GIN-indexable operators are strict, so a null
|
||||
* query argument means an unsatisfiable query.
|
||||
* We assume that GIN-indexable operators are strict, so a null query
|
||||
* argument means an unsatisfiable query.
|
||||
*/
|
||||
if (skey->sk_flags & SK_ISNULL)
|
||||
{
|
||||
|
@ -315,8 +315,8 @@ ginNewScanKey(IndexScanDesc scan)
|
|||
PointerGetDatum(&searchMode)));
|
||||
|
||||
/*
|
||||
* If bogus searchMode is returned, treat as GIN_SEARCH_MODE_ALL;
|
||||
* note in particular we don't allow extractQueryFn to select
|
||||
* If bogus searchMode is returned, treat as GIN_SEARCH_MODE_ALL; note
|
||||
* in particular we don't allow extractQueryFn to select
|
||||
* GIN_SEARCH_MODE_EVERYTHING.
|
||||
*/
|
||||
if (searchMode < GIN_SEARCH_MODE_DEFAULT ||
|
||||
|
@ -344,20 +344,20 @@ ginNewScanKey(IndexScanDesc scan)
|
|||
* If the extractQueryFn didn't create a nullFlags array, create one,
|
||||
* assuming that everything's non-null. Otherwise, run through the
|
||||
* array and make sure each value is exactly 0 or 1; this ensures
|
||||
* binary compatibility with the GinNullCategory representation.
|
||||
* While at it, detect whether any null keys are present.
|
||||
* binary compatibility with the GinNullCategory representation. While
|
||||
* at it, detect whether any null keys are present.
|
||||
*/
|
||||
if (nullFlags == NULL)
|
||||
nullFlags = (bool *) palloc0(nQueryValues * sizeof(bool));
|
||||
else
|
||||
{
|
||||
int32 j;
|
||||
int32 j;
|
||||
|
||||
for (j = 0; j < nQueryValues; j++)
|
||||
{
|
||||
if (nullFlags[j])
|
||||
{
|
||||
nullFlags[j] = true; /* not any other nonzero value */
|
||||
nullFlags[j] = true; /* not any other nonzero value */
|
||||
hasNullQuery = true;
|
||||
}
|
||||
}
|
||||
|
@ -387,11 +387,11 @@ ginNewScanKey(IndexScanDesc scan)
|
|||
/*
|
||||
* If the index is version 0, it may be missing null and placeholder
|
||||
* entries, which would render searches for nulls and full-index scans
|
||||
* unreliable. Throw an error if so.
|
||||
* unreliable. Throw an error if so.
|
||||
*/
|
||||
if (hasNullQuery && !so->isVoidRes)
|
||||
{
|
||||
GinStatsData ginStats;
|
||||
GinStatsData ginStats;
|
||||
|
||||
ginGetStats(scan->indexRelation, &ginStats);
|
||||
if (ginStats.ginVersion < 1)
|
||||
|
@ -410,6 +410,7 @@ ginrescan(PG_FUNCTION_ARGS)
|
|||
{
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
ScanKey scankey = (ScanKey) PG_GETARG_POINTER(1);
|
||||
|
||||
/* remaining arguments are ignored */
|
||||
GinScanOpaque so = (GinScanOpaque) scan->opaque;
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ initGinState(GinState *state, Relation index)
|
|||
* However, we may have a collatable storage type for a noncollatable
|
||||
* indexed data type (for instance, hstore uses text index entries).
|
||||
* If there's no index collation then specify default collation in
|
||||
* case the comparison function needs one. This is harmless if the
|
||||
* case the comparison function needs one. This is harmless if the
|
||||
* comparison function doesn't care about collation, so we just do it
|
||||
* unconditionally. (We could alternatively call get_typcollation,
|
||||
* but that seems like expensive overkill --- there aren't going to be
|
||||
|
@ -359,9 +359,9 @@ cmpEntries(const void *a, const void *b, void *arg)
|
|||
aa->datum, bb->datum));
|
||||
|
||||
/*
|
||||
* Detect if we have any duplicates. If there are equal keys, qsort
|
||||
* must compare them at some point, else it wouldn't know whether one
|
||||
* should go before or after the other.
|
||||
* Detect if we have any duplicates. If there are equal keys, qsort must
|
||||
* compare them at some point, else it wouldn't know whether one should go
|
||||
* before or after the other.
|
||||
*/
|
||||
if (res == 0)
|
||||
data->haveDups = true;
|
||||
|
@ -422,9 +422,9 @@ ginExtractEntries(GinState *ginstate, OffsetNumber attnum,
|
|||
|
||||
/*
|
||||
* If the extractValueFn didn't create a nullFlags array, create one,
|
||||
* assuming that everything's non-null. Otherwise, run through the
|
||||
* array and make sure each value is exactly 0 or 1; this ensures
|
||||
* binary compatibility with the GinNullCategory representation.
|
||||
* assuming that everything's non-null. Otherwise, run through the array
|
||||
* and make sure each value is exactly 0 or 1; this ensures binary
|
||||
* compatibility with the GinNullCategory representation.
|
||||
*/
|
||||
if (nullFlags == NULL)
|
||||
nullFlags = (bool *) palloc0(*nentries * sizeof(bool));
|
||||
|
@ -440,8 +440,8 @@ ginExtractEntries(GinState *ginstate, OffsetNumber attnum,
|
|||
* If there's more than one key, sort and unique-ify.
|
||||
*
|
||||
* XXX Using qsort here is notationally painful, and the overhead is
|
||||
* pretty bad too. For small numbers of keys it'd likely be better to
|
||||
* use a simple insertion sort.
|
||||
* pretty bad too. For small numbers of keys it'd likely be better to use
|
||||
* a simple insertion sort.
|
||||
*/
|
||||
if (*nentries > 1)
|
||||
{
|
||||
|
@ -470,7 +470,7 @@ ginExtractEntries(GinState *ginstate, OffsetNumber attnum,
|
|||
j = 1;
|
||||
for (i = 1; i < *nentries; i++)
|
||||
{
|
||||
if (cmpEntries(&keydata[i-1], &keydata[i], &arg) != 0)
|
||||
if (cmpEntries(&keydata[i - 1], &keydata[i], &arg) != 0)
|
||||
{
|
||||
entries[j] = keydata[i].datum;
|
||||
nullFlags[j] = keydata[i].isnull;
|
||||
|
@ -533,9 +533,9 @@ ginoptions(PG_FUNCTION_ARGS)
|
|||
void
|
||||
ginGetStats(Relation index, GinStatsData *stats)
|
||||
{
|
||||
Buffer metabuffer;
|
||||
Page metapage;
|
||||
GinMetaPageData *metadata;
|
||||
Buffer metabuffer;
|
||||
Page metapage;
|
||||
GinMetaPageData *metadata;
|
||||
|
||||
metabuffer = ReadBuffer(index, GIN_METAPAGE_BLKNO);
|
||||
LockBuffer(metabuffer, GIN_SHARE);
|
||||
|
@ -560,9 +560,9 @@ ginGetStats(Relation index, GinStatsData *stats)
|
|||
void
|
||||
ginUpdateStats(Relation index, const GinStatsData *stats)
|
||||
{
|
||||
Buffer metabuffer;
|
||||
Page metapage;
|
||||
GinMetaPageData *metadata;
|
||||
Buffer metabuffer;
|
||||
Page metapage;
|
||||
GinMetaPageData *metadata;
|
||||
|
||||
metabuffer = ReadBuffer(index, GIN_METAPAGE_BLKNO);
|
||||
LockBuffer(metabuffer, GIN_EXCLUSIVE);
|
||||
|
@ -580,9 +580,9 @@ ginUpdateStats(Relation index, const GinStatsData *stats)
|
|||
|
||||
if (RelationNeedsWAL(index))
|
||||
{
|
||||
XLogRecPtr recptr;
|
||||
ginxlogUpdateMeta data;
|
||||
XLogRecData rdata;
|
||||
XLogRecPtr recptr;
|
||||
ginxlogUpdateMeta data;
|
||||
XLogRecData rdata;
|
||||
|
||||
data.node = index->rd_node;
|
||||
data.ntuples = 0;
|
||||
|
|
|
@ -783,7 +783,7 @@ ginvacuumcleanup(PG_FUNCTION_ARGS)
|
|||
{
|
||||
idxStat.nEntryPages++;
|
||||
|
||||
if ( GinPageIsLeaf(page) )
|
||||
if (GinPageIsLeaf(page))
|
||||
idxStat.nEntries += PageGetMaxOffsetNumber(page);
|
||||
}
|
||||
|
||||
|
|
|
@ -388,7 +388,7 @@ ginRedoVacuumPage(XLogRecPtr lsn, XLogRecord *record)
|
|||
else
|
||||
{
|
||||
OffsetNumber i,
|
||||
*tod;
|
||||
*tod;
|
||||
IndexTuple itup = (IndexTuple) (XLogRecGetData(record) + sizeof(ginxlogVacuumPage));
|
||||
|
||||
tod = (OffsetNumber *) palloc(sizeof(OffsetNumber) * PageGetMaxOffsetNumber(page));
|
||||
|
@ -513,10 +513,10 @@ ginRedoUpdateMetapage(XLogRecPtr lsn, XLogRecord *record)
|
|||
if (!XLByteLE(lsn, PageGetLSN(page)))
|
||||
{
|
||||
OffsetNumber l,
|
||||
off = (PageIsEmpty(page)) ? FirstOffsetNumber :
|
||||
OffsetNumberNext(PageGetMaxOffsetNumber(page));
|
||||
off = (PageIsEmpty(page)) ? FirstOffsetNumber :
|
||||
OffsetNumberNext(PageGetMaxOffsetNumber(page));
|
||||
int i,
|
||||
tupsize;
|
||||
tupsize;
|
||||
IndexTuple tuples = (IndexTuple) (XLogRecGetData(record) + sizeof(ginxlogUpdateMeta));
|
||||
|
||||
for (i = 0; i < data->ntuples; i++)
|
||||
|
|
|
@ -34,8 +34,8 @@ typedef struct
|
|||
/* A List of these is used represent a split-in-progress. */
|
||||
typedef struct
|
||||
{
|
||||
Buffer buf; /* the split page "half" */
|
||||
IndexTuple downlink; /* downlink for this half. */
|
||||
Buffer buf; /* the split page "half" */
|
||||
IndexTuple downlink; /* downlink for this half. */
|
||||
} GISTPageSplitInfo;
|
||||
|
||||
/* non-export function prototypes */
|
||||
|
@ -306,13 +306,13 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate,
|
|||
bool is_split;
|
||||
|
||||
/*
|
||||
* Refuse to modify a page that's incompletely split. This should
|
||||
* not happen because we finish any incomplete splits while we walk
|
||||
* down the tree. However, it's remotely possible that another
|
||||
* concurrent inserter splits a parent page, and errors out before
|
||||
* completing the split. We will just throw an error in that case,
|
||||
* and leave any split we had in progress unfinished too. The next
|
||||
* insert that comes along will clean up the mess.
|
||||
* Refuse to modify a page that's incompletely split. This should not
|
||||
* happen because we finish any incomplete splits while we walk down the
|
||||
* tree. However, it's remotely possible that another concurrent inserter
|
||||
* splits a parent page, and errors out before completing the split. We
|
||||
* will just throw an error in that case, and leave any split we had in
|
||||
* progress unfinished too. The next insert that comes along will clean up
|
||||
* the mess.
|
||||
*/
|
||||
if (GistFollowRight(page))
|
||||
elog(ERROR, "concurrent GiST page split was incomplete");
|
||||
|
@ -338,7 +338,7 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate,
|
|||
SplitedPageLayout *dist = NULL,
|
||||
*ptr;
|
||||
BlockNumber oldrlink = InvalidBlockNumber;
|
||||
GistNSN oldnsn = { 0, 0 };
|
||||
GistNSN oldnsn = {0, 0};
|
||||
SplitedPageLayout rootpg;
|
||||
BlockNumber blkno = BufferGetBlockNumber(buffer);
|
||||
bool is_rootsplit;
|
||||
|
@ -364,8 +364,8 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate,
|
|||
|
||||
/*
|
||||
* Set up pages to work with. Allocate new buffers for all but the
|
||||
* leftmost page. The original page becomes the new leftmost page,
|
||||
* and is just replaced with the new contents.
|
||||
* leftmost page. The original page becomes the new leftmost page, and
|
||||
* is just replaced with the new contents.
|
||||
*
|
||||
* For a root-split, allocate new buffers for all child pages, the
|
||||
* original page is overwritten with new root page containing
|
||||
|
@ -414,8 +414,8 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate,
|
|||
if (is_rootsplit)
|
||||
{
|
||||
IndexTuple *downlinks;
|
||||
int ndownlinks = 0;
|
||||
int i;
|
||||
int ndownlinks = 0;
|
||||
int i;
|
||||
|
||||
rootpg.buffer = buffer;
|
||||
rootpg.page = PageGetTempPageCopySpecial(BufferGetPage(rootpg.buffer));
|
||||
|
@ -443,6 +443,7 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate,
|
|||
for (ptr = dist; ptr; ptr = ptr->next)
|
||||
{
|
||||
GISTPageSplitInfo *si = palloc(sizeof(GISTPageSplitInfo));
|
||||
|
||||
si->buf = ptr->buffer;
|
||||
si->downlink = ptr->itup;
|
||||
*splitinfo = lappend(*splitinfo, si);
|
||||
|
@ -455,7 +456,8 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate,
|
|||
*/
|
||||
for (ptr = dist; ptr; ptr = ptr->next)
|
||||
{
|
||||
char *data = (char *) (ptr->list);
|
||||
char *data = (char *) (ptr->list);
|
||||
|
||||
for (i = 0; i < ptr->block.num; i++)
|
||||
{
|
||||
if (PageAddItem(ptr->page, (Item) data, IndexTupleSize((IndexTuple) data), i + FirstOffsetNumber, false, false) == InvalidOffsetNumber)
|
||||
|
@ -495,8 +497,8 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate,
|
|||
MarkBufferDirty(leftchildbuf);
|
||||
|
||||
/*
|
||||
* The first page in the chain was a temporary working copy meant
|
||||
* to replace the old page. Copy it over the old page.
|
||||
* The first page in the chain was a temporary working copy meant to
|
||||
* replace the old page. Copy it over the old page.
|
||||
*/
|
||||
PageRestoreTempPage(dist->page, BufferGetPage(dist->buffer));
|
||||
dist->page = BufferGetPage(dist->buffer);
|
||||
|
@ -518,8 +520,8 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate,
|
|||
* Return the new child buffers to the caller.
|
||||
*
|
||||
* If this was a root split, we've already inserted the downlink
|
||||
* pointers, in the form of a new root page. Therefore we can
|
||||
* release all the new buffers, and keep just the root page locked.
|
||||
* pointers, in the form of a new root page. Therefore we can release
|
||||
* all the new buffers, and keep just the root page locked.
|
||||
*/
|
||||
if (is_rootsplit)
|
||||
{
|
||||
|
@ -572,20 +574,20 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate,
|
|||
|
||||
/*
|
||||
* If we inserted the downlink for a child page, set NSN and clear
|
||||
* F_FOLLOW_RIGHT flag on the left child, so that concurrent scans know
|
||||
* to follow the rightlink if and only if they looked at the parent page
|
||||
* F_FOLLOW_RIGHT flag on the left child, so that concurrent scans know to
|
||||
* follow the rightlink if and only if they looked at the parent page
|
||||
* before we inserted the downlink.
|
||||
*
|
||||
* Note that we do this *after* writing the WAL record. That means that
|
||||
* the possible full page image in the WAL record does not include
|
||||
* these changes, and they must be replayed even if the page is restored
|
||||
* from the full page image. There's a chicken-and-egg problem: if we
|
||||
* updated the child pages first, we wouldn't know the recptr of the WAL
|
||||
* record we're about to write.
|
||||
* the possible full page image in the WAL record does not include these
|
||||
* changes, and they must be replayed even if the page is restored from
|
||||
* the full page image. There's a chicken-and-egg problem: if we updated
|
||||
* the child pages first, we wouldn't know the recptr of the WAL record
|
||||
* we're about to write.
|
||||
*/
|
||||
if (BufferIsValid(leftchildbuf))
|
||||
{
|
||||
Page leftpg = BufferGetPage(leftchildbuf);
|
||||
Page leftpg = BufferGetPage(leftchildbuf);
|
||||
|
||||
GistPageGetOpaque(leftpg)->nsn = recptr;
|
||||
GistClearFollowRight(leftpg);
|
||||
|
@ -636,8 +638,8 @@ gistdoinsert(Relation r, IndexTuple itup, Size freespace, GISTSTATE *giststate)
|
|||
stack->buffer = ReadBuffer(state.r, stack->blkno);
|
||||
|
||||
/*
|
||||
* Be optimistic and grab shared lock first. Swap it for an
|
||||
* exclusive lock later if we need to update the page.
|
||||
* Be optimistic and grab shared lock first. Swap it for an exclusive
|
||||
* lock later if we need to update the page.
|
||||
*/
|
||||
if (!xlocked)
|
||||
{
|
||||
|
@ -650,9 +652,9 @@ gistdoinsert(Relation r, IndexTuple itup, Size freespace, GISTSTATE *giststate)
|
|||
Assert(!RelationNeedsWAL(state.r) || !XLogRecPtrIsInvalid(stack->lsn));
|
||||
|
||||
/*
|
||||
* If this page was split but the downlink was never inserted to
|
||||
* the parent because the inserting backend crashed before doing
|
||||
* that, fix that now.
|
||||
* If this page was split but the downlink was never inserted to the
|
||||
* parent because the inserting backend crashed before doing that, fix
|
||||
* that now.
|
||||
*/
|
||||
if (GistFollowRight(stack->page))
|
||||
{
|
||||
|
@ -680,8 +682,8 @@ gistdoinsert(Relation r, IndexTuple itup, Size freespace, GISTSTATE *giststate)
|
|||
/*
|
||||
* Concurrent split detected. There's no guarantee that the
|
||||
* downlink for this page is consistent with the tuple we're
|
||||
* inserting anymore, so go back to parent and rechoose the
|
||||
* best child.
|
||||
* inserting anymore, so go back to parent and rechoose the best
|
||||
* child.
|
||||
*/
|
||||
UnlockReleaseBuffer(stack->buffer);
|
||||
xlocked = false;
|
||||
|
@ -696,7 +698,7 @@ gistdoinsert(Relation r, IndexTuple itup, Size freespace, GISTSTATE *giststate)
|
|||
* Find the child node that has the minimum insertion penalty.
|
||||
*/
|
||||
BlockNumber childblkno;
|
||||
IndexTuple newtup;
|
||||
IndexTuple newtup;
|
||||
GISTInsertStack *item;
|
||||
|
||||
stack->childoffnum = gistchoose(state.r, stack->page, itup, giststate);
|
||||
|
@ -722,8 +724,8 @@ gistdoinsert(Relation r, IndexTuple itup, Size freespace, GISTSTATE *giststate)
|
|||
if (newtup)
|
||||
{
|
||||
/*
|
||||
* Swap shared lock for an exclusive one. Beware, the page
|
||||
* may change while we unlock/lock the page...
|
||||
* Swap shared lock for an exclusive one. Beware, the page may
|
||||
* change while we unlock/lock the page...
|
||||
*/
|
||||
if (!xlocked)
|
||||
{
|
||||
|
@ -738,6 +740,7 @@ gistdoinsert(Relation r, IndexTuple itup, Size freespace, GISTSTATE *giststate)
|
|||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the tuple.
|
||||
*
|
||||
|
@ -752,8 +755,8 @@ gistdoinsert(Relation r, IndexTuple itup, Size freespace, GISTSTATE *giststate)
|
|||
stack->childoffnum, InvalidBuffer))
|
||||
{
|
||||
/*
|
||||
* If this was a root split, the root page continues to
|
||||
* be the parent and the updated tuple went to one of the
|
||||
* If this was a root split, the root page continues to be
|
||||
* the parent and the updated tuple went to one of the
|
||||
* child pages, so we just need to retry from the root
|
||||
* page.
|
||||
*/
|
||||
|
@ -779,13 +782,13 @@ gistdoinsert(Relation r, IndexTuple itup, Size freespace, GISTSTATE *giststate)
|
|||
{
|
||||
/*
|
||||
* Leaf page. Insert the new key. We've already updated all the
|
||||
* parents on the way down, but we might have to split the page
|
||||
* if it doesn't fit. gistinserthere() will take care of that.
|
||||
* parents on the way down, but we might have to split the page if
|
||||
* it doesn't fit. gistinserthere() will take care of that.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Swap shared lock for an exclusive one. Be careful, the page
|
||||
* may change while we unlock/lock the page...
|
||||
* Swap shared lock for an exclusive one. Be careful, the page may
|
||||
* change while we unlock/lock the page...
|
||||
*/
|
||||
if (!xlocked)
|
||||
{
|
||||
|
@ -798,8 +801,8 @@ gistdoinsert(Relation r, IndexTuple itup, Size freespace, GISTSTATE *giststate)
|
|||
if (stack->blkno == GIST_ROOT_BLKNO)
|
||||
{
|
||||
/*
|
||||
* the only page that can become inner instead of leaf
|
||||
* is the root page, so for root we should recheck it
|
||||
* the only page that can become inner instead of leaf is
|
||||
* the root page, so for root we should recheck it
|
||||
*/
|
||||
if (!GistPageIsLeaf(stack->page))
|
||||
{
|
||||
|
@ -1059,21 +1062,23 @@ static IndexTuple
|
|||
gistformdownlink(Relation rel, Buffer buf, GISTSTATE *giststate,
|
||||
GISTInsertStack *stack)
|
||||
{
|
||||
Page page = BufferGetPage(buf);
|
||||
Page page = BufferGetPage(buf);
|
||||
OffsetNumber maxoff;
|
||||
OffsetNumber offset;
|
||||
IndexTuple downlink = NULL;
|
||||
IndexTuple downlink = NULL;
|
||||
|
||||
maxoff = PageGetMaxOffsetNumber(page);
|
||||
for (offset = FirstOffsetNumber; offset <= maxoff; offset = OffsetNumberNext(offset))
|
||||
{
|
||||
IndexTuple ituple = (IndexTuple)
|
||||
PageGetItem(page, PageGetItemId(page, offset));
|
||||
PageGetItem(page, PageGetItemId(page, offset));
|
||||
|
||||
if (downlink == NULL)
|
||||
downlink = CopyIndexTuple(ituple);
|
||||
else
|
||||
{
|
||||
IndexTuple newdownlink;
|
||||
IndexTuple newdownlink;
|
||||
|
||||
newdownlink = gistgetadjusted(rel, downlink, ituple,
|
||||
giststate);
|
||||
if (newdownlink)
|
||||
|
@ -1082,19 +1087,18 @@ gistformdownlink(Relation rel, Buffer buf, GISTSTATE *giststate,
|
|||
}
|
||||
|
||||
/*
|
||||
* If the page is completely empty, we can't form a meaningful
|
||||
* downlink for it. But we have to insert a downlink for the page.
|
||||
* Any key will do, as long as its consistent with the downlink of
|
||||
* parent page, so that we can legally insert it to the parent.
|
||||
* A minimal one that matches as few scans as possible would be best,
|
||||
* to keep scans from doing useless work, but we don't know how to
|
||||
* construct that. So we just use the downlink of the original page
|
||||
* that was split - that's as far from optimal as it can get but will
|
||||
* do..
|
||||
* If the page is completely empty, we can't form a meaningful downlink
|
||||
* for it. But we have to insert a downlink for the page. Any key will do,
|
||||
* as long as its consistent with the downlink of parent page, so that we
|
||||
* can legally insert it to the parent. A minimal one that matches as few
|
||||
* scans as possible would be best, to keep scans from doing useless work,
|
||||
* but we don't know how to construct that. So we just use the downlink of
|
||||
* the original page that was split - that's as far from optimal as it can
|
||||
* get but will do..
|
||||
*/
|
||||
if (!downlink)
|
||||
{
|
||||
ItemId iid;
|
||||
ItemId iid;
|
||||
|
||||
LockBuffer(stack->parent->buffer, GIST_EXCLUSIVE);
|
||||
gistFindCorrectParent(rel, stack);
|
||||
|
@ -1131,13 +1135,13 @@ gistfixsplit(GISTInsertState *state, GISTSTATE *giststate)
|
|||
buf = stack->buffer;
|
||||
|
||||
/*
|
||||
* Read the chain of split pages, following the rightlinks. Construct
|
||||
* a downlink tuple for each page.
|
||||
* Read the chain of split pages, following the rightlinks. Construct a
|
||||
* downlink tuple for each page.
|
||||
*/
|
||||
for (;;)
|
||||
{
|
||||
GISTPageSplitInfo *si = palloc(sizeof(GISTPageSplitInfo));
|
||||
IndexTuple downlink;
|
||||
IndexTuple downlink;
|
||||
|
||||
page = BufferGetPage(buf);
|
||||
|
||||
|
@ -1182,8 +1186,8 @@ gistinserttuples(GISTInsertState *state, GISTInsertStack *stack,
|
|||
IndexTuple *tuples, int ntup, OffsetNumber oldoffnum,
|
||||
Buffer leftchild)
|
||||
{
|
||||
List *splitinfo;
|
||||
bool is_split;
|
||||
List *splitinfo;
|
||||
bool is_split;
|
||||
|
||||
is_split = gistplacetopage(state, giststate, stack->buffer,
|
||||
tuples, ntup, oldoffnum,
|
||||
|
@ -1204,21 +1208,21 @@ static void
|
|||
gistfinishsplit(GISTInsertState *state, GISTInsertStack *stack,
|
||||
GISTSTATE *giststate, List *splitinfo)
|
||||
{
|
||||
ListCell *lc;
|
||||
List *reversed;
|
||||
ListCell *lc;
|
||||
List *reversed;
|
||||
GISTPageSplitInfo *right;
|
||||
GISTPageSplitInfo *left;
|
||||
IndexTuple tuples[2];
|
||||
IndexTuple tuples[2];
|
||||
|
||||
/* A split always contains at least two halves */
|
||||
Assert(list_length(splitinfo) >= 2);
|
||||
|
||||
/*
|
||||
* We need to insert downlinks for each new page, and update the
|
||||
* downlink for the original (leftmost) page in the split. Begin at
|
||||
* the rightmost page, inserting one downlink at a time until there's
|
||||
* only two pages left. Finally insert the downlink for the last new
|
||||
* page and update the downlink for the original page as one operation.
|
||||
* We need to insert downlinks for each new page, and update the downlink
|
||||
* for the original (leftmost) page in the split. Begin at the rightmost
|
||||
* page, inserting one downlink at a time until there's only two pages
|
||||
* left. Finally insert the downlink for the last new page and update the
|
||||
* downlink for the original page as one operation.
|
||||
*/
|
||||
|
||||
/* for convenience, create a copy of the list in reverse order */
|
||||
|
@ -1231,7 +1235,7 @@ gistfinishsplit(GISTInsertState *state, GISTInsertStack *stack,
|
|||
LockBuffer(stack->parent->buffer, GIST_EXCLUSIVE);
|
||||
gistFindCorrectParent(state->r, stack);
|
||||
|
||||
while(list_length(reversed) > 2)
|
||||
while (list_length(reversed) > 2)
|
||||
{
|
||||
right = (GISTPageSplitInfo *) linitial(reversed);
|
||||
left = (GISTPageSplitInfo *) lsecond(reversed);
|
||||
|
@ -1386,7 +1390,7 @@ initGISTstate(GISTSTATE *giststate, Relation index)
|
|||
/* opclasses are not required to provide a Distance method */
|
||||
if (OidIsValid(index_getprocid(index, i + 1, GIST_DISTANCE_PROC)))
|
||||
fmgr_info_copy(&(giststate->distanceFn[i]),
|
||||
index_getprocinfo(index, i + 1, GIST_DISTANCE_PROC),
|
||||
index_getprocinfo(index, i + 1, GIST_DISTANCE_PROC),
|
||||
CurrentMemoryContext);
|
||||
else
|
||||
giststate->distanceFn[i].fn_oid = InvalidOid;
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
*
|
||||
* On success return for a heap tuple, *recheck_p is set to indicate
|
||||
* whether recheck is needed. We recheck if any of the consistent() functions
|
||||
* request it. recheck is not interesting when examining a non-leaf entry,
|
||||
* request it. recheck is not interesting when examining a non-leaf entry,
|
||||
* since we must visit the lower index page if there's any doubt.
|
||||
*
|
||||
* If we are doing an ordered scan, so->distances[] is filled with distance
|
||||
|
@ -62,15 +62,15 @@ gistindex_keytest(IndexScanDesc scan,
|
|||
*recheck_p = false;
|
||||
|
||||
/*
|
||||
* If it's a leftover invalid tuple from pre-9.1, treat it as a match
|
||||
* with minimum possible distances. This means we'll always follow it
|
||||
* to the referenced page.
|
||||
* If it's a leftover invalid tuple from pre-9.1, treat it as a match with
|
||||
* minimum possible distances. This means we'll always follow it to the
|
||||
* referenced page.
|
||||
*/
|
||||
if (GistTupleIsInvalid(tuple))
|
||||
{
|
||||
int i;
|
||||
int i;
|
||||
|
||||
if (GistPageIsLeaf(page)) /* shouldn't happen */
|
||||
if (GistPageIsLeaf(page)) /* shouldn't happen */
|
||||
elog(ERROR, "invalid GIST tuple found on leaf page");
|
||||
for (i = 0; i < scan->numberOfOrderBys; i++)
|
||||
so->distances[i] = -get_float8_infinity();
|
||||
|
@ -191,8 +191,8 @@ gistindex_keytest(IndexScanDesc scan,
|
|||
* always be zero, but might as well pass it for possible future
|
||||
* use.)
|
||||
*
|
||||
* Note that Distance functions don't get a recheck argument.
|
||||
* We can't tolerate lossy distance calculations on leaf tuples;
|
||||
* Note that Distance functions don't get a recheck argument. We
|
||||
* can't tolerate lossy distance calculations on leaf tuples;
|
||||
* there is no opportunity to re-sort the tuples afterwards.
|
||||
*/
|
||||
dist = FunctionCall4(&key->sk_func,
|
||||
|
@ -223,7 +223,7 @@ gistindex_keytest(IndexScanDesc scan,
|
|||
* ntids: if not NULL, gistgetbitmap's output tuple counter
|
||||
*
|
||||
* If tbm/ntids aren't NULL, we are doing an amgetbitmap scan, and heap
|
||||
* tuples should be reported directly into the bitmap. If they are NULL,
|
||||
* tuples should be reported directly into the bitmap. If they are NULL,
|
||||
* we're doing a plain or ordered indexscan. For a plain indexscan, heap
|
||||
* tuple TIDs are returned into so->pageData[]. For an ordered indexscan,
|
||||
* heap tuple TIDs are pushed into individual search queue items.
|
||||
|
@ -525,8 +525,8 @@ gistgettuple(PG_FUNCTION_ARGS)
|
|||
/*
|
||||
* While scanning a leaf page, ItemPointers of matching heap
|
||||
* tuples are stored in so->pageData. If there are any on
|
||||
* this page, we fall out of the inner "do" and loop around
|
||||
* to return them.
|
||||
* this page, we fall out of the inner "do" and loop around to
|
||||
* return them.
|
||||
*/
|
||||
gistScanPage(scan, item, so->curTreeItem->distances, NULL, NULL);
|
||||
|
||||
|
|
|
@ -904,7 +904,7 @@ gist_point_compress(PG_FUNCTION_ARGS)
|
|||
PG_RETURN_POINTER(entry);
|
||||
}
|
||||
|
||||
#define point_point_distance(p1,p2) \
|
||||
#define point_point_distance(p1,p2) \
|
||||
DatumGetFloat8(DirectFunctionCall2(point_distance, \
|
||||
PointPGetDatum(p1), PointPGetDatum(p2)))
|
||||
|
||||
|
@ -949,8 +949,8 @@ computeDistance(bool isLeaf, BOX *box, Point *point)
|
|||
else
|
||||
{
|
||||
/* closest point will be a vertex */
|
||||
Point p;
|
||||
double subresult;
|
||||
Point p;
|
||||
double subresult;
|
||||
|
||||
result = point_point_distance(point, &box->low);
|
||||
|
||||
|
|
|
@ -57,9 +57,9 @@ GISTSearchTreeItemCombiner(RBNode *existing, const RBNode *newrb, void *arg)
|
|||
|
||||
/*
|
||||
* If new item is heap tuple, it goes to front of chain; otherwise insert
|
||||
* it before the first index-page item, so that index pages are visited
|
||||
* in LIFO order, ensuring depth-first search of index pages. See
|
||||
* comments in gist_private.h.
|
||||
* it before the first index-page item, so that index pages are visited in
|
||||
* LIFO order, ensuring depth-first search of index pages. See comments
|
||||
* in gist_private.h.
|
||||
*/
|
||||
if (GISTSearchItemIsHeap(*newitem))
|
||||
{
|
||||
|
@ -136,6 +136,7 @@ gistrescan(PG_FUNCTION_ARGS)
|
|||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
ScanKey key = (ScanKey) PG_GETARG_POINTER(1);
|
||||
ScanKey orderbys = (ScanKey) PG_GETARG_POINTER(3);
|
||||
|
||||
/* nkeys and norderbys arguments are ignored */
|
||||
GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
|
||||
int i;
|
||||
|
@ -164,8 +165,8 @@ gistrescan(PG_FUNCTION_ARGS)
|
|||
scan->numberOfKeys * sizeof(ScanKeyData));
|
||||
|
||||
/*
|
||||
* Modify the scan key so that the Consistent method is called for
|
||||
* all comparisons. The original operator is passed to the Consistent
|
||||
* Modify the scan key so that the Consistent method is called for all
|
||||
* comparisons. The original operator is passed to the Consistent
|
||||
* function in the form of its strategy number, which is available
|
||||
* from the sk_strategy field, and its subtype from the sk_subtype
|
||||
* field. Also, preserve sk_func.fn_collation which is the input
|
||||
|
|
|
@ -503,11 +503,12 @@ gistFormTuple(GISTSTATE *giststate, Relation r,
|
|||
}
|
||||
|
||||
res = index_form_tuple(giststate->tupdesc, compatt, isnull);
|
||||
|
||||
/*
|
||||
* The offset number on tuples on internal pages is unused. For historical
|
||||
* reasons, it is set 0xffff.
|
||||
*/
|
||||
ItemPointerSetOffsetNumber( &(res->t_tid), 0xffff);
|
||||
ItemPointerSetOffsetNumber(&(res->t_tid), 0xffff);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,12 +41,12 @@ static void
|
|||
gistRedoClearFollowRight(RelFileNode node, XLogRecPtr lsn,
|
||||
BlockNumber leftblkno)
|
||||
{
|
||||
Buffer buffer;
|
||||
Buffer buffer;
|
||||
|
||||
buffer = XLogReadBuffer(node, leftblkno, false);
|
||||
if (BufferIsValid(buffer))
|
||||
{
|
||||
Page page = (Page) BufferGetPage(buffer);
|
||||
Page page = (Page) BufferGetPage(buffer);
|
||||
|
||||
/*
|
||||
* Note that we still update the page even if page LSN is equal to the
|
||||
|
@ -103,6 +103,7 @@ gistRedoPageUpdateRecord(XLogRecPtr lsn, XLogRecord *record)
|
|||
{
|
||||
int i;
|
||||
OffsetNumber *todelete = (OffsetNumber *) data;
|
||||
|
||||
data += sizeof(OffsetNumber) * xldata->ntodelete;
|
||||
|
||||
for (i = 0; i < xldata->ntodelete; i++)
|
||||
|
@ -115,12 +116,14 @@ gistRedoPageUpdateRecord(XLogRecPtr lsn, XLogRecord *record)
|
|||
if (data - begin < record->xl_len)
|
||||
{
|
||||
OffsetNumber off = (PageIsEmpty(page)) ? FirstOffsetNumber :
|
||||
OffsetNumberNext(PageGetMaxOffsetNumber(page));
|
||||
OffsetNumberNext(PageGetMaxOffsetNumber(page));
|
||||
|
||||
while (data - begin < record->xl_len)
|
||||
{
|
||||
IndexTuple itup = (IndexTuple) data;
|
||||
IndexTuple itup = (IndexTuple) data;
|
||||
Size sz = IndexTupleSize(itup);
|
||||
OffsetNumber l;
|
||||
|
||||
data += sz;
|
||||
|
||||
l = PageAddItem(page, (Item) itup, sz, off, false, false);
|
||||
|
@ -418,7 +421,7 @@ gistXLogSplit(RelFileNode node, BlockNumber blkno, bool page_is_leaf,
|
|||
SplitedPageLayout *ptr;
|
||||
int npage = 0,
|
||||
cur;
|
||||
XLogRecPtr recptr;
|
||||
XLogRecPtr recptr;
|
||||
|
||||
for (ptr = dist; ptr; ptr = ptr->next)
|
||||
npage++;
|
||||
|
@ -540,8 +543,8 @@ gistXLogUpdate(RelFileNode node, Buffer buffer,
|
|||
}
|
||||
|
||||
/*
|
||||
* Include a full page image of the child buf. (only necessary if
|
||||
* a checkpoint happened since the child page was split)
|
||||
* Include a full page image of the child buf. (only necessary if a
|
||||
* checkpoint happened since the child page was split)
|
||||
*/
|
||||
if (BufferIsValid(leftchildbuf))
|
||||
{
|
||||
|
|
|
@ -413,6 +413,7 @@ hashrescan(PG_FUNCTION_ARGS)
|
|||
{
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
ScanKey scankey = (ScanKey) PG_GETARG_POINTER(1);
|
||||
|
||||
/* remaining arguments are ignored */
|
||||
HashScanOpaque so = (HashScanOpaque) scan->opaque;
|
||||
Relation rel = scan->indexRelation;
|
||||
|
|
|
@ -1070,7 +1070,7 @@ relation_close(Relation relation, LOCKMODE lockmode)
|
|||
* This is essentially relation_open plus check that the relation
|
||||
* is not an index nor a composite type. (The caller should also
|
||||
* check that it's not a view or foreign table before assuming it has
|
||||
* storage.)
|
||||
* storage.)
|
||||
* ----------------
|
||||
*/
|
||||
Relation
|
||||
|
@ -1922,8 +1922,8 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
|
|||
|
||||
/*
|
||||
* We're about to do the actual insert -- check for conflict at the
|
||||
* relation or buffer level first, to avoid possibly having to roll
|
||||
* back work we've just done.
|
||||
* relation or buffer level first, to avoid possibly having to roll back
|
||||
* work we've just done.
|
||||
*/
|
||||
CheckForSerializableConflictIn(relation, NULL, buffer);
|
||||
|
||||
|
@ -2228,8 +2228,8 @@ l1:
|
|||
}
|
||||
|
||||
/*
|
||||
* We're about to do the actual delete -- check for conflict first,
|
||||
* to avoid possibly having to roll back work we've just done.
|
||||
* We're about to do the actual delete -- check for conflict first, to
|
||||
* avoid possibly having to roll back work we've just done.
|
||||
*/
|
||||
CheckForSerializableConflictIn(relation, &tp, buffer);
|
||||
|
||||
|
@ -2587,8 +2587,8 @@ l2:
|
|||
}
|
||||
|
||||
/*
|
||||
* We're about to do the actual update -- check for conflict first,
|
||||
* to avoid possibly having to roll back work we've just done.
|
||||
* We're about to do the actual update -- check for conflict first, to
|
||||
* avoid possibly having to roll back work we've just done.
|
||||
*/
|
||||
CheckForSerializableConflictIn(relation, &oldtup, buffer);
|
||||
|
||||
|
@ -2737,8 +2737,8 @@ l2:
|
|||
}
|
||||
|
||||
/*
|
||||
* We're about to create the new tuple -- check for conflict first,
|
||||
* to avoid possibly having to roll back work we've just done.
|
||||
* We're about to create the new tuple -- check for conflict first, to
|
||||
* avoid possibly having to roll back work we've just done.
|
||||
*
|
||||
* NOTE: For a tuple insert, we only need to check for table locks, since
|
||||
* predicate locking at the index level will cover ranges for anything
|
||||
|
@ -3860,12 +3860,12 @@ HeapTupleHeaderAdvanceLatestRemovedXid(HeapTupleHeader tuple,
|
|||
}
|
||||
|
||||
/*
|
||||
* Ignore tuples inserted by an aborted transaction or
|
||||
* if the tuple was updated/deleted by the inserting transaction.
|
||||
* Ignore tuples inserted by an aborted transaction or if the tuple was
|
||||
* updated/deleted by the inserting transaction.
|
||||
*
|
||||
* Look for a committed hint bit, or if no xmin bit is set, check clog.
|
||||
* This needs to work on both master and standby, where it is used
|
||||
* to assess btree delete records.
|
||||
* This needs to work on both master and standby, where it is used to
|
||||
* assess btree delete records.
|
||||
*/
|
||||
if ((tuple->t_infomask & HEAP_XMIN_COMMITTED) ||
|
||||
(!(tuple->t_infomask & HEAP_XMIN_COMMITTED) &&
|
||||
|
@ -3874,7 +3874,7 @@ HeapTupleHeaderAdvanceLatestRemovedXid(HeapTupleHeader tuple,
|
|||
{
|
||||
if (xmax != xmin &&
|
||||
TransactionIdFollows(xmax, *latestRemovedXid))
|
||||
*latestRemovedXid = xmax;
|
||||
*latestRemovedXid = xmax;
|
||||
}
|
||||
|
||||
/* *latestRemovedXid may still be invalid at end */
|
||||
|
@ -4158,8 +4158,8 @@ log_newpage(RelFileNode *rnode, ForkNumber forkNum, BlockNumber blkno,
|
|||
recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_NEWPAGE, rdata);
|
||||
|
||||
/*
|
||||
* The page may be uninitialized. If so, we can't set the LSN
|
||||
* and TLI because that would corrupt the page.
|
||||
* The page may be uninitialized. If so, we can't set the LSN and TLI
|
||||
* because that would corrupt the page.
|
||||
*/
|
||||
if (!PageIsNew(page))
|
||||
{
|
||||
|
@ -4352,8 +4352,8 @@ heap_xlog_newpage(XLogRecPtr lsn, XLogRecord *record)
|
|||
memcpy(page, (char *) xlrec + SizeOfHeapNewpage, BLCKSZ);
|
||||
|
||||
/*
|
||||
* The page may be uninitialized. If so, we can't set the LSN
|
||||
* and TLI because that would corrupt the page.
|
||||
* The page may be uninitialized. If so, we can't set the LSN and TLI
|
||||
* because that would corrupt the page.
|
||||
*/
|
||||
if (!PageIsNew(page))
|
||||
{
|
||||
|
|
|
@ -150,7 +150,7 @@ ReadBufferBI(Relation relation, BlockNumber targetBlock,
|
|||
Buffer
|
||||
RelationGetBufferForTuple(Relation relation, Size len,
|
||||
Buffer otherBuffer, int options,
|
||||
struct BulkInsertStateData *bistate)
|
||||
struct BulkInsertStateData * bistate)
|
||||
{
|
||||
bool use_fsm = !(options & HEAP_INSERT_SKIP_FSM);
|
||||
Buffer buffer = InvalidBuffer;
|
||||
|
|
|
@ -131,7 +131,7 @@ typedef struct RewriteStateData
|
|||
* them */
|
||||
HTAB *rs_unresolved_tups; /* unmatched A tuples */
|
||||
HTAB *rs_old_new_tid_map; /* unmatched B tuples */
|
||||
} RewriteStateData;
|
||||
} RewriteStateData;
|
||||
|
||||
/*
|
||||
* The lookup keys for the hash tables are tuple TID and xmin (we must check
|
||||
|
@ -277,7 +277,7 @@ end_heap_rewrite(RewriteState state)
|
|||
}
|
||||
|
||||
/*
|
||||
* If the rel is WAL-logged, must fsync before commit. We use heap_sync
|
||||
* If the rel is WAL-logged, must fsync before commit. We use heap_sync
|
||||
* to ensure that the toast table gets fsync'd too.
|
||||
*
|
||||
* It's obvious that we must do this when not WAL-logging. It's less
|
||||
|
|
|
@ -872,7 +872,7 @@ index_getprocinfo(Relation irel,
|
|||
procnum, attnum, RelationGetRelationName(irel));
|
||||
|
||||
fmgr_info_cxt(procId, locinfo, irel->rd_indexcxt);
|
||||
fmgr_info_set_collation(irel->rd_indcollation[attnum-1], locinfo);
|
||||
fmgr_info_set_collation(irel->rd_indcollation[attnum - 1], locinfo);
|
||||
}
|
||||
|
||||
return locinfo;
|
||||
|
|
|
@ -179,8 +179,8 @@ top:
|
|||
* The only conflict predicate locking cares about for indexes is when
|
||||
* an index tuple insert conflicts with an existing lock. Since the
|
||||
* actual location of the insert is hard to predict because of the
|
||||
* random search used to prevent O(N^2) performance when there are many
|
||||
* duplicate entries, we can just use the "first valid" page.
|
||||
* random search used to prevent O(N^2) performance when there are
|
||||
* many duplicate entries, we can just use the "first valid" page.
|
||||
*/
|
||||
CheckForSerializableConflictIn(rel, NULL, buf);
|
||||
/* do the insertion */
|
||||
|
@ -915,13 +915,13 @@ _bt_split(Relation rel, Buffer buf, OffsetNumber firstright,
|
|||
/*
|
||||
* origpage is the original page to be split. leftpage is a temporary
|
||||
* buffer that receives the left-sibling data, which will be copied back
|
||||
* into origpage on success. rightpage is the new page that receives
|
||||
* the right-sibling data. If we fail before reaching the critical
|
||||
* section, origpage hasn't been modified and leftpage is only workspace.
|
||||
* In principle we shouldn't need to worry about rightpage either,
|
||||
* because it hasn't been linked into the btree page structure; but to
|
||||
* avoid leaving possibly-confusing junk behind, we are careful to rewrite
|
||||
* rightpage as zeroes before throwing any error.
|
||||
* into origpage on success. rightpage is the new page that receives the
|
||||
* right-sibling data. If we fail before reaching the critical section,
|
||||
* origpage hasn't been modified and leftpage is only workspace. In
|
||||
* principle we shouldn't need to worry about rightpage either, because it
|
||||
* hasn't been linked into the btree page structure; but to avoid leaving
|
||||
* possibly-confusing junk behind, we are careful to rewrite rightpage as
|
||||
* zeroes before throwing any error.
|
||||
*/
|
||||
origpage = BufferGetPage(buf);
|
||||
leftpage = PageGetTempPage(origpage);
|
||||
|
@ -1118,7 +1118,7 @@ _bt_split(Relation rel, Buffer buf, OffsetNumber firstright,
|
|||
{
|
||||
memset(rightpage, 0, BufferGetPageSize(rbuf));
|
||||
elog(ERROR, "right sibling's left-link doesn't match: "
|
||||
"block %u links to %u instead of expected %u in index \"%s\"",
|
||||
"block %u links to %u instead of expected %u in index \"%s\"",
|
||||
oopaque->btpo_next, sopaque->btpo_prev, origpagenumber,
|
||||
RelationGetRelationName(rel));
|
||||
}
|
||||
|
|
|
@ -1268,9 +1268,9 @@ _bt_pagedel(Relation rel, Buffer buf, BTStack stack)
|
|||
|
||||
/*
|
||||
* Check that the parent-page index items we're about to delete/overwrite
|
||||
* contain what we expect. This can fail if the index has become
|
||||
* corrupt for some reason. We want to throw any error before entering
|
||||
* the critical section --- otherwise it'd be a PANIC.
|
||||
* contain what we expect. This can fail if the index has become corrupt
|
||||
* for some reason. We want to throw any error before entering the
|
||||
* critical section --- otherwise it'd be a PANIC.
|
||||
*
|
||||
* The test on the target item is just an Assert because _bt_getstackbuf
|
||||
* should have guaranteed it has the expected contents. The test on the
|
||||
|
|
|
@ -220,7 +220,7 @@ btbuildempty(PG_FUNCTION_ARGS)
|
|||
metapage = (Page) palloc(BLCKSZ);
|
||||
_bt_initmetapage(metapage, P_NONE, 0);
|
||||
|
||||
/* Write the page. If archiving/streaming, XLOG it. */
|
||||
/* Write the page. If archiving/streaming, XLOG it. */
|
||||
smgrwrite(index->rd_smgr, INIT_FORKNUM, BTREE_METAPAGE,
|
||||
(char *) metapage, true);
|
||||
if (XLogIsNeeded())
|
||||
|
@ -403,6 +403,7 @@ btrescan(PG_FUNCTION_ARGS)
|
|||
{
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
ScanKey scankey = (ScanKey) PG_GETARG_POINTER(1);
|
||||
|
||||
/* remaining arguments are ignored */
|
||||
BTScanOpaque so = (BTScanOpaque) scan->opaque;
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ _bt_search(Relation rel, int keysz, ScanKey scankey, bool nextkey,
|
|||
/* If index is empty and access = BT_READ, no root page is created. */
|
||||
if (!BufferIsValid(*bufP))
|
||||
{
|
||||
PredicateLockRelation(rel); /* Nothing finer to lock exists. */
|
||||
PredicateLockRelation(rel); /* Nothing finer to lock exists. */
|
||||
return (BTStack) NULL;
|
||||
}
|
||||
|
||||
|
@ -1364,7 +1364,7 @@ _bt_get_endpoint(Relation rel, uint32 level, bool rightmost)
|
|||
if (!BufferIsValid(buf))
|
||||
{
|
||||
/* empty index... */
|
||||
PredicateLockRelation(rel); /* Nothing finer to lock exists. */
|
||||
PredicateLockRelation(rel); /* Nothing finer to lock exists. */
|
||||
return InvalidBuffer;
|
||||
}
|
||||
|
||||
|
@ -1444,7 +1444,7 @@ _bt_endpoint(IndexScanDesc scan, ScanDirection dir)
|
|||
if (!BufferIsValid(buf))
|
||||
{
|
||||
/* empty index... */
|
||||
PredicateLockRelation(rel); /* Nothing finer to lock exists. */
|
||||
PredicateLockRelation(rel); /* Nothing finer to lock exists. */
|
||||
so->currPos.buf = InvalidBuffer;
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -799,7 +799,7 @@ _bt_load(BTWriteState *wstate, BTSpool *btspool, BTSpool *btspool2)
|
|||
|
||||
/*
|
||||
* If the index is WAL-logged, we must fsync it down to disk before it's
|
||||
* safe to commit the transaction. (For a non-WAL-logged index we don't
|
||||
* safe to commit the transaction. (For a non-WAL-logged index we don't
|
||||
* care since the index will be uninteresting after a crash anyway.)
|
||||
*
|
||||
* It's obvious that we must do this when not WAL-logging the build. It's
|
||||
|
|
|
@ -70,8 +70,8 @@ _bt_mkscankey(Relation rel, IndexTuple itup)
|
|||
|
||||
/*
|
||||
* We can use the cached (default) support procs since no cross-type
|
||||
* comparison can be needed. The cached support proc entries have
|
||||
* the right collation for the index, too.
|
||||
* comparison can be needed. The cached support proc entries have the
|
||||
* right collation for the index, too.
|
||||
*/
|
||||
procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);
|
||||
arg = index_getattr(itup, i + 1, itupdesc, &null);
|
||||
|
@ -120,8 +120,8 @@ _bt_mkscankey_nodata(Relation rel)
|
|||
|
||||
/*
|
||||
* We can use the cached (default) support procs since no cross-type
|
||||
* comparison can be needed. The cached support proc entries have
|
||||
* the right collation for the index, too.
|
||||
* comparison can be needed. The cached support proc entries have the
|
||||
* right collation for the index, too.
|
||||
*/
|
||||
procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);
|
||||
flags = SK_ISNULL | (indoption[i] << SK_BT_INDOPTION_SHIFT);
|
||||
|
|
|
@ -120,7 +120,7 @@ typedef struct GlobalTransactionData
|
|||
TransactionId locking_xid; /* top-level XID of backend working on xact */
|
||||
bool valid; /* TRUE if fully prepared */
|
||||
char gid[GIDSIZE]; /* The GID assigned to the prepared xact */
|
||||
} GlobalTransactionData;
|
||||
} GlobalTransactionData;
|
||||
|
||||
/*
|
||||
* Two Phase Commit shared state. Access to this struct is protected
|
||||
|
@ -1029,8 +1029,8 @@ EndPrepare(GlobalTransaction gxact)
|
|||
/* If we crash now, we have prepared: WAL replay will fix things */
|
||||
|
||||
/*
|
||||
* Wake up all walsenders to send WAL up to the PREPARE record
|
||||
* immediately if replication is enabled
|
||||
* Wake up all walsenders to send WAL up to the PREPARE record immediately
|
||||
* if replication is enabled
|
||||
*/
|
||||
if (max_wal_senders > 0)
|
||||
WalSndWakeup();
|
||||
|
@ -2043,8 +2043,8 @@ RecordTransactionCommitPrepared(TransactionId xid,
|
|||
/*
|
||||
* Wait for synchronous replication, if required.
|
||||
*
|
||||
* Note that at this stage we have marked clog, but still show as
|
||||
* running in the procarray and continue to hold locks.
|
||||
* Note that at this stage we have marked clog, but still show as running
|
||||
* in the procarray and continue to hold locks.
|
||||
*/
|
||||
SyncRepWaitForLSN(recptr);
|
||||
}
|
||||
|
@ -2130,8 +2130,8 @@ RecordTransactionAbortPrepared(TransactionId xid,
|
|||
/*
|
||||
* Wait for synchronous replication, if required.
|
||||
*
|
||||
* Note that at this stage we have marked clog, but still show as
|
||||
* running in the procarray and continue to hold locks.
|
||||
* Note that at this stage we have marked clog, but still show as running
|
||||
* in the procarray and continue to hold locks.
|
||||
*/
|
||||
SyncRepWaitForLSN(recptr);
|
||||
}
|
||||
|
|
|
@ -355,9 +355,9 @@ SetTransactionIdLimit(TransactionId oldest_datfrozenxid, Oid oldest_datoid)
|
|||
char *oldest_datname;
|
||||
|
||||
/*
|
||||
* We can be called when not inside a transaction, for example
|
||||
* during StartupXLOG(). In such a case we cannot do database
|
||||
* access, so we must just report the oldest DB's OID.
|
||||
* We can be called when not inside a transaction, for example during
|
||||
* StartupXLOG(). In such a case we cannot do database access, so we
|
||||
* must just report the oldest DB's OID.
|
||||
*
|
||||
* Note: it's also possible that get_database_name fails and returns
|
||||
* NULL, for example because the database just got dropped. We'll
|
||||
|
|
|
@ -420,11 +420,11 @@ AssignTransactionId(TransactionState s)
|
|||
*/
|
||||
if (isSubXact && !TransactionIdIsValid(s->parent->transactionId))
|
||||
{
|
||||
TransactionState p = s->parent;
|
||||
TransactionState *parents;
|
||||
size_t parentOffset = 0;
|
||||
TransactionState p = s->parent;
|
||||
TransactionState *parents;
|
||||
size_t parentOffset = 0;
|
||||
|
||||
parents = palloc(sizeof(TransactionState) * s->nestingLevel);
|
||||
parents = palloc(sizeof(TransactionState) * s->nestingLevel);
|
||||
while (p != NULL && !TransactionIdIsValid(p->transactionId))
|
||||
{
|
||||
parents[parentOffset++] = p;
|
||||
|
@ -432,8 +432,8 @@ AssignTransactionId(TransactionState s)
|
|||
}
|
||||
|
||||
/*
|
||||
* This is technically a recursive call, but the recursion will
|
||||
* never be more than one layer deep.
|
||||
* This is technically a recursive call, but the recursion will never
|
||||
* be more than one layer deep.
|
||||
*/
|
||||
while (parentOffset != 0)
|
||||
AssignTransactionId(parents[--parentOffset]);
|
||||
|
@ -1037,16 +1037,17 @@ RecordTransactionCommit(void)
|
|||
/*
|
||||
* Check if we want to commit asynchronously. We can allow the XLOG flush
|
||||
* to happen asynchronously if synchronous_commit=off, or if the current
|
||||
* transaction has not performed any WAL-logged operation. The latter case
|
||||
* can arise if the current transaction wrote only to temporary and/or
|
||||
* unlogged tables. In case of a crash, the loss of such a transaction
|
||||
* will be irrelevant since temp tables will be lost anyway, and unlogged
|
||||
* tables will be truncated. (Given the foregoing, you might think that it
|
||||
* would be unnecessary to emit the XLOG record at all in this case, but we
|
||||
* don't currently try to do that. It would certainly cause problems at
|
||||
* least in Hot Standby mode, where the KnownAssignedXids machinery
|
||||
* requires tracking every XID assignment. It might be OK to skip it only
|
||||
* when wal_level < hot_standby, but for now we don't.)
|
||||
* transaction has not performed any WAL-logged operation. The latter
|
||||
* case can arise if the current transaction wrote only to temporary
|
||||
* and/or unlogged tables. In case of a crash, the loss of such a
|
||||
* transaction will be irrelevant since temp tables will be lost anyway,
|
||||
* and unlogged tables will be truncated. (Given the foregoing, you might
|
||||
* think that it would be unnecessary to emit the XLOG record at all in
|
||||
* this case, but we don't currently try to do that. It would certainly
|
||||
* cause problems at least in Hot Standby mode, where the
|
||||
* KnownAssignedXids machinery requires tracking every XID assignment. It
|
||||
* might be OK to skip it only when wal_level < hot_standby, but for now
|
||||
* we don't.)
|
||||
*
|
||||
* However, if we're doing cleanup of any non-temp rels or committing any
|
||||
* command that wanted to force sync commit, then we must flush XLOG
|
||||
|
@ -1130,8 +1131,8 @@ RecordTransactionCommit(void)
|
|||
/*
|
||||
* Wait for synchronous replication, if required.
|
||||
*
|
||||
* Note that at this stage we have marked clog, but still show as
|
||||
* running in the procarray and continue to hold locks.
|
||||
* Note that at this stage we have marked clog, but still show as running
|
||||
* in the procarray and continue to hold locks.
|
||||
*/
|
||||
SyncRepWaitForLSN(XactLastRecEnd);
|
||||
|
||||
|
@ -1785,10 +1786,10 @@ CommitTransaction(void)
|
|||
}
|
||||
|
||||
/*
|
||||
* The remaining actions cannot call any user-defined code, so it's
|
||||
* safe to start shutting down within-transaction services. But note
|
||||
* that most of this stuff could still throw an error, which would
|
||||
* switch us into the transaction-abort path.
|
||||
* The remaining actions cannot call any user-defined code, so it's safe
|
||||
* to start shutting down within-transaction services. But note that most
|
||||
* of this stuff could still throw an error, which would switch us into
|
||||
* the transaction-abort path.
|
||||
*/
|
||||
|
||||
/* Shut down the deferred-trigger manager */
|
||||
|
@ -1805,8 +1806,8 @@ CommitTransaction(void)
|
|||
|
||||
/*
|
||||
* Mark serializable transaction as complete for predicate locking
|
||||
* purposes. This should be done as late as we can put it and still
|
||||
* allow errors to be raised for failure patterns found at commit.
|
||||
* purposes. This should be done as late as we can put it and still allow
|
||||
* errors to be raised for failure patterns found at commit.
|
||||
*/
|
||||
PreCommit_CheckForSerializationFailure();
|
||||
|
||||
|
@ -1988,10 +1989,10 @@ PrepareTransaction(void)
|
|||
}
|
||||
|
||||
/*
|
||||
* The remaining actions cannot call any user-defined code, so it's
|
||||
* safe to start shutting down within-transaction services. But note
|
||||
* that most of this stuff could still throw an error, which would
|
||||
* switch us into the transaction-abort path.
|
||||
* The remaining actions cannot call any user-defined code, so it's safe
|
||||
* to start shutting down within-transaction services. But note that most
|
||||
* of this stuff could still throw an error, which would switch us into
|
||||
* the transaction-abort path.
|
||||
*/
|
||||
|
||||
/* Shut down the deferred-trigger manager */
|
||||
|
@ -2008,8 +2009,8 @@ PrepareTransaction(void)
|
|||
|
||||
/*
|
||||
* Mark serializable transaction as complete for predicate locking
|
||||
* purposes. This should be done as late as we can put it and still
|
||||
* allow errors to be raised for failure patterns found at commit.
|
||||
* purposes. This should be done as late as we can put it and still allow
|
||||
* errors to be raised for failure patterns found at commit.
|
||||
*/
|
||||
PreCommit_CheckForSerializationFailure();
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@
|
|||
/* File path names (all relative to $PGDATA) */
|
||||
#define RECOVERY_COMMAND_FILE "recovery.conf"
|
||||
#define RECOVERY_COMMAND_DONE "recovery.done"
|
||||
#define PROMOTE_SIGNAL_FILE "promote"
|
||||
#define PROMOTE_SIGNAL_FILE "promote"
|
||||
|
||||
|
||||
/* User-settable parameters */
|
||||
|
@ -160,6 +160,7 @@ static XLogRecPtr LastRec;
|
|||
* known, need to check the shared state".
|
||||
*/
|
||||
static bool LocalRecoveryInProgress = true;
|
||||
|
||||
/*
|
||||
* Local copy of SharedHotStandbyActive variable. False actually means "not
|
||||
* known, need to check the shared state".
|
||||
|
@ -355,10 +356,9 @@ typedef struct XLogCtlInsert
|
|||
/*
|
||||
* exclusiveBackup is true if a backup started with pg_start_backup() is
|
||||
* in progress, and nonExclusiveBackups is a counter indicating the number
|
||||
* of streaming base backups currently in progress. forcePageWrites is
|
||||
* set to true when either of these is non-zero. lastBackupStart is the
|
||||
* latest checkpoint redo location used as a starting point for an online
|
||||
* backup.
|
||||
* of streaming base backups currently in progress. forcePageWrites is set
|
||||
* to true when either of these is non-zero. lastBackupStart is the latest
|
||||
* checkpoint redo location used as a starting point for an online backup.
|
||||
*/
|
||||
bool exclusiveBackup;
|
||||
int nonExclusiveBackups;
|
||||
|
@ -388,7 +388,7 @@ typedef struct XLogCtlData
|
|||
XLogwrtResult LogwrtResult;
|
||||
uint32 ckptXidEpoch; /* nextXID & epoch of latest checkpoint */
|
||||
TransactionId ckptXid;
|
||||
XLogRecPtr asyncXactLSN; /* LSN of newest async commit/abort */
|
||||
XLogRecPtr asyncXactLSN; /* LSN of newest async commit/abort */
|
||||
uint32 lastRemovedLog; /* latest removed/recycled XLOG segment */
|
||||
uint32 lastRemovedSeg;
|
||||
|
||||
|
@ -425,9 +425,9 @@ typedef struct XLogCtlData
|
|||
bool SharedHotStandbyActive;
|
||||
|
||||
/*
|
||||
* recoveryWakeupLatch is used to wake up the startup process to
|
||||
* continue WAL replay, if it is waiting for WAL to arrive or failover
|
||||
* trigger file to appear.
|
||||
* recoveryWakeupLatch is used to wake up the startup process to continue
|
||||
* WAL replay, if it is waiting for WAL to arrive or failover trigger file
|
||||
* to appear.
|
||||
*/
|
||||
Latch recoveryWakeupLatch;
|
||||
|
||||
|
@ -576,7 +576,7 @@ typedef struct xl_parameter_change
|
|||
/* logs restore point */
|
||||
typedef struct xl_restore_point
|
||||
{
|
||||
TimestampTz rp_time;
|
||||
TimestampTz rp_time;
|
||||
char rp_name[MAXFNAMELEN];
|
||||
} xl_restore_point;
|
||||
|
||||
|
@ -4272,27 +4272,29 @@ existsTimeLineHistory(TimeLineID probeTLI)
|
|||
static bool
|
||||
rescanLatestTimeLine(void)
|
||||
{
|
||||
TimeLineID newtarget;
|
||||
TimeLineID newtarget;
|
||||
|
||||
newtarget = findNewestTimeLine(recoveryTargetTLI);
|
||||
if (newtarget != recoveryTargetTLI)
|
||||
{
|
||||
/*
|
||||
* Determine the list of expected TLIs for the new TLI
|
||||
*/
|
||||
List *newExpectedTLIs;
|
||||
List *newExpectedTLIs;
|
||||
|
||||
newExpectedTLIs = readTimeLineHistory(newtarget);
|
||||
|
||||
/*
|
||||
* If the current timeline is not part of the history of the
|
||||
* new timeline, we cannot proceed to it.
|
||||
* If the current timeline is not part of the history of the new
|
||||
* timeline, we cannot proceed to it.
|
||||
*
|
||||
* XXX This isn't foolproof: The new timeline might have forked from
|
||||
* the current one, but before the current recovery location. In that
|
||||
* case we will still switch to the new timeline and proceed replaying
|
||||
* from it even though the history doesn't match what we already
|
||||
* replayed. That's not good. We will likely notice at the next online
|
||||
* checkpoint, as the TLI won't match what we expected, but it's
|
||||
* not guaranteed. The admin needs to make sure that doesn't happen.
|
||||
* checkpoint, as the TLI won't match what we expected, but it's not
|
||||
* guaranteed. The admin needs to make sure that doesn't happen.
|
||||
*/
|
||||
if (!list_member_int(newExpectedTLIs,
|
||||
(int) recoveryTargetTLI))
|
||||
|
@ -4480,7 +4482,7 @@ writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI,
|
|||
timestamptz_to_str(recoveryStopTime));
|
||||
else if (recoveryTarget == RECOVERY_TARGET_NAME)
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"%s%u\t%s\tat restore point \"%s\"\n",
|
||||
"%s%u\t%s\tat restore point \"%s\"\n",
|
||||
(srcfd < 0) ? "" : "\n",
|
||||
parentTLI,
|
||||
xlogfname,
|
||||
|
@ -4921,7 +4923,7 @@ check_wal_buffers(int *newval, void **extra, GucSource source)
|
|||
{
|
||||
/*
|
||||
* If we haven't yet changed the boot_val default of -1, just let it
|
||||
* be. We'll fix it when XLOGShmemSize is called.
|
||||
* be. We'll fix it when XLOGShmemSize is called.
|
||||
*/
|
||||
if (XLOGbuffers == -1)
|
||||
return true;
|
||||
|
@ -4954,8 +4956,8 @@ XLOGShmemSize(void)
|
|||
/*
|
||||
* If the value of wal_buffers is -1, use the preferred auto-tune value.
|
||||
* This isn't an amazingly clean place to do this, but we must wait till
|
||||
* NBuffers has received its final value, and must do it before using
|
||||
* the value of XLOGbuffers to do anything important.
|
||||
* NBuffers has received its final value, and must do it before using the
|
||||
* value of XLOGbuffers to do anything important.
|
||||
*/
|
||||
if (XLOGbuffers == -1)
|
||||
{
|
||||
|
@ -5086,9 +5088,9 @@ BootStrapXLOG(void)
|
|||
/*
|
||||
* Set up information for the initial checkpoint record
|
||||
*
|
||||
* The initial checkpoint record is written to the beginning of the
|
||||
* WAL segment with logid=0 logseg=1. The very first WAL segment, 0/0, is
|
||||
* not used, so that we can use 0/0 to mean "before any valid WAL segment".
|
||||
* The initial checkpoint record is written to the beginning of the WAL
|
||||
* segment with logid=0 logseg=1. The very first WAL segment, 0/0, is not
|
||||
* used, so that we can use 0/0 to mean "before any valid WAL segment".
|
||||
*/
|
||||
checkPoint.redo.xlogid = 0;
|
||||
checkPoint.redo.xrecoff = XLogSegSize + SizeOfXLogLongPHD;
|
||||
|
@ -5219,8 +5221,8 @@ readRecoveryCommandFile(void)
|
|||
TimeLineID rtli = 0;
|
||||
bool rtliGiven = false;
|
||||
ConfigVariable *item,
|
||||
*head = NULL,
|
||||
*tail = NULL;
|
||||
*head = NULL,
|
||||
*tail = NULL;
|
||||
|
||||
fd = AllocateFile(RECOVERY_COMMAND_FILE, "r");
|
||||
if (fd == NULL)
|
||||
|
@ -5236,7 +5238,7 @@ readRecoveryCommandFile(void)
|
|||
/*
|
||||
* Since we're asking ParseConfigFp() to error out at FATAL, there's no
|
||||
* need to check the return value.
|
||||
*/
|
||||
*/
|
||||
ParseConfigFp(fd, RECOVERY_COMMAND_FILE, 0, FATAL, &head, &tail);
|
||||
|
||||
for (item = head; item; item = item->next)
|
||||
|
@ -5312,7 +5314,7 @@ readRecoveryCommandFile(void)
|
|||
* this overrides recovery_target_time
|
||||
*/
|
||||
if (recoveryTarget == RECOVERY_TARGET_XID ||
|
||||
recoveryTarget == RECOVERY_TARGET_NAME)
|
||||
recoveryTarget == RECOVERY_TARGET_NAME)
|
||||
continue;
|
||||
recoveryTarget = RECOVERY_TARGET_TIME;
|
||||
|
||||
|
@ -5321,7 +5323,7 @@ readRecoveryCommandFile(void)
|
|||
*/
|
||||
recoveryTargetTime =
|
||||
DatumGetTimestampTz(DirectFunctionCall3(timestamptz_in,
|
||||
CStringGetDatum(item->value),
|
||||
CStringGetDatum(item->value),
|
||||
ObjectIdGetDatum(InvalidOid),
|
||||
Int32GetDatum(-1)));
|
||||
ereport(DEBUG2,
|
||||
|
@ -5610,8 +5612,8 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
|
|||
if (recoveryTarget == RECOVERY_TARGET_UNSET)
|
||||
{
|
||||
/*
|
||||
* Save timestamp of latest transaction commit/abort if this is
|
||||
* a transaction record
|
||||
* Save timestamp of latest transaction commit/abort if this is a
|
||||
* transaction record
|
||||
*/
|
||||
if (record->xl_rmid == RM_XACT_ID)
|
||||
SetLatestXTime(recordXtime);
|
||||
|
@ -5636,8 +5638,8 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
|
|||
else if (recoveryTarget == RECOVERY_TARGET_NAME)
|
||||
{
|
||||
/*
|
||||
* There can be many restore points that share the same name, so we stop
|
||||
* at the first one
|
||||
* There can be many restore points that share the same name, so we
|
||||
* stop at the first one
|
||||
*/
|
||||
stopsHere = (strcmp(recordRPName, recoveryTargetName) == 0);
|
||||
|
||||
|
@ -5699,14 +5701,14 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
|
|||
strncpy(recoveryStopName, recordRPName, MAXFNAMELEN);
|
||||
|
||||
ereport(LOG,
|
||||
(errmsg("recovery stopping at restore point \"%s\", time %s",
|
||||
recoveryStopName,
|
||||
timestamptz_to_str(recoveryStopTime))));
|
||||
(errmsg("recovery stopping at restore point \"%s\", time %s",
|
||||
recoveryStopName,
|
||||
timestamptz_to_str(recoveryStopTime))));
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that if we use a RECOVERY_TARGET_TIME then we can stop
|
||||
* at a restore point since they are timestamped, though the latest
|
||||
* Note that if we use a RECOVERY_TARGET_TIME then we can stop at a
|
||||
* restore point since they are timestamped, though the latest
|
||||
* transaction time is not updated.
|
||||
*/
|
||||
if (record->xl_rmid == RM_XACT_ID && recoveryStopAfter)
|
||||
|
@ -5732,7 +5734,7 @@ recoveryPausesHere(void)
|
|||
|
||||
while (RecoveryIsPaused())
|
||||
{
|
||||
pg_usleep(1000000L); /* 1000 ms */
|
||||
pg_usleep(1000000L); /* 1000 ms */
|
||||
HandleStartupProcInterrupts();
|
||||
}
|
||||
}
|
||||
|
@ -5742,7 +5744,7 @@ RecoveryIsPaused(void)
|
|||
{
|
||||
/* use volatile pointer to prevent code rearrangement */
|
||||
volatile XLogCtlData *xlogctl = XLogCtl;
|
||||
bool recoveryPause;
|
||||
bool recoveryPause;
|
||||
|
||||
SpinLockAcquire(&xlogctl->info_lck);
|
||||
recoveryPause = xlogctl->recoveryPause;
|
||||
|
@ -5771,7 +5773,7 @@ pg_xlog_replay_pause(PG_FUNCTION_ARGS)
|
|||
if (!superuser())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
(errmsg("must be superuser to control recovery"))));
|
||||
(errmsg("must be superuser to control recovery"))));
|
||||
|
||||
if (!RecoveryInProgress())
|
||||
ereport(ERROR,
|
||||
|
@ -5793,7 +5795,7 @@ pg_xlog_replay_resume(PG_FUNCTION_ARGS)
|
|||
if (!superuser())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
(errmsg("must be superuser to control recovery"))));
|
||||
(errmsg("must be superuser to control recovery"))));
|
||||
|
||||
if (!RecoveryInProgress())
|
||||
ereport(ERROR,
|
||||
|
@ -5815,7 +5817,7 @@ pg_is_xlog_replay_paused(PG_FUNCTION_ARGS)
|
|||
if (!superuser())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
(errmsg("must be superuser to control recovery"))));
|
||||
(errmsg("must be superuser to control recovery"))));
|
||||
|
||||
if (!RecoveryInProgress())
|
||||
ereport(ERROR,
|
||||
|
@ -5870,7 +5872,7 @@ GetLatestXTime(void)
|
|||
Datum
|
||||
pg_last_xact_replay_timestamp(PG_FUNCTION_ARGS)
|
||||
{
|
||||
TimestampTz xtime;
|
||||
TimestampTz xtime;
|
||||
|
||||
xtime = GetLatestXTime();
|
||||
if (xtime == 0)
|
||||
|
@ -6132,10 +6134,10 @@ StartupXLOG(void)
|
|||
InRecovery = true; /* force recovery even if SHUTDOWNED */
|
||||
|
||||
/*
|
||||
* Make sure that REDO location exists. This may not be
|
||||
* the case if there was a crash during an online backup,
|
||||
* which left a backup_label around that references a WAL
|
||||
* segment that's already been archived.
|
||||
* Make sure that REDO location exists. This may not be the case
|
||||
* if there was a crash during an online backup, which left a
|
||||
* backup_label around that references a WAL segment that's
|
||||
* already been archived.
|
||||
*/
|
||||
if (XLByteLT(checkPoint.redo, checkPointLoc))
|
||||
{
|
||||
|
@ -6150,7 +6152,7 @@ StartupXLOG(void)
|
|||
ereport(FATAL,
|
||||
(errmsg("could not locate required checkpoint record"),
|
||||
errhint("If you are not restoring from a backup, try removing the file \"%s/backup_label\".", DataDir)));
|
||||
wasShutdown = false; /* keep compiler quiet */
|
||||
wasShutdown = false; /* keep compiler quiet */
|
||||
}
|
||||
/* set flag to delete it later */
|
||||
haveBackupLabel = true;
|
||||
|
@ -6330,9 +6332,9 @@ StartupXLOG(void)
|
|||
|
||||
/*
|
||||
* We're in recovery, so unlogged relations relations may be trashed
|
||||
* and must be reset. This should be done BEFORE allowing Hot
|
||||
* Standby connections, so that read-only backends don't try to
|
||||
* read whatever garbage is left over from before.
|
||||
* and must be reset. This should be done BEFORE allowing Hot Standby
|
||||
* connections, so that read-only backends don't try to read whatever
|
||||
* garbage is left over from before.
|
||||
*/
|
||||
ResetUnloggedRelations(UNLOGGED_RELATION_CLEANUP);
|
||||
|
||||
|
@ -6517,7 +6519,8 @@ StartupXLOG(void)
|
|||
if (recoveryStopsHere(record, &recoveryApply))
|
||||
{
|
||||
/*
|
||||
* Pause only if users can connect to send a resume message
|
||||
* Pause only if users can connect to send a resume
|
||||
* message
|
||||
*/
|
||||
if (recoveryPauseAtTarget && standbyState == STANDBY_SNAPSHOT_READY)
|
||||
{
|
||||
|
@ -7003,8 +7006,8 @@ HotStandbyActive(void)
|
|||
{
|
||||
/*
|
||||
* We check shared state each time only until Hot Standby is active. We
|
||||
* can't de-activate Hot Standby, so there's no need to keep checking after
|
||||
* the shared variable has once been seen true.
|
||||
* can't de-activate Hot Standby, so there's no need to keep checking
|
||||
* after the shared variable has once been seen true.
|
||||
*/
|
||||
if (LocalHotStandbyActive)
|
||||
return true;
|
||||
|
@ -7429,14 +7432,14 @@ LogCheckpointEnd(bool restartpoint)
|
|||
*/
|
||||
longest_secs = (long) (CheckpointStats.ckpt_longest_sync / 1000000);
|
||||
longest_usecs = CheckpointStats.ckpt_longest_sync -
|
||||
(uint64) longest_secs * 1000000;
|
||||
(uint64) longest_secs *1000000;
|
||||
|
||||
average_sync_time = 0;
|
||||
if (CheckpointStats.ckpt_sync_rels > 0)
|
||||
if (CheckpointStats.ckpt_sync_rels > 0)
|
||||
average_sync_time = CheckpointStats.ckpt_agg_sync_time /
|
||||
CheckpointStats.ckpt_sync_rels;
|
||||
average_secs = (long) (average_sync_time / 1000000);
|
||||
average_usecs = average_sync_time - (uint64) average_secs * 1000000;
|
||||
average_usecs = average_sync_time - (uint64) average_secs *1000000;
|
||||
|
||||
if (restartpoint)
|
||||
elog(LOG, "restartpoint complete: wrote %d buffers (%.1f%%); "
|
||||
|
@ -8241,9 +8244,9 @@ RequestXLogSwitch(void)
|
|||
XLogRecPtr
|
||||
XLogRestorePoint(const char *rpName)
|
||||
{
|
||||
XLogRecPtr RecPtr;
|
||||
XLogRecData rdata;
|
||||
xl_restore_point xlrec;
|
||||
XLogRecPtr RecPtr;
|
||||
XLogRecData rdata;
|
||||
xl_restore_point xlrec;
|
||||
|
||||
xlrec.rp_time = GetCurrentTimestamp();
|
||||
strncpy(xlrec.rp_name, rpName, MAXFNAMELEN);
|
||||
|
@ -8257,7 +8260,7 @@ XLogRestorePoint(const char *rpName)
|
|||
|
||||
ereport(LOG,
|
||||
(errmsg("restore point \"%s\" created at %X/%X",
|
||||
rpName, RecPtr.xlogid, RecPtr.xrecoff)));
|
||||
rpName, RecPtr.xlogid, RecPtr.xrecoff)));
|
||||
|
||||
return RecPtr;
|
||||
}
|
||||
|
@ -8643,7 +8646,7 @@ get_sync_bit(int method)
|
|||
|
||||
/*
|
||||
* Optimize writes by bypassing kernel cache with O_DIRECT when using
|
||||
* O_SYNC/O_FSYNC and O_DSYNC. But only if archiving and streaming are
|
||||
* O_SYNC/O_FSYNC and O_DSYNC. But only if archiving and streaming are
|
||||
* disabled, otherwise the archive command or walsender process will read
|
||||
* the WAL soon after writing it, which is guaranteed to cause a physical
|
||||
* read if we bypassed the kernel cache. We also skip the
|
||||
|
@ -8775,7 +8778,7 @@ pg_start_backup(PG_FUNCTION_ARGS)
|
|||
text *backupid = PG_GETARG_TEXT_P(0);
|
||||
bool fast = PG_GETARG_BOOL(1);
|
||||
char *backupidstr;
|
||||
XLogRecPtr startpoint;
|
||||
XLogRecPtr startpoint;
|
||||
char startxlogstr[MAXFNAMELEN];
|
||||
|
||||
backupidstr = text_to_cstring(backupid);
|
||||
|
@ -8791,7 +8794,7 @@ pg_start_backup(PG_FUNCTION_ARGS)
|
|||
* do_pg_start_backup is the workhorse of the user-visible pg_start_backup()
|
||||
* function. It creates the necessary starting checkpoint and constructs the
|
||||
* backup label file.
|
||||
*
|
||||
*
|
||||
* There are two kind of backups: exclusive and non-exclusive. An exclusive
|
||||
* backup is started with pg_start_backup(), and there can be only one active
|
||||
* at a time. The backup label file of an exclusive backup is written to
|
||||
|
@ -8826,7 +8829,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, char **labelfile)
|
|||
if (!superuser() && !is_authenticated_user_replication_role())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("must be superuser or replication role to run a backup")));
|
||||
errmsg("must be superuser or replication role to run a backup")));
|
||||
|
||||
if (RecoveryInProgress())
|
||||
ereport(ERROR,
|
||||
|
@ -8897,25 +8900,27 @@ do_pg_start_backup(const char *backupidstr, bool fast, char **labelfile)
|
|||
/* Ensure we release forcePageWrites if fail below */
|
||||
PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
|
||||
{
|
||||
bool gotUniqueStartpoint = false;
|
||||
bool gotUniqueStartpoint = false;
|
||||
|
||||
do
|
||||
{
|
||||
/*
|
||||
* Force a CHECKPOINT. Aside from being necessary to prevent torn
|
||||
* page problems, this guarantees that two successive backup runs will
|
||||
* have different checkpoint positions and hence different history
|
||||
* file names, even if nothing happened in between.
|
||||
* page problems, this guarantees that two successive backup runs
|
||||
* will have different checkpoint positions and hence different
|
||||
* history file names, even if nothing happened in between.
|
||||
*
|
||||
* We use CHECKPOINT_IMMEDIATE only if requested by user (via passing
|
||||
* fast = true). Otherwise this can take awhile.
|
||||
* We use CHECKPOINT_IMMEDIATE only if requested by user (via
|
||||
* passing fast = true). Otherwise this can take awhile.
|
||||
*/
|
||||
RequestCheckpoint(CHECKPOINT_FORCE | CHECKPOINT_WAIT |
|
||||
(fast ? CHECKPOINT_IMMEDIATE : 0));
|
||||
|
||||
/*
|
||||
* Now we need to fetch the checkpoint record location, and also its
|
||||
* REDO pointer. The oldest point in WAL that would be needed to
|
||||
* restore starting from the checkpoint is precisely the REDO pointer.
|
||||
* Now we need to fetch the checkpoint record location, and also
|
||||
* its REDO pointer. The oldest point in WAL that would be needed
|
||||
* to restore starting from the checkpoint is precisely the REDO
|
||||
* pointer.
|
||||
*/
|
||||
LWLockAcquire(ControlFileLock, LW_SHARED);
|
||||
checkpointloc = ControlFile->checkPoint;
|
||||
|
@ -8923,16 +8928,15 @@ do_pg_start_backup(const char *backupidstr, bool fast, char **labelfile)
|
|||
LWLockRelease(ControlFileLock);
|
||||
|
||||
/*
|
||||
* If two base backups are started at the same time (in WAL
|
||||
* sender processes), we need to make sure that they use
|
||||
* different checkpoints as starting locations, because we use
|
||||
* the starting WAL location as a unique identifier for the base
|
||||
* backup in the end-of-backup WAL record and when we write the
|
||||
* backup history file. Perhaps it would be better generate a
|
||||
* separate unique ID for each backup instead of forcing another
|
||||
* checkpoint, but taking a checkpoint right after another is
|
||||
* not that expensive either because only few buffers have been
|
||||
* dirtied yet.
|
||||
* If two base backups are started at the same time (in WAL sender
|
||||
* processes), we need to make sure that they use different
|
||||
* checkpoints as starting locations, because we use the starting
|
||||
* WAL location as a unique identifier for the base backup in the
|
||||
* end-of-backup WAL record and when we write the backup history
|
||||
* file. Perhaps it would be better generate a separate unique ID
|
||||
* for each backup instead of forcing another checkpoint, but
|
||||
* taking a checkpoint right after another is not that expensive
|
||||
* either because only few buffers have been dirtied yet.
|
||||
*/
|
||||
LWLockAcquire(WALInsertLock, LW_SHARED);
|
||||
if (XLByteLT(XLogCtl->Insert.lastBackupStart, startpoint))
|
||||
|
@ -8941,13 +8945,13 @@ do_pg_start_backup(const char *backupidstr, bool fast, char **labelfile)
|
|||
gotUniqueStartpoint = true;
|
||||
}
|
||||
LWLockRelease(WALInsertLock);
|
||||
} while(!gotUniqueStartpoint);
|
||||
} while (!gotUniqueStartpoint);
|
||||
|
||||
XLByteToSeg(startpoint, _logId, _logSeg);
|
||||
XLogFileName(xlogfilename, ThisTimeLineID, _logId, _logSeg);
|
||||
|
||||
/*
|
||||
* Construct backup label file
|
||||
* Construct backup label file
|
||||
*/
|
||||
initStringInfo(&labelfbuf);
|
||||
|
||||
|
@ -8970,8 +8974,8 @@ do_pg_start_backup(const char *backupidstr, bool fast, char **labelfile)
|
|||
{
|
||||
/*
|
||||
* Check for existing backup label --- implies a backup is already
|
||||
* running. (XXX given that we checked exclusiveBackup above, maybe
|
||||
* it would be OK to just unlink any such label file?)
|
||||
* running. (XXX given that we checked exclusiveBackup above,
|
||||
* maybe it would be OK to just unlink any such label file?)
|
||||
*/
|
||||
if (stat(BACKUP_LABEL_FILE, &stat_buf) != 0)
|
||||
{
|
||||
|
@ -9018,7 +9022,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, char **labelfile)
|
|||
static void
|
||||
pg_start_backup_callback(int code, Datum arg)
|
||||
{
|
||||
bool exclusive = DatumGetBool(arg);
|
||||
bool exclusive = DatumGetBool(arg);
|
||||
|
||||
/* Update backup counters and forcePageWrites on failure */
|
||||
LWLockAcquire(WALInsertLock, LW_EXCLUSIVE);
|
||||
|
@ -9101,7 +9105,7 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive)
|
|||
if (!superuser() && !is_authenticated_user_replication_role())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
(errmsg("must be superuser or replication role to run a backup"))));
|
||||
(errmsg("must be superuser or replication role to run a backup"))));
|
||||
|
||||
if (RecoveryInProgress())
|
||||
ereport(ERROR,
|
||||
|
@ -9145,8 +9149,8 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive)
|
|||
/*
|
||||
* Read the existing label file into memory.
|
||||
*/
|
||||
struct stat statbuf;
|
||||
int r;
|
||||
struct stat statbuf;
|
||||
int r;
|
||||
|
||||
if (stat(BACKUP_LABEL_FILE, &statbuf))
|
||||
{
|
||||
|
@ -9197,7 +9201,7 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive)
|
|||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
errmsg("invalid data in file \"%s\"", BACKUP_LABEL_FILE)));
|
||||
remaining = strchr(labelfile, '\n') + 1; /* %n is not portable enough */
|
||||
remaining = strchr(labelfile, '\n') + 1; /* %n is not portable enough */
|
||||
|
||||
/*
|
||||
* Write the backup-end xlog record
|
||||
|
@ -9388,8 +9392,8 @@ pg_switch_xlog(PG_FUNCTION_ARGS)
|
|||
Datum
|
||||
pg_create_restore_point(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *restore_name = PG_GETARG_TEXT_P(0);
|
||||
char *restore_name_str;
|
||||
text *restore_name = PG_GETARG_TEXT_P(0);
|
||||
char *restore_name_str;
|
||||
XLogRecPtr restorepoint;
|
||||
char location[MAXFNAMELEN];
|
||||
|
||||
|
@ -9407,7 +9411,7 @@ pg_create_restore_point(PG_FUNCTION_ARGS)
|
|||
if (!XLogIsNeeded())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
errmsg("WAL level not sufficient for creating a restore point"),
|
||||
errmsg("WAL level not sufficient for creating a restore point"),
|
||||
errhint("wal_level must be set to \"archive\" or \"hot_standby\" at server start.")));
|
||||
|
||||
restore_name_str = text_to_cstring(restore_name);
|
||||
|
@ -9423,7 +9427,7 @@ pg_create_restore_point(PG_FUNCTION_ARGS)
|
|||
* As a convenience, return the WAL location of the restore point record
|
||||
*/
|
||||
snprintf(location, sizeof(location), "%X/%X",
|
||||
restorepoint.xlogid, restorepoint.xrecoff);
|
||||
restorepoint.xlogid, restorepoint.xrecoff);
|
||||
PG_RETURN_TEXT_P(cstring_to_text(location));
|
||||
}
|
||||
|
||||
|
@ -10177,8 +10181,8 @@ retry:
|
|||
}
|
||||
|
||||
/*
|
||||
* If it hasn't been long since last attempt, sleep
|
||||
* to avoid busy-waiting.
|
||||
* If it hasn't been long since last attempt, sleep to
|
||||
* avoid busy-waiting.
|
||||
*/
|
||||
now = (pg_time_t) time(NULL);
|
||||
if ((now - last_fail_time) < 5)
|
||||
|
@ -10404,7 +10408,7 @@ static bool
|
|||
CheckForStandbyTrigger(void)
|
||||
{
|
||||
struct stat stat_buf;
|
||||
static bool triggered = false;
|
||||
static bool triggered = false;
|
||||
|
||||
if (triggered)
|
||||
return true;
|
||||
|
@ -10446,8 +10450,8 @@ CheckPromoteSignal(void)
|
|||
if (stat(PROMOTE_SIGNAL_FILE, &stat_buf) == 0)
|
||||
{
|
||||
/*
|
||||
* Since we are in a signal handler, it's not safe
|
||||
* to elog. We silently ignore any error from unlink.
|
||||
* Since we are in a signal handler, it's not safe to elog. We
|
||||
* silently ignore any error from unlink.
|
||||
*/
|
||||
unlink(PROMOTE_SIGNAL_FILE);
|
||||
return true;
|
||||
|
|
|
@ -1011,8 +1011,8 @@ SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames)
|
|||
|
||||
/*
|
||||
* Note that we must do the permissions check against the target
|
||||
* role not the calling user. We require CREATE privileges,
|
||||
* since without CREATE you won't be able to do anything using the
|
||||
* role not the calling user. We require CREATE privileges, since
|
||||
* without CREATE you won't be able to do anything using the
|
||||
* default privs anyway.
|
||||
*/
|
||||
iacls->nspid = get_namespace_oid(nspname, false);
|
||||
|
@ -1707,7 +1707,7 @@ ExecGrant_Relation(InternalGrant *istmt)
|
|||
pg_class_tuple->relkind != RELKIND_FOREIGN_TABLE)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||
errmsg("\"%s\" is not a foreign table",
|
||||
errmsg("\"%s\" is not a foreign table",
|
||||
NameStr(pg_class_tuple->relname))));
|
||||
|
||||
/* Adjust the default permissions based on object type */
|
||||
|
@ -1964,13 +1964,13 @@ ExecGrant_Relation(InternalGrant *istmt)
|
|||
this_privileges &= (AclMode) ACL_SELECT;
|
||||
}
|
||||
else if (pg_class_tuple->relkind == RELKIND_FOREIGN_TABLE &&
|
||||
this_privileges & ~((AclMode) ACL_SELECT))
|
||||
this_privileges & ~((AclMode) ACL_SELECT))
|
||||
{
|
||||
/* Foreign tables have the same restriction as sequences. */
|
||||
ereport(WARNING,
|
||||
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
|
||||
errmsg("foreign table \"%s\" only supports SELECT column privileges",
|
||||
NameStr(pg_class_tuple->relname))));
|
||||
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
|
||||
errmsg("foreign table \"%s\" only supports SELECT column privileges",
|
||||
NameStr(pg_class_tuple->relname))));
|
||||
this_privileges &= (AclMode) ACL_SELECT;
|
||||
}
|
||||
|
||||
|
@ -4768,7 +4768,7 @@ pg_extension_ownercheck(Oid ext_oid, Oid roleid)
|
|||
* Note: roles do not have owners per se; instead we use this test in
|
||||
* places where an ownership-like permissions test is needed for a role.
|
||||
* Be sure to apply it to the role trying to do the operation, not the
|
||||
* role being operated on! Also note that this generally should not be
|
||||
* role being operated on! Also note that this generally should not be
|
||||
* considered enough privilege if the target role is a superuser.
|
||||
* (We don't handle that consideration here because we want to give a
|
||||
* separate error message for such cases, so the caller has to deal with it.)
|
||||
|
|
|
@ -80,11 +80,11 @@ forkname_to_number(char *forkName)
|
|||
|
||||
/*
|
||||
* forkname_chars
|
||||
* We use this to figure out whether a filename could be a relation
|
||||
* fork (as opposed to an oddly named stray file that somehow ended
|
||||
* up in the database directory). If the passed string begins with
|
||||
* a fork name (other than the main fork name), we return its length,
|
||||
* and set *fork (if not NULL) to the fork number. If not, we return 0.
|
||||
* We use this to figure out whether a filename could be a relation
|
||||
* fork (as opposed to an oddly named stray file that somehow ended
|
||||
* up in the database directory). If the passed string begins with
|
||||
* a fork name (other than the main fork name), we return its length,
|
||||
* and set *fork (if not NULL) to the fork number. If not, we return 0.
|
||||
*
|
||||
* Note that the present coding assumes that there are no fork names which
|
||||
* are prefixes of other fork names.
|
||||
|
@ -96,7 +96,8 @@ forkname_chars(const char *str, ForkNumber *fork)
|
|||
|
||||
for (forkNum = 1; forkNum <= MAX_FORKNUM; forkNum++)
|
||||
{
|
||||
int len = strlen(forkNames[forkNum]);
|
||||
int len = strlen(forkNames[forkNum]);
|
||||
|
||||
if (strncmp(forkNames[forkNum], str, len) == 0)
|
||||
{
|
||||
if (fork)
|
||||
|
@ -150,7 +151,7 @@ relpathbackend(RelFileNode rnode, BackendId backend, ForkNumber forknum)
|
|||
{
|
||||
/* OIDCHARS will suffice for an integer, too */
|
||||
pathlen = 5 + OIDCHARS + 2 + OIDCHARS + 1 + OIDCHARS + 1
|
||||
+ FORKNAMECHARS + 1;
|
||||
+ FORKNAMECHARS + 1;
|
||||
path = (char *) palloc(pathlen);
|
||||
if (forknum != MAIN_FORKNUM)
|
||||
snprintf(path, pathlen, "base/%u/t%d_%u_%s",
|
||||
|
@ -167,8 +168,8 @@ relpathbackend(RelFileNode rnode, BackendId backend, ForkNumber forknum)
|
|||
if (backend == InvalidBackendId)
|
||||
{
|
||||
pathlen = 9 + 1 + OIDCHARS + 1
|
||||
+ strlen(TABLESPACE_VERSION_DIRECTORY) + 1 + OIDCHARS + 1
|
||||
+ OIDCHARS + 1 + FORKNAMECHARS + 1;
|
||||
+ strlen(TABLESPACE_VERSION_DIRECTORY) + 1 + OIDCHARS + 1
|
||||
+ OIDCHARS + 1 + FORKNAMECHARS + 1;
|
||||
path = (char *) palloc(pathlen);
|
||||
if (forknum != MAIN_FORKNUM)
|
||||
snprintf(path, pathlen, "pg_tblspc/%u/%s/%u/%u_%s",
|
||||
|
@ -184,8 +185,8 @@ relpathbackend(RelFileNode rnode, BackendId backend, ForkNumber forknum)
|
|||
{
|
||||
/* OIDCHARS will suffice for an integer, too */
|
||||
pathlen = 9 + 1 + OIDCHARS + 1
|
||||
+ strlen(TABLESPACE_VERSION_DIRECTORY) + 1 + OIDCHARS + 2
|
||||
+ OIDCHARS + 1 + OIDCHARS + 1 + FORKNAMECHARS + 1;
|
||||
+ strlen(TABLESPACE_VERSION_DIRECTORY) + 1 + OIDCHARS + 2
|
||||
+ OIDCHARS + 1 + OIDCHARS + 1 + FORKNAMECHARS + 1;
|
||||
path = (char *) palloc(pathlen);
|
||||
if (forknum != MAIN_FORKNUM)
|
||||
snprintf(path, pathlen, "pg_tblspc/%u/%s/%u/t%d_%u_%s",
|
||||
|
|
|
@ -160,7 +160,7 @@ static const Oid object_classes[MAX_OCLASS] = {
|
|||
ForeignServerRelationId, /* OCLASS_FOREIGN_SERVER */
|
||||
UserMappingRelationId, /* OCLASS_USER_MAPPING */
|
||||
DefaultAclRelationId, /* OCLASS_DEFACL */
|
||||
ExtensionRelationId /* OCLASS_EXTENSION */
|
||||
ExtensionRelationId /* OCLASS_EXTENSION */
|
||||
};
|
||||
|
||||
|
||||
|
@ -1021,8 +1021,8 @@ deleteOneObject(const ObjectAddress *object, Relation depRel)
|
|||
|
||||
/*
|
||||
* Delete any comments or security labels associated with this object.
|
||||
* (This is a convenient place to do these things, rather than having every
|
||||
* object type know to do it.)
|
||||
* (This is a convenient place to do these things, rather than having
|
||||
* every object type know to do it.)
|
||||
*/
|
||||
DeleteComments(object->objectId, object->classId, object->objectSubId);
|
||||
DeleteSecurityLabel(object);
|
||||
|
@ -1263,7 +1263,7 @@ recordDependencyOnExpr(const ObjectAddress *depender,
|
|||
* whereas 'behavior' is used for everything else.
|
||||
*
|
||||
* NOTE: the caller should ensure that a whole-table dependency on the
|
||||
* specified relation is created separately, if one is needed. In particular,
|
||||
* specified relation is created separately, if one is needed. In particular,
|
||||
* a whole-row Var "relation.*" will not cause this routine to emit any
|
||||
* dependency item. This is appropriate behavior for subexpressions of an
|
||||
* ordinary query, so other cases need to cope as necessary.
|
||||
|
@ -1383,7 +1383,7 @@ find_expr_references_walker(Node *node,
|
|||
|
||||
/*
|
||||
* A whole-row Var references no specific columns, so adds no new
|
||||
* dependency. (We assume that there is a whole-table dependency
|
||||
* dependency. (We assume that there is a whole-table dependency
|
||||
* arising from each underlying rangetable entry. While we could
|
||||
* record such a dependency when finding a whole-row Var that
|
||||
* references a relation directly, it's quite unclear how to extend
|
||||
|
@ -1431,8 +1431,8 @@ find_expr_references_walker(Node *node,
|
|||
|
||||
/*
|
||||
* We must also depend on the constant's collation: it could be
|
||||
* different from the datatype's, if a CollateExpr was const-folded
|
||||
* to a simple constant. However we can save work in the most common
|
||||
* different from the datatype's, if a CollateExpr was const-folded to
|
||||
* a simple constant. However we can save work in the most common
|
||||
* case where the collation is "default", since we know that's pinned.
|
||||
*/
|
||||
if (OidIsValid(con->constcollid) &&
|
||||
|
@ -1695,7 +1695,7 @@ find_expr_references_walker(Node *node,
|
|||
}
|
||||
foreach(ct, rte->funccolcollations)
|
||||
{
|
||||
Oid collid = lfirst_oid(ct);
|
||||
Oid collid = lfirst_oid(ct);
|
||||
|
||||
if (OidIsValid(collid) &&
|
||||
collid != DEFAULT_COLLATION_OID)
|
||||
|
@ -2224,12 +2224,12 @@ getObjectDescription(const ObjectAddress *object)
|
|||
HeapTuple collTup;
|
||||
|
||||
collTup = SearchSysCache1(COLLOID,
|
||||
ObjectIdGetDatum(object->objectId));
|
||||
ObjectIdGetDatum(object->objectId));
|
||||
if (!HeapTupleIsValid(collTup))
|
||||
elog(ERROR, "cache lookup failed for collation %u",
|
||||
object->objectId);
|
||||
appendStringInfo(&buffer, _("collation %s"),
|
||||
NameStr(((Form_pg_collation) GETSTRUCT(collTup))->collname));
|
||||
NameStr(((Form_pg_collation) GETSTRUCT(collTup))->collname));
|
||||
ReleaseSysCache(collTup);
|
||||
break;
|
||||
}
|
||||
|
@ -2796,7 +2796,7 @@ getObjectDescription(const ObjectAddress *object)
|
|||
char *
|
||||
getObjectDescriptionOids(Oid classid, Oid objid)
|
||||
{
|
||||
ObjectAddress address;
|
||||
ObjectAddress address;
|
||||
|
||||
address.classId = classid;
|
||||
address.objectId = objid;
|
||||
|
|
|
@ -431,7 +431,7 @@ CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind,
|
|||
CheckAttributeType(NameStr(tupdesc->attrs[i]->attname),
|
||||
tupdesc->attrs[i]->atttypid,
|
||||
tupdesc->attrs[i]->attcollation,
|
||||
NIL, /* assume we're creating a new rowtype */
|
||||
NIL, /* assume we're creating a new rowtype */
|
||||
allow_system_table_mods);
|
||||
}
|
||||
}
|
||||
|
@ -497,7 +497,7 @@ CheckAttributeType(const char *attname,
|
|||
int i;
|
||||
|
||||
/*
|
||||
* Check for self-containment. Eventually we might be able to allow
|
||||
* Check for self-containment. Eventually we might be able to allow
|
||||
* this (just return without complaint, if so) but it's not clear how
|
||||
* many other places would require anti-recursion defenses before it
|
||||
* would be safe to allow tables to contain their own rowtype.
|
||||
|
@ -505,8 +505,8 @@ CheckAttributeType(const char *attname,
|
|||
if (list_member_oid(containing_rowtypes, atttypid))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
|
||||
errmsg("composite type %s cannot be made a member of itself",
|
||||
format_type_be(atttypid))));
|
||||
errmsg("composite type %s cannot be made a member of itself",
|
||||
format_type_be(atttypid))));
|
||||
|
||||
containing_rowtypes = lcons_oid(atttypid, containing_rowtypes);
|
||||
|
||||
|
@ -541,15 +541,15 @@ CheckAttributeType(const char *attname,
|
|||
}
|
||||
|
||||
/*
|
||||
* This might not be strictly invalid per SQL standard, but it is
|
||||
* pretty useless, and it cannot be dumped, so we must disallow it.
|
||||
* This might not be strictly invalid per SQL standard, but it is pretty
|
||||
* useless, and it cannot be dumped, so we must disallow it.
|
||||
*/
|
||||
if (!OidIsValid(attcollation) && type_is_collatable(atttypid))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
|
||||
errmsg("no collation was derived for column \"%s\" with collatable type %s",
|
||||
attname, format_type_be(atttypid)),
|
||||
errhint("Use the COLLATE clause to set the collation explicitly.")));
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
|
||||
errmsg("no collation was derived for column \"%s\" with collatable type %s",
|
||||
attname, format_type_be(atttypid)),
|
||||
errhint("Use the COLLATE clause to set the collation explicitly.")));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -921,7 +921,7 @@ AddNewRelationType(const char *typeName,
|
|||
-1, /* typmod */
|
||||
0, /* array dimensions for typBaseType */
|
||||
false, /* Type NOT NULL */
|
||||
InvalidOid); /* typcollation */
|
||||
InvalidOid); /* typcollation */
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
|
@ -992,9 +992,9 @@ heap_create_with_catalog(const char *relname,
|
|||
CheckAttributeNamesTypes(tupdesc, relkind, allow_system_table_mods);
|
||||
|
||||
/*
|
||||
* If the relation already exists, it's an error, unless the user specifies
|
||||
* "IF NOT EXISTS". In that case, we just print a notice and do nothing
|
||||
* further.
|
||||
* If the relation already exists, it's an error, unless the user
|
||||
* specifies "IF NOT EXISTS". In that case, we just print a notice and do
|
||||
* nothing further.
|
||||
*/
|
||||
existing_relid = get_relname_relid(relname, relnamespace);
|
||||
if (existing_relid != InvalidOid)
|
||||
|
@ -1004,7 +1004,7 @@ heap_create_with_catalog(const char *relname,
|
|||
ereport(NOTICE,
|
||||
(errcode(ERRCODE_DUPLICATE_TABLE),
|
||||
errmsg("relation \"%s\" already exists, skipping",
|
||||
relname)));
|
||||
relname)));
|
||||
heap_close(pg_class_desc, RowExclusiveLock);
|
||||
return InvalidOid;
|
||||
}
|
||||
|
@ -1048,8 +1048,8 @@ heap_create_with_catalog(const char *relname,
|
|||
if (!OidIsValid(relid))
|
||||
{
|
||||
/*
|
||||
* Use binary-upgrade override for pg_class.oid/relfilenode,
|
||||
* if supplied.
|
||||
* Use binary-upgrade override for pg_class.oid/relfilenode, if
|
||||
* supplied.
|
||||
*/
|
||||
if (OidIsValid(binary_upgrade_next_heap_pg_class_oid) &&
|
||||
(relkind == RELKIND_RELATION || relkind == RELKIND_SEQUENCE ||
|
||||
|
@ -1183,7 +1183,7 @@ heap_create_with_catalog(const char *relname,
|
|||
-1, /* typmod */
|
||||
0, /* array dimensions for typBaseType */
|
||||
false, /* Type NOT NULL */
|
||||
InvalidOid); /* typcollation */
|
||||
InvalidOid); /* typcollation */
|
||||
|
||||
pfree(relarrayname);
|
||||
}
|
||||
|
@ -1285,12 +1285,12 @@ heap_create_with_catalog(const char *relname,
|
|||
register_on_commit_action(relid, oncommit);
|
||||
|
||||
/*
|
||||
* If this is an unlogged relation, it needs an init fork so that it
|
||||
* can be correctly reinitialized on restart. Since we're going to
|
||||
* do an immediate sync, we ony need to xlog this if archiving or
|
||||
* streaming is enabled. And the immediate sync is required, because
|
||||
* otherwise there's no guarantee that this will hit the disk before
|
||||
* the next checkpoint moves the redo pointer.
|
||||
* If this is an unlogged relation, it needs an init fork so that it can
|
||||
* be correctly reinitialized on restart. Since we're going to do an
|
||||
* immediate sync, we ony need to xlog this if archiving or streaming is
|
||||
* enabled. And the immediate sync is required, because otherwise there's
|
||||
* no guarantee that this will hit the disk before the next checkpoint
|
||||
* moves the redo pointer.
|
||||
*/
|
||||
if (relpersistence == RELPERSISTENCE_UNLOGGED)
|
||||
{
|
||||
|
@ -1654,8 +1654,8 @@ heap_drop_with_catalog(Oid relid)
|
|||
|
||||
/*
|
||||
* There can no longer be anyone *else* touching the relation, but we
|
||||
* might still have open queries or cursors, or pending trigger events,
|
||||
* in our own session.
|
||||
* might still have open queries or cursors, or pending trigger events, in
|
||||
* our own session.
|
||||
*/
|
||||
CheckTableNotInUse(rel, "DROP TABLE");
|
||||
|
||||
|
@ -1664,8 +1664,8 @@ heap_drop_with_catalog(Oid relid)
|
|||
*/
|
||||
if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
|
||||
{
|
||||
Relation rel;
|
||||
HeapTuple tuple;
|
||||
Relation rel;
|
||||
HeapTuple tuple;
|
||||
|
||||
rel = heap_open(ForeignTableRelationId, RowExclusiveLock);
|
||||
|
||||
|
@ -1899,7 +1899,7 @@ StoreRelCheck(Relation rel, char *ccname, Node *expr,
|
|||
CONSTRAINT_CHECK, /* Constraint Type */
|
||||
false, /* Is Deferrable */
|
||||
false, /* Is Deferred */
|
||||
true, /* Is Validated */
|
||||
true, /* Is Validated */
|
||||
RelationGetRelid(rel), /* relation */
|
||||
attNos, /* attrs in the constraint */
|
||||
keycount, /* # attrs in the constraint */
|
||||
|
|
|
@ -187,18 +187,18 @@ index_check_primary_key(Relation heapRel,
|
|||
int i;
|
||||
|
||||
/*
|
||||
* If ALTER TABLE, check that there isn't already a PRIMARY KEY. In
|
||||
* CREATE TABLE, we have faith that the parser rejected multiple pkey
|
||||
* clauses; and CREATE INDEX doesn't have a way to say PRIMARY KEY, so
|
||||
* it's no problem either.
|
||||
* If ALTER TABLE, check that there isn't already a PRIMARY KEY. In CREATE
|
||||
* TABLE, we have faith that the parser rejected multiple pkey clauses;
|
||||
* and CREATE INDEX doesn't have a way to say PRIMARY KEY, so it's no
|
||||
* problem either.
|
||||
*/
|
||||
if (is_alter_table &&
|
||||
relationHasPrimaryKey(heapRel))
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
|
||||
errmsg("multiple primary keys for table \"%s\" are not allowed",
|
||||
RelationGetRelationName(heapRel))));
|
||||
errmsg("multiple primary keys for table \"%s\" are not allowed",
|
||||
RelationGetRelationName(heapRel))));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -222,7 +222,7 @@ index_check_primary_key(Relation heapRel,
|
|||
continue;
|
||||
|
||||
atttuple = SearchSysCache2(ATTNUM,
|
||||
ObjectIdGetDatum(RelationGetRelid(heapRel)),
|
||||
ObjectIdGetDatum(RelationGetRelid(heapRel)),
|
||||
Int16GetDatum(attnum));
|
||||
if (!HeapTupleIsValid(atttuple))
|
||||
elog(ERROR, "cache lookup failed for attribute %d of relation %u",
|
||||
|
@ -243,15 +243,14 @@ index_check_primary_key(Relation heapRel,
|
|||
}
|
||||
|
||||
/*
|
||||
* XXX: Shouldn't the ALTER TABLE .. SET NOT NULL cascade to child
|
||||
* tables? Currently, since the PRIMARY KEY itself doesn't cascade,
|
||||
* we don't cascade the notnull constraint(s) either; but this is
|
||||
* pretty debatable.
|
||||
* XXX: Shouldn't the ALTER TABLE .. SET NOT NULL cascade to child tables?
|
||||
* Currently, since the PRIMARY KEY itself doesn't cascade, we don't
|
||||
* cascade the notnull constraint(s) either; but this is pretty debatable.
|
||||
*
|
||||
* XXX: possible future improvement: when being called from ALTER
|
||||
* TABLE, it would be more efficient to merge this with the outer
|
||||
* ALTER TABLE, so as to avoid two scans. But that seems to
|
||||
* complicate DefineIndex's API unduly.
|
||||
* XXX: possible future improvement: when being called from ALTER TABLE,
|
||||
* it would be more efficient to merge this with the outer ALTER TABLE, so
|
||||
* as to avoid two scans. But that seems to complicate DefineIndex's API
|
||||
* unduly.
|
||||
*/
|
||||
if (cmds)
|
||||
AlterTableInternal(RelationGetRelid(heapRel), cmds, false);
|
||||
|
@ -788,8 +787,8 @@ index_create(Relation heapRelation,
|
|||
if (!OidIsValid(indexRelationId))
|
||||
{
|
||||
/*
|
||||
* Use binary-upgrade override for pg_class.oid/relfilenode,
|
||||
* if supplied.
|
||||
* Use binary-upgrade override for pg_class.oid/relfilenode, if
|
||||
* supplied.
|
||||
*/
|
||||
if (OidIsValid(binary_upgrade_next_index_pg_class_oid))
|
||||
{
|
||||
|
@ -872,7 +871,7 @@ index_create(Relation heapRelation,
|
|||
* ----------------
|
||||
*/
|
||||
UpdateIndexRelation(indexRelationId, heapRelationId, indexInfo,
|
||||
collationObjectId, classObjectId, coloptions, isprimary, is_exclusion,
|
||||
collationObjectId, classObjectId, coloptions, isprimary, is_exclusion,
|
||||
!deferrable,
|
||||
!concurrent);
|
||||
|
||||
|
@ -947,7 +946,7 @@ index_create(Relation heapRelation,
|
|||
|
||||
/*
|
||||
* If there are no simply-referenced columns, give the index an
|
||||
* auto dependency on the whole table. In most cases, this will
|
||||
* auto dependency on the whole table. In most cases, this will
|
||||
* be redundant, but it might not be if the index expressions and
|
||||
* predicate contain no Vars or only whole-row Vars.
|
||||
*/
|
||||
|
@ -1067,7 +1066,7 @@ index_create(Relation heapRelation,
|
|||
|
||||
/*
|
||||
* Close the index; but we keep the lock that we acquired above until end
|
||||
* of transaction. Closing the heap is caller's responsibility.
|
||||
* of transaction. Closing the heap is caller's responsibility.
|
||||
*/
|
||||
index_close(indexRelation, NoLock);
|
||||
|
||||
|
@ -1176,8 +1175,8 @@ index_constraint_create(Relation heapRelation,
|
|||
|
||||
/*
|
||||
* If the constraint is deferrable, create the deferred uniqueness
|
||||
* checking trigger. (The trigger will be given an internal
|
||||
* dependency on the constraint by CreateTrigger.)
|
||||
* checking trigger. (The trigger will be given an internal dependency on
|
||||
* the constraint by CreateTrigger.)
|
||||
*/
|
||||
if (deferrable)
|
||||
{
|
||||
|
@ -1213,7 +1212,7 @@ index_constraint_create(Relation heapRelation,
|
|||
* have been so marked already, so no need to clear the flag in the other
|
||||
* case.
|
||||
*
|
||||
* Note: this might better be done by callers. We do it here to avoid
|
||||
* Note: this might better be done by callers. We do it here to avoid
|
||||
* exposing index_update_stats() globally, but that wouldn't be necessary
|
||||
* if relhaspkey went away.
|
||||
*/
|
||||
|
@ -1235,10 +1234,10 @@ index_constraint_create(Relation heapRelation,
|
|||
*/
|
||||
if (update_pgindex && (mark_as_primary || deferrable))
|
||||
{
|
||||
Relation pg_index;
|
||||
HeapTuple indexTuple;
|
||||
Form_pg_index indexForm;
|
||||
bool dirty = false;
|
||||
Relation pg_index;
|
||||
HeapTuple indexTuple;
|
||||
Form_pg_index indexForm;
|
||||
bool dirty = false;
|
||||
|
||||
pg_index = heap_open(IndexRelationId, RowExclusiveLock);
|
||||
|
||||
|
@ -1303,8 +1302,8 @@ index_drop(Oid indexId)
|
|||
userIndexRelation = index_open(indexId, AccessExclusiveLock);
|
||||
|
||||
/*
|
||||
* There can no longer be anyone *else* touching the index, but we
|
||||
* might still have open queries using it in our own session.
|
||||
* There can no longer be anyone *else* touching the index, but we might
|
||||
* still have open queries using it in our own session.
|
||||
*/
|
||||
CheckTableNotInUse(userIndexRelation, "DROP INDEX");
|
||||
|
||||
|
@ -1739,7 +1738,8 @@ index_build(Relation heapRelation,
|
|||
*/
|
||||
if (heapRelation->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
|
||||
{
|
||||
RegProcedure ambuildempty = indexRelation->rd_am->ambuildempty;
|
||||
RegProcedure ambuildempty = indexRelation->rd_am->ambuildempty;
|
||||
|
||||
RelationOpenSmgr(indexRelation);
|
||||
smgrcreate(indexRelation->rd_smgr, INIT_FORKNUM, false);
|
||||
OidFunctionCall1(ambuildempty, PointerGetDatum(indexRelation));
|
||||
|
@ -2410,7 +2410,7 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
|
|||
ivinfo.strategy = NULL;
|
||||
|
||||
state.tuplesort = tuplesort_begin_datum(TIDOID,
|
||||
TIDLessOperator, InvalidOid, false,
|
||||
TIDLessOperator, InvalidOid, false,
|
||||
maintenance_work_mem,
|
||||
false);
|
||||
state.htups = state.itups = state.tups_inserted = 0;
|
||||
|
@ -2834,7 +2834,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks)
|
|||
* use catalog indexes while collecting the list.)
|
||||
*
|
||||
* To avoid deadlocks, VACUUM FULL or CLUSTER on a system catalog must omit the
|
||||
* REINDEX_CHECK_CONSTRAINTS flag. REINDEX should be used to rebuild an index
|
||||
* REINDEX_CHECK_CONSTRAINTS flag. REINDEX should be used to rebuild an index
|
||||
* if constraint inconsistency is suspected. For optimal performance, other
|
||||
* callers should include the flag only after transforming the data in a manner
|
||||
* that risks a change in constraint validity.
|
||||
|
|
|
@ -2446,10 +2446,10 @@ CheckSetNamespace(Oid oldNspOid, Oid nspOid, Oid classid, Oid objid)
|
|||
if (oldNspOid == nspOid)
|
||||
ereport(ERROR,
|
||||
(classid == RelationRelationId ?
|
||||
errcode(ERRCODE_DUPLICATE_TABLE) :
|
||||
errcode(ERRCODE_DUPLICATE_TABLE) :
|
||||
classid == ProcedureRelationId ?
|
||||
errcode(ERRCODE_DUPLICATE_FUNCTION) :
|
||||
errcode(ERRCODE_DUPLICATE_OBJECT),
|
||||
errcode(ERRCODE_DUPLICATE_FUNCTION) :
|
||||
errcode(ERRCODE_DUPLICATE_OBJECT),
|
||||
errmsg("%s is already in schema \"%s\"",
|
||||
getObjectDescriptionOids(classid, objid),
|
||||
get_namespace_name(nspOid))));
|
||||
|
@ -2458,7 +2458,7 @@ CheckSetNamespace(Oid oldNspOid, Oid nspOid, Oid classid, Oid objid)
|
|||
if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("cannot move objects into or out of temporary schemas")));
|
||||
errmsg("cannot move objects into or out of temporary schemas")));
|
||||
|
||||
/* same for TOAST schema */
|
||||
if (nspOid == PG_TOAST_NAMESPACE || oldNspOid == PG_TOAST_NAMESPACE)
|
||||
|
@ -2525,7 +2525,7 @@ QualifiedNameGetCreationNamespace(List *names, char **objname_p)
|
|||
/*
|
||||
* get_namespace_oid - given a namespace name, look up the OID
|
||||
*
|
||||
* If missing_ok is false, throw an error if namespace name not found. If
|
||||
* If missing_ok is false, throw an error if namespace name not found. If
|
||||
* true, just return InvalidOid.
|
||||
*/
|
||||
Oid
|
||||
|
@ -2535,9 +2535,9 @@ get_namespace_oid(const char *nspname, bool missing_ok)
|
|||
|
||||
oid = GetSysCacheOid1(NAMESPACENAME, CStringGetDatum(nspname));
|
||||
if (!OidIsValid(oid) && !missing_ok)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_SCHEMA),
|
||||
errmsg("schema \"%s\" does not exist", nspname)));
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_SCHEMA),
|
||||
errmsg("schema \"%s\" does not exist", nspname)));
|
||||
|
||||
return oid;
|
||||
}
|
||||
|
@ -2727,7 +2727,7 @@ GetTempNamespaceBackendId(Oid namespaceId)
|
|||
/* See if the namespace name starts with "pg_temp_" or "pg_toast_temp_" */
|
||||
nspname = get_namespace_name(namespaceId);
|
||||
if (!nspname)
|
||||
return InvalidBackendId; /* no such namespace? */
|
||||
return InvalidBackendId; /* no such namespace? */
|
||||
if (strncmp(nspname, "pg_temp_", 8) == 0)
|
||||
result = atoi(nspname + 8);
|
||||
else if (strncmp(nspname, "pg_toast_temp_", 14) == 0)
|
||||
|
@ -2798,8 +2798,8 @@ GetOverrideSearchPath(MemoryContext context)
|
|||
*
|
||||
* It's possible that newpath->useTemp is set but there is no longer any
|
||||
* active temp namespace, if the path was saved during a transaction that
|
||||
* created a temp namespace and was later rolled back. In that case we just
|
||||
* ignore useTemp. A plausible alternative would be to create a new temp
|
||||
* created a temp namespace and was later rolled back. In that case we just
|
||||
* ignore useTemp. A plausible alternative would be to create a new temp
|
||||
* namespace, but for existing callers that's not necessary because an empty
|
||||
* temp namespace wouldn't affect their results anyway.
|
||||
*
|
||||
|
@ -3522,7 +3522,7 @@ check_search_path(char **newval, void **extra, GucSource source)
|
|||
if (source == PGC_S_TEST)
|
||||
ereport(NOTICE,
|
||||
(errcode(ERRCODE_UNDEFINED_SCHEMA),
|
||||
errmsg("schema \"%s\" does not exist", curname)));
|
||||
errmsg("schema \"%s\" does not exist", curname)));
|
||||
else
|
||||
{
|
||||
GUC_check_errdetail("schema \"%s\" does not exist", curname);
|
||||
|
|
|
@ -78,7 +78,7 @@ static Relation get_relation_by_qualified_name(ObjectType objtype,
|
|||
static ObjectAddress get_object_address_relobject(ObjectType objtype,
|
||||
List *objname, Relation *relp);
|
||||
static ObjectAddress get_object_address_attribute(ObjectType objtype,
|
||||
List *objname, Relation *relp, LOCKMODE lockmode);
|
||||
List *objname, Relation *relp, LOCKMODE lockmode);
|
||||
static ObjectAddress get_object_address_opcf(ObjectType objtype, List *objname,
|
||||
List *objargs);
|
||||
static bool object_exists(ObjectAddress address);
|
||||
|
@ -108,8 +108,8 @@ ObjectAddress
|
|||
get_object_address(ObjectType objtype, List *objname, List *objargs,
|
||||
Relation *relp, LOCKMODE lockmode)
|
||||
{
|
||||
ObjectAddress address;
|
||||
Relation relation = NULL;
|
||||
ObjectAddress address;
|
||||
Relation relation = NULL;
|
||||
|
||||
/* Some kind of lock must be taken. */
|
||||
Assert(lockmode != NoLock);
|
||||
|
@ -130,7 +130,7 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
|
|||
case OBJECT_COLUMN:
|
||||
address =
|
||||
get_object_address_attribute(objtype, objname, &relation,
|
||||
lockmode);
|
||||
lockmode);
|
||||
break;
|
||||
case OBJECT_RULE:
|
||||
case OBJECT_TRIGGER:
|
||||
|
@ -201,10 +201,10 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
|
|||
break;
|
||||
case OBJECT_CAST:
|
||||
{
|
||||
TypeName *sourcetype = (TypeName *) linitial(objname);
|
||||
TypeName *targettype = (TypeName *) linitial(objargs);
|
||||
Oid sourcetypeid = typenameTypeId(NULL, sourcetype);
|
||||
Oid targettypeid = typenameTypeId(NULL, targettype);
|
||||
TypeName *sourcetype = (TypeName *) linitial(objname);
|
||||
TypeName *targettype = (TypeName *) linitial(objargs);
|
||||
Oid sourcetypeid = typenameTypeId(NULL, sourcetype);
|
||||
Oid targettypeid = typenameTypeId(NULL, targettype);
|
||||
|
||||
address.classId = CastRelationId;
|
||||
address.objectId =
|
||||
|
@ -242,8 +242,8 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
|
|||
|
||||
/*
|
||||
* If we're dealing with a relation or attribute, then the relation is
|
||||
* already locked. If we're dealing with any other type of object, we need
|
||||
* to lock it and then verify that it still exists.
|
||||
* already locked. If we're dealing with any other type of object, we
|
||||
* need to lock it and then verify that it still exists.
|
||||
*/
|
||||
if (address.classId != RelationRelationId)
|
||||
{
|
||||
|
@ -308,7 +308,7 @@ get_object_address_unqualified(ObjectType objtype, List *qualname)
|
|||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized objtype: %d", (int) objtype);
|
||||
msg = NULL; /* placate compiler */
|
||||
msg = NULL; /* placate compiler */
|
||||
}
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
|
@ -379,7 +379,7 @@ static Relation
|
|||
get_relation_by_qualified_name(ObjectType objtype, List *objname,
|
||||
LOCKMODE lockmode)
|
||||
{
|
||||
Relation relation;
|
||||
Relation relation;
|
||||
|
||||
relation = relation_openrv(makeRangeVarFromNameList(objname), lockmode);
|
||||
switch (objtype)
|
||||
|
@ -449,7 +449,7 @@ get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp)
|
|||
nnames = list_length(objname);
|
||||
if (nnames < 2)
|
||||
{
|
||||
Oid reloid;
|
||||
Oid reloid;
|
||||
|
||||
/*
|
||||
* For compatibility with very old releases, we sometimes allow users
|
||||
|
@ -514,7 +514,7 @@ static ObjectAddress
|
|||
get_object_address_attribute(ObjectType objtype, List *objname,
|
||||
Relation *relp, LOCKMODE lockmode)
|
||||
{
|
||||
ObjectAddress address;
|
||||
ObjectAddress address;
|
||||
List *relname;
|
||||
Oid reloid;
|
||||
Relation relation;
|
||||
|
@ -534,7 +534,7 @@ get_object_address_attribute(ObjectType objtype, List *objname,
|
|||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
||||
errmsg("column \"%s\" of relation \"%s\" does not exist",
|
||||
attname, RelationGetRelationName(relation))));
|
||||
attname, RelationGetRelationName(relation))));
|
||||
|
||||
*relp = relation;
|
||||
return address;
|
||||
|
@ -584,8 +584,8 @@ object_exists(ObjectAddress address)
|
|||
int cache = -1;
|
||||
Oid indexoid = InvalidOid;
|
||||
Relation rel;
|
||||
ScanKeyData skey[1];
|
||||
SysScanDesc sd;
|
||||
ScanKeyData skey[1];
|
||||
SysScanDesc sd;
|
||||
bool found;
|
||||
|
||||
/* Sub-objects require special treatment. */
|
||||
|
@ -609,9 +609,9 @@ object_exists(ObjectAddress address)
|
|||
|
||||
/*
|
||||
* For object types that have a relevant syscache, we use it; for
|
||||
* everything else, we'll have to do an index-scan. This switch
|
||||
* sets either the cache to be used for the syscache lookup, or the
|
||||
* index to be used for the index scan.
|
||||
* everything else, we'll have to do an index-scan. This switch sets
|
||||
* either the cache to be used for the syscache lookup, or the index to be
|
||||
* used for the index scan.
|
||||
*/
|
||||
switch (address.classId)
|
||||
{
|
||||
|
@ -664,6 +664,7 @@ object_exists(ObjectAddress address)
|
|||
cache = OPFAMILYOID;
|
||||
break;
|
||||
case LargeObjectRelationId:
|
||||
|
||||
/*
|
||||
* Weird backward compatibility hack: ObjectAddress notation uses
|
||||
* LargeObjectRelationId for large objects, but since PostgreSQL
|
||||
|
@ -816,15 +817,15 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
|
|||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("must be owner of large object %u",
|
||||
address.objectId)));
|
||||
address.objectId)));
|
||||
break;
|
||||
case OBJECT_CAST:
|
||||
{
|
||||
/* We can only check permissions on the source/target types */
|
||||
TypeName *sourcetype = (TypeName *) linitial(objname);
|
||||
TypeName *targettype = (TypeName *) linitial(objargs);
|
||||
Oid sourcetypeid = typenameTypeId(NULL, sourcetype);
|
||||
Oid targettypeid = typenameTypeId(NULL, targettype);
|
||||
TypeName *sourcetype = (TypeName *) linitial(objname);
|
||||
TypeName *targettype = (TypeName *) linitial(objargs);
|
||||
Oid sourcetypeid = typenameTypeId(NULL, sourcetype);
|
||||
Oid targettypeid = typenameTypeId(NULL, targettype);
|
||||
|
||||
if (!pg_type_ownercheck(sourcetypeid, roleid)
|
||||
&& !pg_type_ownercheck(targettypeid, roleid))
|
||||
|
@ -851,6 +852,7 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
|
|||
NameListToString(objname));
|
||||
break;
|
||||
case OBJECT_ROLE:
|
||||
|
||||
/*
|
||||
* We treat roles as being "owned" by those with CREATEROLE priv,
|
||||
* except that superusers are only owned by superusers.
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue