mirror of
https://github.com/postgres/postgres.git
synced 2025-04-20 00:42:27 +03:00
Pgindent run for 8.0.
This commit is contained in:
parent
90cb9c3051
commit
b6b71b85bc
@ -25,32 +25,38 @@ Datum gbt_bit_same(PG_FUNCTION_ARGS);
|
||||
|
||||
/* define for comparison */
|
||||
|
||||
static bool gbt_bitgt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_bitgt(const void *a, const void *b)
|
||||
{
|
||||
return (DatumGetBool(DirectFunctionCall2(bitgt, PointerGetDatum(a), PointerGetDatum(b))));
|
||||
}
|
||||
|
||||
static bool gbt_bitge (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_bitge(const void *a, const void *b)
|
||||
{
|
||||
return (DatumGetBool(DirectFunctionCall2(bitge, PointerGetDatum(a), PointerGetDatum(b))));
|
||||
}
|
||||
|
||||
static bool gbt_biteq (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_biteq(const void *a, const void *b)
|
||||
{
|
||||
return (DatumGetBool(DirectFunctionCall2(biteq, PointerGetDatum(a), PointerGetDatum(b))));
|
||||
}
|
||||
|
||||
static bool gbt_bitle (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_bitle(const void *a, const void *b)
|
||||
{
|
||||
return (DatumGetBool(DirectFunctionCall2(bitle, PointerGetDatum(a), PointerGetDatum(b))));
|
||||
}
|
||||
|
||||
static bool gbt_bitlt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_bitlt(const void *a, const void *b)
|
||||
{
|
||||
return (DatumGetBool(DirectFunctionCall2(bitlt, PointerGetDatum(a), PointerGetDatum(b))));
|
||||
}
|
||||
|
||||
static int32 gbt_bitcmp ( const bytea * a , const bytea * b )
|
||||
static int32
|
||||
gbt_bitcmp(const bytea *a, const bytea *b)
|
||||
{
|
||||
return
|
||||
(DatumGetInt32(DirectFunctionCall2(byteacmp, PointerGetDatum(a), PointerGetDatum(b))));
|
||||
@ -72,7 +78,8 @@ gbt_bit_xfrm ( bytea * leaf )
|
||||
|
||||
|
||||
|
||||
static GBT_VARKEY * gbt_bit_l2n ( GBT_VARKEY * leaf )
|
||||
static GBT_VARKEY *
|
||||
gbt_bit_l2n(GBT_VARKEY * leaf)
|
||||
{
|
||||
|
||||
GBT_VARKEY *out = leaf;
|
||||
@ -111,6 +118,7 @@ Datum
|
||||
gbt_bit_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
|
||||
PG_RETURN_POINTER(gbt_var_compress(entry, &tinfo));
|
||||
}
|
||||
|
||||
@ -127,20 +135,19 @@ gbt_bit_consistent(PG_FUNCTION_ARGS)
|
||||
GBT_VARKEY_R r = gbt_var_key_readable(key);
|
||||
|
||||
if (GIST_LEAF(entry))
|
||||
{
|
||||
retval = gbt_var_consistent(&r, query, &strategy, TRUE, &tinfo);
|
||||
} else {
|
||||
else
|
||||
{
|
||||
bytea *q = gbt_bit_xfrm((bytea *) query);
|
||||
|
||||
retval = gbt_var_consistent(&r, (void *) q, &strategy, FALSE, &tinfo);
|
||||
pfree(q);
|
||||
}
|
||||
|
||||
if ( ktst != key ){
|
||||
if (ktst != key)
|
||||
pfree(key);
|
||||
}
|
||||
if ( qtst != query ){
|
||||
if (qtst != query)
|
||||
pfree(query);
|
||||
}
|
||||
PG_RETURN_BOOL(retval);
|
||||
}
|
||||
|
||||
@ -151,6 +158,7 @@ gbt_bit_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
||||
int32 *size = (int *) PG_GETARG_POINTER(1);
|
||||
|
||||
PG_RETURN_POINTER(gbt_var_union(entryvec, size, &tinfo));
|
||||
}
|
||||
|
||||
@ -160,6 +168,7 @@ gbt_bit_picksplit(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
||||
GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
|
||||
|
||||
gbt_var_picksplit(entryvec, v, &tinfo);
|
||||
PG_RETURN_POINTER(v);
|
||||
}
|
||||
@ -170,6 +179,7 @@ gbt_bit_same(PG_FUNCTION_ARGS)
|
||||
Datum d1 = PG_GETARG_DATUM(0);
|
||||
Datum d2 = PG_GETARG_DATUM(1);
|
||||
bool *result = (bool *) PG_GETARG_POINTER(2);
|
||||
|
||||
PG_RETURN_POINTER(gbt_var_same(result, d1, d2, &tinfo));
|
||||
}
|
||||
|
||||
@ -180,6 +190,6 @@ gbt_bit_penalty(PG_FUNCTION_ARGS)
|
||||
float *result = (float *) PG_GETARG_POINTER(2);
|
||||
GISTENTRY *o = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
GISTENTRY *n = (GISTENTRY *) PG_GETARG_POINTER(1);
|
||||
|
||||
PG_RETURN_POINTER(gbt_var_penalty(result, o, n, &tinfo));
|
||||
}
|
||||
|
||||
|
@ -23,33 +23,39 @@ Datum gbt_bytea_same(PG_FUNCTION_ARGS);
|
||||
|
||||
/* define for comparison */
|
||||
|
||||
static bool gbt_byteagt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_byteagt(const void *a, const void *b)
|
||||
{
|
||||
return (DatumGetBool(DirectFunctionCall2(byteagt, PointerGetDatum(a), PointerGetDatum(b))));
|
||||
}
|
||||
|
||||
static bool gbt_byteage (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_byteage(const void *a, const void *b)
|
||||
{
|
||||
return (DatumGetBool(DirectFunctionCall2(byteage, PointerGetDatum(a), PointerGetDatum(b))));
|
||||
}
|
||||
|
||||
static bool gbt_byteaeq (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_byteaeq(const void *a, const void *b)
|
||||
{
|
||||
return (DatumGetBool(DirectFunctionCall2(byteaeq, PointerGetDatum(a), PointerGetDatum(b))));
|
||||
}
|
||||
|
||||
static bool gbt_byteale (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_byteale(const void *a, const void *b)
|
||||
{
|
||||
return (DatumGetBool(DirectFunctionCall2(byteale, PointerGetDatum(a), PointerGetDatum(b))));
|
||||
}
|
||||
|
||||
static bool gbt_bytealt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_bytealt(const void *a, const void *b)
|
||||
{
|
||||
return (DatumGetBool(DirectFunctionCall2(bytealt, PointerGetDatum(a), PointerGetDatum(b))));
|
||||
}
|
||||
|
||||
|
||||
static int32 gbt_byteacmp ( const bytea * a , const bytea * b )
|
||||
static int32
|
||||
gbt_byteacmp(const bytea *a, const bytea *b)
|
||||
{
|
||||
return
|
||||
(DatumGetInt32(DirectFunctionCall2(byteacmp, PointerGetDatum(a), PointerGetDatum(b))));
|
||||
@ -80,6 +86,7 @@ Datum
|
||||
gbt_bytea_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
|
||||
PG_RETURN_POINTER(gbt_var_compress(entry, &tinfo));
|
||||
}
|
||||
|
||||
@ -99,12 +106,10 @@ gbt_bytea_consistent(PG_FUNCTION_ARGS)
|
||||
|
||||
retval = gbt_var_consistent(&r, query, &strategy, GIST_LEAF(entry), &tinfo);
|
||||
|
||||
if ( ktst != key ){
|
||||
if (ktst != key)
|
||||
pfree(key);
|
||||
}
|
||||
if ( qtst != query ){
|
||||
if (qtst != query)
|
||||
pfree(query);
|
||||
}
|
||||
PG_RETURN_BOOL(retval);
|
||||
}
|
||||
|
||||
@ -115,6 +120,7 @@ gbt_bytea_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
||||
int32 *size = (int *) PG_GETARG_POINTER(1);
|
||||
|
||||
PG_RETURN_POINTER(gbt_var_union(entryvec, size, &tinfo));
|
||||
}
|
||||
|
||||
@ -124,6 +130,7 @@ gbt_bytea_picksplit(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
||||
GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
|
||||
|
||||
gbt_var_picksplit(entryvec, v, &tinfo);
|
||||
PG_RETURN_POINTER(v);
|
||||
}
|
||||
@ -134,6 +141,7 @@ gbt_bytea_same(PG_FUNCTION_ARGS)
|
||||
Datum d1 = PG_GETARG_DATUM(0);
|
||||
Datum d2 = PG_GETARG_DATUM(1);
|
||||
bool *result = (bool *) PG_GETARG_POINTER(2);
|
||||
|
||||
PG_RETURN_POINTER(gbt_var_same(result, d1, d2, &tinfo));
|
||||
}
|
||||
|
||||
@ -144,6 +152,6 @@ gbt_bytea_penalty(PG_FUNCTION_ARGS)
|
||||
float *result = (float *) PG_GETARG_POINTER(2);
|
||||
GISTENTRY *o = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
GISTENTRY *n = (GISTENTRY *) PG_GETARG_POINTER(1);
|
||||
|
||||
PG_RETURN_POINTER(gbt_var_penalty(result, o, n, &tinfo));
|
||||
}
|
||||
|
||||
|
@ -25,23 +25,28 @@ Datum gbt_cash_consistent(PG_FUNCTION_ARGS);
|
||||
Datum gbt_cash_penalty(PG_FUNCTION_ARGS);
|
||||
Datum gbt_cash_same(PG_FUNCTION_ARGS);
|
||||
|
||||
static bool gbt_cashgt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_cashgt(const void *a, const void *b)
|
||||
{
|
||||
return (*((Cash *) a) > *((Cash *) b));
|
||||
}
|
||||
static bool gbt_cashge (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_cashge(const void *a, const void *b)
|
||||
{
|
||||
return (*((Cash *) a) >= *((Cash *) b));
|
||||
}
|
||||
static bool gbt_casheq (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_casheq(const void *a, const void *b)
|
||||
{
|
||||
return (*((Cash *) a) == *((Cash *) b));
|
||||
}
|
||||
static bool gbt_cashle (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_cashle(const void *a, const void *b)
|
||||
{
|
||||
return (*((Cash *) a) <= *((Cash *) b));
|
||||
}
|
||||
static bool gbt_cashlt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_cashlt(const void *a, const void *b)
|
||||
{
|
||||
return (*((Cash *) a) < *((Cash *) b));
|
||||
}
|
||||
@ -50,12 +55,10 @@ static int
|
||||
gbt_cashkey_cmp(const void *a, const void *b)
|
||||
{
|
||||
|
||||
if ( *(Cash*)&(((Nsrt *) a)->t[0]) > *(Cash*)&(((Nsrt *) b)->t[0]) ){
|
||||
if (*(Cash *) &(((Nsrt *) a)->t[0]) > *(Cash *) &(((Nsrt *) b)->t[0]))
|
||||
return 1;
|
||||
} else
|
||||
if ( *(Cash*)&(((Nsrt *) a)->t[0]) < *(Cash*)&(((Nsrt *) b)->t[0]) ){
|
||||
else if (*(Cash *) &(((Nsrt *) a)->t[0]) < *(Cash *) &(((Nsrt *) b)->t[0]))
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
@ -84,6 +87,7 @@ gbt_cash_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
GISTENTRY *retval = NULL;
|
||||
|
||||
PG_RETURN_POINTER(gbt_num_compress(retval, entry, &tinfo));
|
||||
}
|
||||
|
||||
@ -96,6 +100,7 @@ gbt_cash_consistent(PG_FUNCTION_ARGS)
|
||||
cashKEY *kkk = (cashKEY *) DatumGetPointer(entry->key);
|
||||
GBT_NUMKEY_R key;
|
||||
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
|
||||
|
||||
key.lower = (GBT_NUMKEY *) & kkk->lower;
|
||||
key.upper = (GBT_NUMKEY *) & kkk->upper;
|
||||
|
||||
@ -110,6 +115,7 @@ gbt_cash_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
||||
void *out = palloc(sizeof(cashKEY));
|
||||
|
||||
*(int *) PG_GETARG_POINTER(1) = sizeof(cashKEY);
|
||||
PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
|
||||
}
|
||||
@ -128,7 +134,8 @@ gbt_cash_penalty(PG_FUNCTION_ARGS)
|
||||
|
||||
penalty_range_enlarge(origentry->lower, origentry->upper, newentry->lower, newentry->upper);
|
||||
|
||||
if ( res > 0 ){
|
||||
if (res > 0)
|
||||
{
|
||||
*result += FLT_MIN;
|
||||
*result += (float) (res / ((double) (res + origentry->upper - origentry->lower)));
|
||||
*result *= (FLT_MAX / (((GISTENTRY *) PG_GETARG_POINTER(0))->rel->rd_att->natts + 1));
|
||||
@ -158,5 +165,3 @@ gbt_cash_same(PG_FUNCTION_ARGS)
|
||||
*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
|
||||
|
@ -25,35 +25,40 @@ Datum gbt_date_consistent(PG_FUNCTION_ARGS);
|
||||
Datum gbt_date_penalty(PG_FUNCTION_ARGS);
|
||||
Datum gbt_date_same(PG_FUNCTION_ARGS);
|
||||
|
||||
static bool gbt_dategt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_dategt(const void *a, const void *b)
|
||||
{
|
||||
return DatumGetBool(
|
||||
DirectFunctionCall2(date_gt, DateADTGetDatum(*((DateADT *) a)), DateADTGetDatum(*((DateADT *) b)))
|
||||
);
|
||||
}
|
||||
|
||||
static bool gbt_datege (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_datege(const void *a, const void *b)
|
||||
{
|
||||
return DatumGetBool(
|
||||
DirectFunctionCall2(date_ge, DateADTGetDatum(*((DateADT *) a)), DateADTGetDatum(*((DateADT *) b)))
|
||||
);
|
||||
}
|
||||
|
||||
static bool gbt_dateeq (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_dateeq(const void *a, const void *b)
|
||||
{
|
||||
return DatumGetBool(
|
||||
DirectFunctionCall2(date_eq, DateADTGetDatum(*((DateADT *) a)), DateADTGetDatum(*((DateADT *) b)))
|
||||
);
|
||||
}
|
||||
|
||||
static bool gbt_datele (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_datele(const void *a, const void *b)
|
||||
{
|
||||
return DatumGetBool(
|
||||
DirectFunctionCall2(date_le, DateADTGetDatum(*((DateADT *) a)), DateADTGetDatum(*((DateADT *) b)))
|
||||
);
|
||||
}
|
||||
|
||||
static bool gbt_datelt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_datelt(const void *a, const void *b)
|
||||
{
|
||||
return DatumGetBool(
|
||||
DirectFunctionCall2(date_lt, DateADTGetDatum(*((DateADT *) a)), DateADTGetDatum(*((DateADT *) b)))
|
||||
@ -65,12 +70,10 @@ static bool gbt_datelt (const void *a, const void *b)
|
||||
static int
|
||||
gbt_datekey_cmp(const void *a, const void *b)
|
||||
{
|
||||
if ( gbt_dategt( (void*)&(((Nsrt *) a)->t[0]) , (void*)&(((Nsrt *) b)->t[0]) ) ){
|
||||
if (gbt_dategt((void *) &(((Nsrt *) a)->t[0]), (void *) &(((Nsrt *) b)->t[0])))
|
||||
return 1;
|
||||
} else
|
||||
if ( gbt_datelt( (void*)&(((Nsrt *) a)->t[0]) , (void*)&(((Nsrt *) b)->t[0]) ) ){
|
||||
else if (gbt_datelt((void *) &(((Nsrt *) a)->t[0]), (void *) &(((Nsrt *) b)->t[0])))
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -99,6 +102,7 @@ gbt_date_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
GISTENTRY *retval = NULL;
|
||||
|
||||
PG_RETURN_POINTER(gbt_num_compress(retval, entry, &tinfo));
|
||||
}
|
||||
|
||||
@ -127,6 +131,7 @@ gbt_date_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
||||
void *out = palloc(sizeof(dateKEY));
|
||||
|
||||
*(int *) PG_GETARG_POINTER(1) = sizeof(dateKEY);
|
||||
PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
|
||||
}
|
||||
@ -138,7 +143,8 @@ gbt_date_penalty(PG_FUNCTION_ARGS)
|
||||
dateKEY *origentry = (dateKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
|
||||
dateKEY *newentry = (dateKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
|
||||
float *result = (float *) PG_GETARG_POINTER(2);
|
||||
int32 diff, res ;
|
||||
int32 diff,
|
||||
res;
|
||||
|
||||
diff = DatumGetInt32(DirectFunctionCall2(
|
||||
date_mi,
|
||||
@ -156,7 +162,8 @@ gbt_date_penalty(PG_FUNCTION_ARGS)
|
||||
|
||||
*result = 0.0;
|
||||
|
||||
if ( res > 0 ){
|
||||
if (res > 0)
|
||||
{
|
||||
diff = DatumGetInt32(DirectFunctionCall2(
|
||||
date_mi,
|
||||
DateADTGetDatum(origentry->upper),
|
||||
|
@ -24,23 +24,28 @@ Datum gbt_float4_consistent(PG_FUNCTION_ARGS);
|
||||
Datum gbt_float4_penalty(PG_FUNCTION_ARGS);
|
||||
Datum gbt_float4_same(PG_FUNCTION_ARGS);
|
||||
|
||||
static bool gbt_float4gt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_float4gt(const void *a, const void *b)
|
||||
{
|
||||
return (*((float4 *) a) > *((float4 *) b));
|
||||
}
|
||||
static bool gbt_float4ge (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_float4ge(const void *a, const void *b)
|
||||
{
|
||||
return (*((float4 *) a) >= *((float4 *) b));
|
||||
}
|
||||
static bool gbt_float4eq (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_float4eq(const void *a, const void *b)
|
||||
{
|
||||
return (*((float4 *) a) == *((float4 *) b));
|
||||
}
|
||||
static bool gbt_float4le (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_float4le(const void *a, const void *b)
|
||||
{
|
||||
return (*((float4 *) a) <= *((float4 *) b));
|
||||
}
|
||||
static bool gbt_float4lt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_float4lt(const void *a, const void *b)
|
||||
{
|
||||
return (*((float4 *) a) < *((float4 *) b));
|
||||
}
|
||||
@ -49,12 +54,10 @@ static int
|
||||
gbt_float4key_cmp(const void *a, const void *b)
|
||||
{
|
||||
|
||||
if ( *(float4*)&(((Nsrt *) a)->t[0]) > *(float4*)&(((Nsrt *) b)->t[0]) ){
|
||||
if (*(float4 *) &(((Nsrt *) a)->t[0]) > *(float4 *) &(((Nsrt *) b)->t[0]))
|
||||
return 1;
|
||||
} else
|
||||
if ( *(float4*)&(((Nsrt *) a)->t[0]) < *(float4*)&(((Nsrt *) b)->t[0]) ){
|
||||
else if (*(float4 *) &(((Nsrt *) a)->t[0]) < *(float4 *) &(((Nsrt *) b)->t[0]))
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
@ -83,6 +86,7 @@ gbt_float4_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
GISTENTRY *retval = NULL;
|
||||
|
||||
PG_RETURN_POINTER(gbt_num_compress(retval, entry, &tinfo));
|
||||
}
|
||||
|
||||
@ -95,6 +99,7 @@ gbt_float4_consistent(PG_FUNCTION_ARGS)
|
||||
float4KEY *kkk = (float4KEY *) DatumGetPointer(entry->key);
|
||||
GBT_NUMKEY_R key;
|
||||
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
|
||||
|
||||
key.lower = (GBT_NUMKEY *) & kkk->lower;
|
||||
key.upper = (GBT_NUMKEY *) & kkk->upper;
|
||||
|
||||
@ -109,6 +114,7 @@ gbt_float4_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
||||
void *out = palloc(sizeof(float4KEY));
|
||||
|
||||
*(int *) PG_GETARG_POINTER(1) = sizeof(float4KEY);
|
||||
PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
|
||||
}
|
||||
@ -127,7 +133,8 @@ gbt_float4_penalty(PG_FUNCTION_ARGS)
|
||||
|
||||
penalty_range_enlarge(origentry->lower, origentry->upper, newentry->lower, newentry->upper);
|
||||
|
||||
if ( res > 0 ){
|
||||
if (res > 0)
|
||||
{
|
||||
*result += FLT_MIN;
|
||||
*result += (float) (res / ((double) (res + origentry->upper - origentry->lower)));
|
||||
*result *= (FLT_MAX / (((GISTENTRY *) PG_GETARG_POINTER(0))->rel->rd_att->natts + 1));
|
||||
@ -157,4 +164,3 @@ gbt_float4_same(PG_FUNCTION_ARGS)
|
||||
*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
|
@ -25,23 +25,28 @@ Datum gbt_float8_penalty(PG_FUNCTION_ARGS);
|
||||
Datum gbt_float8_same(PG_FUNCTION_ARGS);
|
||||
|
||||
|
||||
static bool gbt_float8gt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_float8gt(const void *a, const void *b)
|
||||
{
|
||||
return (*((float8 *) a) > *((float8 *) b));
|
||||
}
|
||||
static bool gbt_float8ge (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_float8ge(const void *a, const void *b)
|
||||
{
|
||||
return (*((float8 *) a) >= *((float8 *) b));
|
||||
}
|
||||
static bool gbt_float8eq (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_float8eq(const void *a, const void *b)
|
||||
{
|
||||
return (*((float8 *) a) == *((float8 *) b));
|
||||
}
|
||||
static bool gbt_float8le (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_float8le(const void *a, const void *b)
|
||||
{
|
||||
return (*((float8 *) a) <= *((float8 *) b));
|
||||
}
|
||||
static bool gbt_float8lt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_float8lt(const void *a, const void *b)
|
||||
{
|
||||
return (*((float8 *) a) < *((float8 *) b));
|
||||
}
|
||||
@ -50,12 +55,10 @@ static int
|
||||
gbt_float8key_cmp(const void *a, const void *b)
|
||||
{
|
||||
|
||||
if ( *(float8*)&(((Nsrt *) a)->t[0]) > *(float8*)&(((Nsrt *) b)->t[0]) ){
|
||||
if (*(float8 *) &(((Nsrt *) a)->t[0]) > *(float8 *) &(((Nsrt *) b)->t[0]))
|
||||
return 1;
|
||||
} else
|
||||
if ( *(float8*)&(((Nsrt *) a)->t[0]) < *(float8*)&(((Nsrt *) b)->t[0]) ){
|
||||
else if (*(float8 *) &(((Nsrt *) a)->t[0]) < *(float8 *) &(((Nsrt *) b)->t[0]))
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
@ -84,6 +87,7 @@ gbt_float8_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
GISTENTRY *retval = NULL;
|
||||
|
||||
PG_RETURN_POINTER(gbt_num_compress(retval, entry, &tinfo));
|
||||
}
|
||||
|
||||
@ -97,6 +101,7 @@ gbt_float8_consistent(PG_FUNCTION_ARGS)
|
||||
float8KEY *kkk = (float8KEY *) DatumGetPointer(entry->key);
|
||||
GBT_NUMKEY_R key;
|
||||
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
|
||||
|
||||
key.lower = (GBT_NUMKEY *) & kkk->lower;
|
||||
key.upper = (GBT_NUMKEY *) & kkk->upper;
|
||||
|
||||
@ -111,6 +116,7 @@ gbt_float8_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
||||
void *out = palloc(sizeof(float8KEY));
|
||||
|
||||
*(int *) PG_GETARG_POINTER(1) = sizeof(float8KEY);
|
||||
PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
|
||||
}
|
||||
@ -129,7 +135,8 @@ gbt_float8_penalty(PG_FUNCTION_ARGS)
|
||||
|
||||
penalty_range_enlarge(origentry->lower, origentry->upper, newentry->lower, newentry->upper);
|
||||
|
||||
if ( res > 0 ){
|
||||
if (res > 0)
|
||||
{
|
||||
*result += FLT_MIN;
|
||||
*result += (float) (res / ((double) (res + origentry->upper - origentry->lower)));
|
||||
*result *= (FLT_MAX / (((GISTENTRY *) PG_GETARG_POINTER(0))->rel->rd_att->natts + 1));
|
||||
|
@ -42,4 +42,3 @@ gbt_decompress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_POINTER(PG_GETARG_POINTER(0));
|
||||
}
|
||||
|
||||
|
@ -32,23 +32,28 @@ Datum gbt_inet_penalty(PG_FUNCTION_ARGS);
|
||||
Datum gbt_inet_same(PG_FUNCTION_ARGS);
|
||||
|
||||
|
||||
static bool gbt_inetgt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_inetgt(const void *a, const void *b)
|
||||
{
|
||||
return (*((double *) a) > *((double *) b));
|
||||
}
|
||||
static bool gbt_inetge (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_inetge(const void *a, const void *b)
|
||||
{
|
||||
return (*((double *) a) >= *((double *) b));
|
||||
}
|
||||
static bool gbt_ineteq (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_ineteq(const void *a, const void *b)
|
||||
{
|
||||
return (*((double *) a) == *((double *) b));
|
||||
}
|
||||
static bool gbt_inetle (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_inetle(const void *a, const void *b)
|
||||
{
|
||||
return (*((double *) a) <= *((double *) b));
|
||||
}
|
||||
static bool gbt_inetlt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_inetlt(const void *a, const void *b)
|
||||
{
|
||||
return (*((double *) a) < *((double *) b));
|
||||
}
|
||||
@ -57,12 +62,10 @@ static int
|
||||
gbt_inetkey_cmp(const void *a, const void *b)
|
||||
{
|
||||
|
||||
if ( *(double*)(&((Nsrt *) a)->t[0]) > *(double*)(&((Nsrt *) b)->t[0]) ){
|
||||
if (*(double *) (&((Nsrt *) a)->t[0]) > *(double *) (&((Nsrt *) b)->t[0]))
|
||||
return 1;
|
||||
} else
|
||||
if ( *(double*)(&((Nsrt *) a)->t[0]) < *(double*)(&((Nsrt *) b)->t[0]) ){
|
||||
else if (*(double *) (&((Nsrt *) a)->t[0]) < *(double *) (&((Nsrt *) b)->t[0]))
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
@ -94,6 +97,7 @@ gbt_inet_compress_inetrnal(GISTENTRY *retval , GISTENTRY *entry , Oid typid)
|
||||
if (entry->leafkey)
|
||||
{
|
||||
inetKEY *r = (inetKEY *) palloc(sizeof(inetKEY));
|
||||
|
||||
retval = palloc(sizeof(GISTENTRY));
|
||||
r->lower = convert_network_to_scalar(entry->key, typid);
|
||||
r->upper = r->lower;
|
||||
@ -114,6 +118,7 @@ gbt_inet_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
GISTENTRY *retval = NULL;
|
||||
|
||||
PG_RETURN_POINTER(gbt_inet_compress_inetrnal(retval, entry, INETOID));
|
||||
}
|
||||
|
||||
@ -122,6 +127,7 @@ gbt_cidr_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
GISTENTRY *retval = NULL;
|
||||
|
||||
PG_RETURN_POINTER(gbt_inet_compress_inetrnal(retval, entry, CIDROID));
|
||||
}
|
||||
|
||||
@ -131,7 +137,8 @@ gbt_inet_consistent_internal (
|
||||
const GISTENTRY *entry,
|
||||
const double *query,
|
||||
const StrategyNumber *strategy
|
||||
){
|
||||
)
|
||||
{
|
||||
inetKEY *kkk = (inetKEY *) DatumGetPointer(entry->key);
|
||||
GBT_NUMKEY_R key;
|
||||
|
||||
@ -174,6 +181,7 @@ gbt_inet_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
||||
void *out = palloc(sizeof(inetKEY));
|
||||
|
||||
*(int *) PG_GETARG_POINTER(1) = sizeof(inetKEY);
|
||||
PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
|
||||
}
|
||||
@ -192,7 +200,8 @@ gbt_inet_penalty(PG_FUNCTION_ARGS)
|
||||
|
||||
penalty_range_enlarge(origentry->lower, origentry->upper, newentry->lower, newentry->upper);
|
||||
|
||||
if ( res > 0 ){
|
||||
if (res > 0)
|
||||
{
|
||||
*result += FLT_MIN;
|
||||
*result += (float) (res / ((double) (res + origentry->upper - origentry->lower)));
|
||||
*result *= (FLT_MAX / (((GISTENTRY *) PG_GETARG_POINTER(0))->rel->rd_att->natts + 1));
|
||||
|
@ -24,23 +24,28 @@ Datum gbt_int2_consistent(PG_FUNCTION_ARGS);
|
||||
Datum gbt_int2_penalty(PG_FUNCTION_ARGS);
|
||||
Datum gbt_int2_same(PG_FUNCTION_ARGS);
|
||||
|
||||
static bool gbt_int2gt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_int2gt(const void *a, const void *b)
|
||||
{
|
||||
return (*((int16 *) a) > *((int16 *) b));
|
||||
}
|
||||
static bool gbt_int2ge (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_int2ge(const void *a, const void *b)
|
||||
{
|
||||
return (*((int16 *) a) >= *((int16 *) b));
|
||||
}
|
||||
static bool gbt_int2eq (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_int2eq(const void *a, const void *b)
|
||||
{
|
||||
return (*((int16 *) a) == *((int16 *) b));
|
||||
}
|
||||
static bool gbt_int2le (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_int2le(const void *a, const void *b)
|
||||
{
|
||||
return (*((int16 *) a) <= *((int16 *) b));
|
||||
}
|
||||
static bool gbt_int2lt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_int2lt(const void *a, const void *b)
|
||||
{
|
||||
return (*((int16 *) a) < *((int16 *) b));
|
||||
}
|
||||
@ -49,12 +54,10 @@ static int
|
||||
gbt_int2key_cmp(const void *a, const void *b)
|
||||
{
|
||||
|
||||
if ( *(int16*)(&((Nsrt *) a)->t[0]) > *(int16*)&(((Nsrt *) b)->t[0]) ){
|
||||
if (*(int16 *) (&((Nsrt *) a)->t[0]) > *(int16 *) &(((Nsrt *) b)->t[0]))
|
||||
return 1;
|
||||
} else
|
||||
if ( *(int16*)&(((Nsrt *) a)->t[0]) < *(int16*)&(((Nsrt *) b)->t[0]) ){
|
||||
else if (*(int16 *) &(((Nsrt *) a)->t[0]) < *(int16 *) &(((Nsrt *) b)->t[0]))
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
@ -87,6 +90,7 @@ gbt_int2_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
GISTENTRY *retval = NULL;
|
||||
|
||||
PG_RETURN_POINTER(gbt_num_compress(retval, entry, &tinfo));
|
||||
}
|
||||
|
||||
@ -99,6 +103,7 @@ gbt_int2_consistent(PG_FUNCTION_ARGS)
|
||||
int16KEY *kkk = (int16KEY *) DatumGetPointer(entry->key);
|
||||
GBT_NUMKEY_R key;
|
||||
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
|
||||
|
||||
key.lower = (GBT_NUMKEY *) & kkk->lower;
|
||||
key.upper = (GBT_NUMKEY *) & kkk->upper;
|
||||
|
||||
@ -113,6 +118,7 @@ gbt_int2_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
||||
void *out = palloc(sizeof(int16KEY));
|
||||
|
||||
*(int *) PG_GETARG_POINTER(1) = sizeof(int16KEY);
|
||||
PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
|
||||
}
|
||||
@ -130,7 +136,8 @@ gbt_int2_penalty(PG_FUNCTION_ARGS)
|
||||
|
||||
penalty_range_enlarge(origentry->lower, origentry->upper, newentry->lower, newentry->upper);
|
||||
|
||||
if ( res > 0 ){
|
||||
if (res > 0)
|
||||
{
|
||||
*result += FLT_MIN;
|
||||
*result += (float) (res / ((double) (res + origentry->upper - origentry->lower)));
|
||||
*result *= (FLT_MAX / (((GISTENTRY *) PG_GETARG_POINTER(0))->rel->rd_att->natts + 1));
|
||||
|
@ -25,23 +25,28 @@ Datum gbt_int4_penalty(PG_FUNCTION_ARGS);
|
||||
Datum gbt_int4_same(PG_FUNCTION_ARGS);
|
||||
|
||||
|
||||
static bool gbt_int4gt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_int4gt(const void *a, const void *b)
|
||||
{
|
||||
return (*((int32 *) a) > *((int32 *) b));
|
||||
}
|
||||
static bool gbt_int4ge (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_int4ge(const void *a, const void *b)
|
||||
{
|
||||
return (*((int32 *) a) >= *((int32 *) b));
|
||||
}
|
||||
static bool gbt_int4eq (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_int4eq(const void *a, const void *b)
|
||||
{
|
||||
return (*((int32 *) a) == *((int32 *) b));
|
||||
}
|
||||
static bool gbt_int4le (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_int4le(const void *a, const void *b)
|
||||
{
|
||||
return (*((int32 *) a) <= *((int32 *) b));
|
||||
}
|
||||
static bool gbt_int4lt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_int4lt(const void *a, const void *b)
|
||||
{
|
||||
return (*((int32 *) a) < *((int32 *) b));
|
||||
}
|
||||
@ -50,12 +55,10 @@ static int
|
||||
gbt_int4key_cmp(const void *a, const void *b)
|
||||
{
|
||||
|
||||
if ( *(int32*)&(((Nsrt *) a)->t[0]) > *(int32*)&(((Nsrt *) b)->t[0]) ){
|
||||
if (*(int32 *) &(((Nsrt *) a)->t[0]) > *(int32 *) &(((Nsrt *) b)->t[0]))
|
||||
return 1;
|
||||
} else
|
||||
if ( *(int32*)&(((Nsrt *) a)->t[0]) < *(int32*)&(((Nsrt *) b)->t[0]) ){
|
||||
else if (*(int32 *) &(((Nsrt *) a)->t[0]) < *(int32 *) &(((Nsrt *) b)->t[0]))
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
@ -84,6 +87,7 @@ gbt_int4_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
GISTENTRY *retval = NULL;
|
||||
|
||||
PG_RETURN_POINTER(gbt_num_compress(retval, entry, &tinfo));
|
||||
}
|
||||
|
||||
@ -97,6 +101,7 @@ gbt_int4_consistent(PG_FUNCTION_ARGS)
|
||||
int32KEY *kkk = (int32KEY *) DatumGetPointer(entry->key);
|
||||
GBT_NUMKEY_R key;
|
||||
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
|
||||
|
||||
key.lower = (GBT_NUMKEY *) & kkk->lower;
|
||||
key.upper = (GBT_NUMKEY *) & kkk->upper;
|
||||
|
||||
@ -111,6 +116,7 @@ gbt_int4_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
||||
void *out = palloc(sizeof(int32KEY));
|
||||
|
||||
*(int *) PG_GETARG_POINTER(1) = sizeof(int32KEY);
|
||||
PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
|
||||
}
|
||||
@ -128,7 +134,8 @@ gbt_int4_penalty(PG_FUNCTION_ARGS)
|
||||
|
||||
penalty_range_enlarge(origentry->lower, origentry->upper, newentry->lower, newentry->upper);
|
||||
|
||||
if ( res > 0 ){
|
||||
if (res > 0)
|
||||
{
|
||||
*result += FLT_MIN;
|
||||
*result += (float) (res / ((double) (res + origentry->upper - origentry->lower)));
|
||||
*result *= (FLT_MAX / (((GISTENTRY *) PG_GETARG_POINTER(0))->rel->rd_att->natts + 1));
|
||||
|
@ -25,23 +25,28 @@ Datum gbt_int8_penalty(PG_FUNCTION_ARGS);
|
||||
Datum gbt_int8_same(PG_FUNCTION_ARGS);
|
||||
|
||||
|
||||
static bool gbt_int8gt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_int8gt(const void *a, const void *b)
|
||||
{
|
||||
return (*((int64 *) a) > *((int64 *) b));
|
||||
}
|
||||
static bool gbt_int8ge (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_int8ge(const void *a, const void *b)
|
||||
{
|
||||
return (*((int64 *) a) >= *((int64 *) b));
|
||||
}
|
||||
static bool gbt_int8eq (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_int8eq(const void *a, const void *b)
|
||||
{
|
||||
return (*((int64 *) a) == *((int64 *) b));
|
||||
}
|
||||
static bool gbt_int8le (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_int8le(const void *a, const void *b)
|
||||
{
|
||||
return (*((int64 *) a) <= *((int64 *) b));
|
||||
}
|
||||
static bool gbt_int8lt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_int8lt(const void *a, const void *b)
|
||||
{
|
||||
return (*((int64 *) a) < *((int64 *) b));
|
||||
}
|
||||
@ -50,12 +55,10 @@ static int
|
||||
gbt_int8key_cmp(const void *a, const void *b)
|
||||
{
|
||||
|
||||
if ( *(int64*)&(((Nsrt *) a)->t[0]) > *(int64*)&(((Nsrt *) b)->t[0]) ){
|
||||
if (*(int64 *) &(((Nsrt *) a)->t[0]) > *(int64 *) &(((Nsrt *) b)->t[0]))
|
||||
return 1;
|
||||
} else
|
||||
if ( *(int64*)&(((Nsrt *) a)->t[0]) < *(int64*)&(((Nsrt *) b)->t[0]) ){
|
||||
else if (*(int64 *) &(((Nsrt *) a)->t[0]) < *(int64 *) &(((Nsrt *) b)->t[0]))
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
@ -84,6 +87,7 @@ gbt_int8_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
GISTENTRY *retval = NULL;
|
||||
|
||||
PG_RETURN_POINTER(gbt_num_compress(retval, entry, &tinfo));
|
||||
}
|
||||
|
||||
@ -96,6 +100,7 @@ gbt_int8_consistent(PG_FUNCTION_ARGS)
|
||||
int64KEY *kkk = (int64KEY *) DatumGetPointer(entry->key);
|
||||
GBT_NUMKEY_R key;
|
||||
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
|
||||
|
||||
key.lower = (GBT_NUMKEY *) & kkk->lower;
|
||||
key.upper = (GBT_NUMKEY *) & kkk->upper;
|
||||
|
||||
@ -110,6 +115,7 @@ gbt_int8_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
||||
void *out = palloc(sizeof(int64KEY));
|
||||
|
||||
*(int *) PG_GETARG_POINTER(1) = sizeof(int64KEY);
|
||||
PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
|
||||
}
|
||||
@ -127,7 +133,8 @@ gbt_int8_penalty(PG_FUNCTION_ARGS)
|
||||
|
||||
penalty_range_enlarge(origentry->lower, origentry->upper, newentry->lower, newentry->upper);
|
||||
|
||||
if ( res > 0 ){
|
||||
if (res > 0)
|
||||
{
|
||||
*result += FLT_MIN;
|
||||
*result += (float) (res / ((double) (res + origentry->upper - origentry->lower)));
|
||||
*result *= (FLT_MAX / (((GISTENTRY *) PG_GETARG_POINTER(0))->rel->rd_att->natts + 1));
|
||||
@ -157,4 +164,3 @@ gbt_int8_same(PG_FUNCTION_ARGS)
|
||||
*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,8 @@
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Interval lower, upper;
|
||||
Interval lower,
|
||||
upper;
|
||||
} intvKEY;
|
||||
|
||||
|
||||
@ -27,27 +28,32 @@ Datum gbt_intv_penalty(PG_FUNCTION_ARGS);
|
||||
Datum gbt_intv_same(PG_FUNCTION_ARGS);
|
||||
|
||||
|
||||
static bool gbt_intvgt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_intvgt(const void *a, const void *b)
|
||||
{
|
||||
return DatumGetBool(DirectFunctionCall2(interval_gt, IntervalPGetDatum(a), IntervalPGetDatum(b)));
|
||||
}
|
||||
|
||||
static bool gbt_intvge (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_intvge(const void *a, const void *b)
|
||||
{
|
||||
return DatumGetBool(DirectFunctionCall2(interval_ge, IntervalPGetDatum(a), IntervalPGetDatum(b)));
|
||||
}
|
||||
|
||||
static bool gbt_intveq (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_intveq(const void *a, const void *b)
|
||||
{
|
||||
return DatumGetBool(DirectFunctionCall2(interval_eq, IntervalPGetDatum(a), IntervalPGetDatum(b)));
|
||||
}
|
||||
|
||||
static bool gbt_intvle (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_intvle(const void *a, const void *b)
|
||||
{
|
||||
return DatumGetBool(DirectFunctionCall2(interval_le, IntervalPGetDatum(a), IntervalPGetDatum(b)));
|
||||
}
|
||||
|
||||
static bool gbt_intvlt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_intvlt(const void *a, const void *b)
|
||||
{
|
||||
return DatumGetBool(DirectFunctionCall2(interval_lt, IntervalPGetDatum(a), IntervalPGetDatum(b)));
|
||||
}
|
||||
@ -64,11 +70,13 @@ gbt_intvkey_cmp(const void *a, const void *b)
|
||||
}
|
||||
|
||||
|
||||
static double intr2num ( const Interval * i )
|
||||
static double
|
||||
intr2num(const Interval *i)
|
||||
{
|
||||
double ret = 0.0;
|
||||
struct pg_tm tm;
|
||||
fsec_t fsec;
|
||||
|
||||
interval2tm(*i, &tm, &fsec);
|
||||
ret += (tm.tm_year * 360.0 * 86400.0);
|
||||
ret += (tm.tm_mon * 12.0 * 86400.0);
|
||||
@ -106,17 +114,24 @@ gbt_intv_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
GISTENTRY *retval = entry;
|
||||
if ( entry->leafkey || INTERVALSIZE != sizeof(Interval) ) {
|
||||
|
||||
if (entry->leafkey || INTERVALSIZE != sizeof(Interval))
|
||||
{
|
||||
char *r = (char *) palloc(2 * INTERVALSIZE);
|
||||
|
||||
retval = palloc(sizeof(GISTENTRY));
|
||||
|
||||
if ( entry->leafkey ) {
|
||||
if (entry->leafkey)
|
||||
{
|
||||
Interval *key = DatumGetIntervalP(entry->key);
|
||||
|
||||
memcpy((void *) r, (void *) key, INTERVALSIZE);
|
||||
memcpy((void *) (r + INTERVALSIZE), (void *) key, INTERVALSIZE);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
intvKEY *key = (intvKEY *) DatumGetPointer(entry->key);
|
||||
|
||||
memcpy(r, &key->lower, INTERVALSIZE);
|
||||
memcpy(r + INTERVALSIZE, &key->upper, INTERVALSIZE);
|
||||
}
|
||||
@ -135,7 +150,8 @@ gbt_intv_decompress(PG_FUNCTION_ARGS)
|
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
GISTENTRY *retval = entry;
|
||||
|
||||
if ( INTERVALSIZE != sizeof(Interval) ) {
|
||||
if (INTERVALSIZE != sizeof(Interval))
|
||||
{
|
||||
intvKEY *r = palloc(sizeof(intvKEY));
|
||||
char *key = DatumGetPointer(entry->key);
|
||||
|
||||
@ -174,6 +190,7 @@ gbt_intv_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
||||
void *out = palloc(sizeof(intvKEY));
|
||||
|
||||
*(int *) PG_GETARG_POINTER(1) = sizeof(intvKEY);
|
||||
PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
|
||||
}
|
||||
@ -185,7 +202,9 @@ gbt_intv_penalty(PG_FUNCTION_ARGS)
|
||||
intvKEY *origentry = (intvKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
|
||||
intvKEY *newentry = (intvKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
|
||||
float *result = (float *) PG_GETARG_POINTER(2);
|
||||
double iorg[2], inew[2], res;
|
||||
double iorg[2],
|
||||
inew[2],
|
||||
res;
|
||||
|
||||
iorg[0] = intr2num(&origentry->lower);
|
||||
iorg[1] = intr2num(&origentry->upper);
|
||||
@ -196,7 +215,8 @@ gbt_intv_penalty(PG_FUNCTION_ARGS)
|
||||
|
||||
*result = 0.0;
|
||||
|
||||
if ( res > 0 ){
|
||||
if (res > 0)
|
||||
{
|
||||
*result += FLT_MIN;
|
||||
*result += (float) (res / (res + iorg[1] - iorg[0]));
|
||||
*result *= (FLT_MAX / (((GISTENTRY *) PG_GETARG_POINTER(0))->rel->rd_att->natts + 1));
|
||||
@ -226,4 +246,3 @@ gbt_intv_same(PG_FUNCTION_ARGS)
|
||||
*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
|
@ -27,26 +27,31 @@ Datum gbt_macad_penalty(PG_FUNCTION_ARGS);
|
||||
Datum gbt_macad_same(PG_FUNCTION_ARGS);
|
||||
|
||||
|
||||
static bool gbt_macadgt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_macadgt(const void *a, const void *b)
|
||||
{
|
||||
return DatumGetBool(DirectFunctionCall2(macaddr_gt, PointerGetDatum(a), PointerGetDatum(b)));
|
||||
}
|
||||
static bool gbt_macadge (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_macadge(const void *a, const void *b)
|
||||
{
|
||||
return DatumGetBool(DirectFunctionCall2(macaddr_ge, PointerGetDatum(a), PointerGetDatum(b)));
|
||||
}
|
||||
|
||||
static bool gbt_macadeq (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_macadeq(const void *a, const void *b)
|
||||
{
|
||||
return DatumGetBool(DirectFunctionCall2(macaddr_eq, PointerGetDatum(a), PointerGetDatum(b)));
|
||||
}
|
||||
|
||||
static bool gbt_macadle (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_macadle(const void *a, const void *b)
|
||||
{
|
||||
return DatumGetBool(DirectFunctionCall2(macaddr_le, PointerGetDatum(a), PointerGetDatum(b)));
|
||||
}
|
||||
|
||||
static bool gbt_macadlt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_macadlt(const void *a, const void *b)
|
||||
{
|
||||
return DatumGetBool(DirectFunctionCall2(macaddr_lt, PointerGetDatum(a), PointerGetDatum(b)));
|
||||
}
|
||||
@ -84,13 +89,15 @@ static const gbtree_ninfo tinfo =
|
||||
|
||||
|
||||
|
||||
static uint64 mac_2_uint64 ( macaddr * m ){
|
||||
static uint64
|
||||
mac_2_uint64(macaddr *m)
|
||||
{
|
||||
unsigned char *mi = (unsigned char *) m;
|
||||
uint64 res = 0;
|
||||
int i;
|
||||
for (i=0; i<6; i++ ){
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
res += (((uint64) mi[i]) << ((uint64) ((5 - i) * 8)));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -101,6 +108,7 @@ gbt_macad_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
GISTENTRY *retval = NULL;
|
||||
|
||||
PG_RETURN_POINTER(gbt_num_compress(retval, entry, &tinfo));
|
||||
}
|
||||
|
||||
@ -114,6 +122,7 @@ gbt_macad_consistent(PG_FUNCTION_ARGS)
|
||||
macKEY *kkk = (macKEY *) DatumGetPointer(entry->key);
|
||||
GBT_NUMKEY_R key;
|
||||
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
|
||||
|
||||
key.lower = (GBT_NUMKEY *) & kkk->lower;
|
||||
key.upper = (GBT_NUMKEY *) & kkk->upper;
|
||||
|
||||
@ -128,6 +137,7 @@ gbt_macad_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
||||
void *out = palloc(sizeof(macKEY));
|
||||
|
||||
*(int *) PG_GETARG_POINTER(1) = sizeof(macKEY);
|
||||
PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
|
||||
}
|
||||
@ -139,7 +149,8 @@ gbt_macad_penalty(PG_FUNCTION_ARGS)
|
||||
macKEY *origentry = (macKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
|
||||
macKEY *newentry = (macKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
|
||||
float *result = (float *) PG_GETARG_POINTER(2);
|
||||
uint64 iorg[2], inew[2];
|
||||
uint64 iorg[2],
|
||||
inew[2];
|
||||
uint64 res;
|
||||
|
||||
iorg[0] = mac_2_uint64(&origentry->lower);
|
||||
@ -151,7 +162,8 @@ gbt_macad_penalty(PG_FUNCTION_ARGS)
|
||||
|
||||
*result = 0.0;
|
||||
|
||||
if ( res > 0 ){
|
||||
if (res > 0)
|
||||
{
|
||||
*result += FLT_MIN;
|
||||
*result += (float) (((double) res) / ((double) res + (double) iorg[1] - (double) iorg[0]));
|
||||
*result *= (FLT_MAX / (((GISTENTRY *) PG_GETARG_POINTER(0))->rel->rd_att->natts + 1));
|
||||
@ -181,4 +193,3 @@ gbt_macad_same(PG_FUNCTION_ARGS)
|
||||
*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
|
@ -23,33 +23,39 @@ Datum gbt_numeric_same(PG_FUNCTION_ARGS);
|
||||
|
||||
/* define for comparison */
|
||||
|
||||
static bool gbt_numeric_gt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_numeric_gt(const void *a, const void *b)
|
||||
{
|
||||
return (DatumGetBool(DirectFunctionCall2(numeric_gt, PointerGetDatum(a), PointerGetDatum(b))));
|
||||
}
|
||||
|
||||
static bool gbt_numeric_ge (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_numeric_ge(const void *a, const void *b)
|
||||
{
|
||||
return (DatumGetBool(DirectFunctionCall2(numeric_ge, PointerGetDatum(a), PointerGetDatum(b))));
|
||||
}
|
||||
|
||||
static bool gbt_numeric_eq (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_numeric_eq(const void *a, const void *b)
|
||||
{
|
||||
return (DatumGetBool(DirectFunctionCall2(numeric_eq, PointerGetDatum(a), PointerGetDatum(b))));
|
||||
}
|
||||
|
||||
static bool gbt_numeric_le (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_numeric_le(const void *a, const void *b)
|
||||
{
|
||||
return (DatumGetBool(DirectFunctionCall2(numeric_le, PointerGetDatum(a), PointerGetDatum(b))));
|
||||
}
|
||||
|
||||
static bool gbt_numeric_lt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_numeric_lt(const void *a, const void *b)
|
||||
{
|
||||
return (DatumGetBool(DirectFunctionCall2(numeric_lt, PointerGetDatum(a), PointerGetDatum(b))));
|
||||
}
|
||||
|
||||
|
||||
static int32 gbt_numeric_cmp ( const bytea * a , const bytea * b )
|
||||
static int32
|
||||
gbt_numeric_cmp(const bytea *a, const bytea *b)
|
||||
{
|
||||
return
|
||||
(DatumGetInt32(DirectFunctionCall2(numeric_cmp, PointerGetDatum(a), PointerGetDatum(b))));
|
||||
@ -80,6 +86,7 @@ Datum
|
||||
gbt_numeric_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
|
||||
PG_RETURN_POINTER(gbt_var_compress(entry, &tinfo));
|
||||
}
|
||||
|
||||
@ -100,12 +107,10 @@ gbt_numeric_consistent(PG_FUNCTION_ARGS)
|
||||
|
||||
retval = gbt_var_consistent(&r, query, &strategy, GIST_LEAF(entry), &tinfo);
|
||||
|
||||
if ( ktst != key ){
|
||||
if (ktst != key)
|
||||
pfree(key);
|
||||
}
|
||||
if ( qtst != query ){
|
||||
if (qtst != query)
|
||||
pfree(query);
|
||||
}
|
||||
PG_RETURN_BOOL(retval);
|
||||
}
|
||||
|
||||
@ -116,6 +121,7 @@ gbt_numeric_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
||||
int32 *size = (int *) PG_GETARG_POINTER(1);
|
||||
|
||||
PG_RETURN_POINTER(gbt_var_union(entryvec, size, &tinfo));
|
||||
}
|
||||
|
||||
@ -126,6 +132,7 @@ gbt_numeric_same(PG_FUNCTION_ARGS)
|
||||
Datum d1 = PG_GETARG_DATUM(0);
|
||||
Datum d2 = PG_GETARG_DATUM(1);
|
||||
bool *result = (bool *) PG_GETARG_POINTER(2);
|
||||
|
||||
PG_RETURN_POINTER(gbt_var_same(result, d1, d2, &tinfo));
|
||||
}
|
||||
|
||||
@ -137,12 +144,16 @@ gbt_numeric_penalty (PG_FUNCTION_ARGS)
|
||||
GISTENTRY *n = (GISTENTRY *) PG_GETARG_POINTER(1);
|
||||
float *result = (float *) PG_GETARG_POINTER(2);
|
||||
|
||||
Numeric us, os, ds ;
|
||||
Numeric us,
|
||||
os,
|
||||
ds;
|
||||
|
||||
GBT_VARKEY *org = (GBT_VARKEY *) DatumGetPointer(o->key);
|
||||
GBT_VARKEY *newe = (GBT_VARKEY *) DatumGetPointer(n->key);
|
||||
Datum uni;
|
||||
GBT_VARKEY_R rk , ok, uk ;
|
||||
GBT_VARKEY_R rk,
|
||||
ok,
|
||||
uk;
|
||||
|
||||
rk = gbt_var_key_readable(org);
|
||||
uni = PointerGetDatum(gbt_var_key_copy(&rk, TRUE));
|
||||
@ -176,13 +187,13 @@ gbt_numeric_penalty (PG_FUNCTION_ARGS)
|
||||
{
|
||||
|
||||
if (NUMERIC_IS_NAN(os))
|
||||
{
|
||||
*result = 0.0;
|
||||
} else {
|
||||
else
|
||||
*result = 1.0;
|
||||
}
|
||||
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Numeric nul = DatumGetNumeric(DirectFunctionCall1(int4_numeric, Int32GetDatum(0)));
|
||||
|
||||
@ -221,7 +232,7 @@ gbt_numeric_picksplit(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
||||
GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
|
||||
|
||||
gbt_var_picksplit(entryvec, v, &tinfo);
|
||||
PG_RETURN_POINTER(v);
|
||||
}
|
||||
|
||||
|
@ -25,23 +25,28 @@ Datum gbt_oid_penalty(PG_FUNCTION_ARGS);
|
||||
Datum gbt_oid_same(PG_FUNCTION_ARGS);
|
||||
|
||||
|
||||
static bool gbt_oidgt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_oidgt(const void *a, const void *b)
|
||||
{
|
||||
return (*((Oid *) a) > *((Oid *) b));
|
||||
}
|
||||
static bool gbt_oidge (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_oidge(const void *a, const void *b)
|
||||
{
|
||||
return (*((Oid *) a) >= *((Oid *) b));
|
||||
}
|
||||
static bool gbt_oideq (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_oideq(const void *a, const void *b)
|
||||
{
|
||||
return (*((Oid *) a) == *((Oid *) b));
|
||||
}
|
||||
static bool gbt_oidle (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_oidle(const void *a, const void *b)
|
||||
{
|
||||
return (*((Oid *) a) <= *((Oid *) b));
|
||||
}
|
||||
static bool gbt_oidlt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_oidlt(const void *a, const void *b)
|
||||
{
|
||||
return (*((Oid *) a) < *((Oid *) b));
|
||||
}
|
||||
@ -50,12 +55,10 @@ static int
|
||||
gbt_oidkey_cmp(const void *a, const void *b)
|
||||
{
|
||||
|
||||
if ( *(Oid*)&(((Nsrt *) a)->t[0]) > *(Oid*)&(((Nsrt *) b)->t[0]) ){
|
||||
if (*(Oid *) &(((Nsrt *) a)->t[0]) > *(Oid *) &(((Nsrt *) b)->t[0]))
|
||||
return 1;
|
||||
} else
|
||||
if ( *(Oid*)&(((Nsrt *) a)->t[0]) < *(Oid*)&(((Nsrt *) b)->t[0]) ){
|
||||
else if (*(Oid *) &(((Nsrt *) a)->t[0]) < *(Oid *) &(((Nsrt *) b)->t[0]))
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
@ -84,6 +87,7 @@ gbt_oid_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
GISTENTRY *retval = NULL;
|
||||
|
||||
PG_RETURN_POINTER(gbt_num_compress(retval, entry, &tinfo));
|
||||
}
|
||||
|
||||
@ -97,6 +101,7 @@ gbt_oid_consistent(PG_FUNCTION_ARGS)
|
||||
oidKEY *kkk = (oidKEY *) DatumGetPointer(entry->key);
|
||||
GBT_NUMKEY_R key;
|
||||
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
|
||||
|
||||
key.lower = (GBT_NUMKEY *) & kkk->lower;
|
||||
key.upper = (GBT_NUMKEY *) & kkk->upper;
|
||||
|
||||
@ -111,6 +116,7 @@ gbt_oid_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
||||
void *out = palloc(sizeof(oidKEY));
|
||||
|
||||
*(int *) PG_GETARG_POINTER(1) = sizeof(oidKEY);
|
||||
PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
|
||||
}
|
||||
@ -129,7 +135,8 @@ gbt_oid_penalty(PG_FUNCTION_ARGS)
|
||||
|
||||
penalty_range_enlarge(origentry->lower, origentry->upper, newentry->lower, newentry->upper);
|
||||
|
||||
if ( res > 0 ){
|
||||
if (res > 0)
|
||||
{
|
||||
*result += FLT_MIN;
|
||||
*result += (float) (res / ((double) (res + origentry->upper - origentry->lower)));
|
||||
*result *= (FLT_MAX / (((GISTENTRY *) PG_GETARG_POINTER(0))->rel->rd_att->natts + 1));
|
||||
|
@ -26,32 +26,38 @@ Datum gbt_text_same(PG_FUNCTION_ARGS);
|
||||
|
||||
/* define for comparison */
|
||||
|
||||
static bool gbt_textgt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_textgt(const void *a, const void *b)
|
||||
{
|
||||
return (DatumGetBool(DirectFunctionCall2(text_gt, PointerGetDatum(a), PointerGetDatum(b))));
|
||||
}
|
||||
|
||||
static bool gbt_textge (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_textge(const void *a, const void *b)
|
||||
{
|
||||
return (DatumGetBool(DirectFunctionCall2(text_ge, PointerGetDatum(a), PointerGetDatum(b))));
|
||||
}
|
||||
|
||||
static bool gbt_texteq (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_texteq(const void *a, const void *b)
|
||||
{
|
||||
return (DatumGetBool(DirectFunctionCall2(texteq, PointerGetDatum(a), PointerGetDatum(b))));
|
||||
}
|
||||
|
||||
static bool gbt_textle (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_textle(const void *a, const void *b)
|
||||
{
|
||||
return (DatumGetBool(DirectFunctionCall2(text_le, PointerGetDatum(a), PointerGetDatum(b))));
|
||||
}
|
||||
|
||||
static bool gbt_textlt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_textlt(const void *a, const void *b)
|
||||
{
|
||||
return (DatumGetBool(DirectFunctionCall2(text_lt, PointerGetDatum(a), PointerGetDatum(b))));
|
||||
}
|
||||
|
||||
static int32 gbt_textcmp ( const bytea * a , const bytea * b )
|
||||
static int32
|
||||
gbt_textcmp(const bytea *a, const bytea *b)
|
||||
{
|
||||
return strcmp(VARDATA(a), VARDATA(b));
|
||||
}
|
||||
@ -90,7 +96,8 @@ gbt_text_xfrm ( bytea * leaf )
|
||||
}
|
||||
|
||||
|
||||
static GBT_VARKEY * gbt_text_l2n ( GBT_VARKEY * leaf )
|
||||
static GBT_VARKEY *
|
||||
gbt_text_l2n(GBT_VARKEY * leaf)
|
||||
{
|
||||
|
||||
GBT_VARKEY *out = leaf;
|
||||
@ -135,6 +142,7 @@ Datum
|
||||
gbt_text_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
|
||||
PG_RETURN_POINTER(gbt_var_compress(entry, &tinfo));
|
||||
}
|
||||
|
||||
@ -158,7 +166,8 @@ gbt_bpchar_compress (PG_FUNCTION_ARGS)
|
||||
|
||||
pfree(trim);
|
||||
pfree(DatumGetPointer(d));
|
||||
} else
|
||||
}
|
||||
else
|
||||
retval = entry;
|
||||
|
||||
PG_RETURN_POINTER(retval);
|
||||
@ -179,21 +188,20 @@ gbt_text_consistent(PG_FUNCTION_ARGS)
|
||||
GBT_VARKEY_R r = gbt_var_key_readable(key);
|
||||
|
||||
if (GIST_LEAF(entry))
|
||||
{
|
||||
retval = gbt_var_consistent(&r, query, &strategy, TRUE, &tinfo);
|
||||
} else {
|
||||
else
|
||||
{
|
||||
bytea *q = gbt_text_xfrm((bytea *) query);
|
||||
|
||||
retval = gbt_var_consistent(&r, (void *) q, &strategy, FALSE, &tinfo);
|
||||
if (q != query)
|
||||
pfree(q);
|
||||
}
|
||||
|
||||
if ( ktst != key ){
|
||||
if (ktst != key)
|
||||
pfree(key);
|
||||
}
|
||||
if ( qtst != query ){
|
||||
if (qtst != query)
|
||||
pfree(query);
|
||||
}
|
||||
|
||||
PG_RETURN_BOOL(retval);
|
||||
}
|
||||
@ -213,10 +221,11 @@ gbt_bpchar_consistent(PG_FUNCTION_ARGS)
|
||||
GBT_VARKEY_R r = gbt_var_key_readable(key);
|
||||
|
||||
if (GIST_LEAF(entry))
|
||||
{
|
||||
retval = gbt_var_consistent(&r, trim, &strategy, TRUE, &tinfo);
|
||||
} else {
|
||||
else
|
||||
{
|
||||
bytea *q = gbt_text_xfrm((bytea *) trim);
|
||||
|
||||
retval = gbt_var_consistent(&r, (void *) q, &strategy, FALSE, &tinfo);
|
||||
if (q != trim)
|
||||
pfree(q);
|
||||
@ -224,12 +233,10 @@ gbt_bpchar_consistent(PG_FUNCTION_ARGS)
|
||||
|
||||
pfree(trim);
|
||||
|
||||
if ( ktst != key ){
|
||||
if (ktst != key)
|
||||
pfree(key);
|
||||
}
|
||||
if ( qtst != query ){
|
||||
if (qtst != query)
|
||||
pfree(query);
|
||||
}
|
||||
PG_RETURN_BOOL(retval);
|
||||
}
|
||||
|
||||
@ -241,6 +248,7 @@ gbt_text_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
||||
int32 *size = (int *) PG_GETARG_POINTER(1);
|
||||
|
||||
PG_RETURN_POINTER(gbt_var_union(entryvec, size, &tinfo));
|
||||
}
|
||||
|
||||
@ -250,6 +258,7 @@ gbt_text_picksplit(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
||||
GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
|
||||
|
||||
gbt_var_picksplit(entryvec, v, &tinfo);
|
||||
PG_RETURN_POINTER(v);
|
||||
}
|
||||
@ -260,6 +269,7 @@ gbt_text_same(PG_FUNCTION_ARGS)
|
||||
Datum d1 = PG_GETARG_DATUM(0);
|
||||
Datum d2 = PG_GETARG_DATUM(1);
|
||||
bool *result = (bool *) PG_GETARG_POINTER(2);
|
||||
|
||||
PG_RETURN_POINTER(gbt_var_same(result, d1, d2, &tinfo));
|
||||
}
|
||||
|
||||
@ -270,6 +280,6 @@ gbt_text_penalty(PG_FUNCTION_ARGS)
|
||||
float *result = (float *) PG_GETARG_POINTER(2);
|
||||
GISTENTRY *o = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
GISTENTRY *n = (GISTENTRY *) PG_GETARG_POINTER(1);
|
||||
|
||||
PG_RETURN_POINTER(gbt_var_penalty(result, o, n, &tinfo));
|
||||
}
|
||||
|
||||
|
@ -30,35 +30,40 @@ Datum gbt_time_penalty(PG_FUNCTION_ARGS);
|
||||
Datum gbt_time_same(PG_FUNCTION_ARGS);
|
||||
|
||||
|
||||
static bool gbt_timegt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_timegt(const void *a, const void *b)
|
||||
{
|
||||
return DatumGetBool(
|
||||
DirectFunctionCall2(time_gt, TimeADTGetDatum(*((TimeADT *) a)), TimeADTGetDatum(*((TimeADT *) b)))
|
||||
);
|
||||
}
|
||||
|
||||
static bool gbt_timege (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_timege(const void *a, const void *b)
|
||||
{
|
||||
return DatumGetBool(
|
||||
DirectFunctionCall2(time_ge, TimeADTGetDatum(*((TimeADT *) a)), TimeADTGetDatum(*((TimeADT *) b)))
|
||||
);
|
||||
}
|
||||
|
||||
static bool gbt_timeeq (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_timeeq(const void *a, const void *b)
|
||||
{
|
||||
return DatumGetBool(
|
||||
DirectFunctionCall2(time_eq, TimeADTGetDatum(*((TimeADT *) a)), TimeADTGetDatum(*((TimeADT *) b)))
|
||||
);
|
||||
}
|
||||
|
||||
static bool gbt_timele (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_timele(const void *a, const void *b)
|
||||
{
|
||||
return DatumGetBool(
|
||||
DirectFunctionCall2(time_le, TimeADTGetDatum(*((TimeADT *) a)), TimeADTGetDatum(*((TimeADT *) b)))
|
||||
);
|
||||
}
|
||||
|
||||
static bool gbt_timelt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_timelt(const void *a, const void *b)
|
||||
{
|
||||
return DatumGetBool(
|
||||
DirectFunctionCall2(time_lt, TimeADTGetDatum(*((TimeADT *) a)), TimeADTGetDatum(*((TimeADT *) b)))
|
||||
@ -70,12 +75,10 @@ static bool gbt_timelt (const void *a, const void *b)
|
||||
static int
|
||||
gbt_timekey_cmp(const void *a, const void *b)
|
||||
{
|
||||
if ( gbt_timegt( (void*)&(((Nsrt *) a)->t[0]) , (void*)&(((Nsrt *) b)->t[0]) ) ){
|
||||
if (gbt_timegt((void *) &(((Nsrt *) a)->t[0]), (void *) &(((Nsrt *) b)->t[0])))
|
||||
return 1;
|
||||
} else
|
||||
if ( gbt_timelt( (void*)&(((Nsrt *) a)->t[0]) , (void*)&(((Nsrt *) b)->t[0]) ) ){
|
||||
else if (gbt_timelt((void *) &(((Nsrt *) a)->t[0]), (void *) &(((Nsrt *) b)->t[0])))
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -104,6 +107,7 @@ gbt_time_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
GISTENTRY *retval = NULL;
|
||||
|
||||
PG_RETURN_POINTER(gbt_num_compress(retval, entry, &tinfo));
|
||||
}
|
||||
|
||||
@ -175,6 +179,7 @@ gbt_time_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
||||
void *out = palloc(sizeof(timeKEY));
|
||||
|
||||
*(int *) PG_GETARG_POINTER(1) = sizeof(timeKEY);
|
||||
PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
|
||||
}
|
||||
@ -187,8 +192,10 @@ gbt_time_penalty(PG_FUNCTION_ARGS)
|
||||
timeKEY *newentry = (timeKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
|
||||
float *result = (float *) PG_GETARG_POINTER(2);
|
||||
Interval *intr;
|
||||
|
||||
#ifdef HAVE_INT64_TIMESTAMP
|
||||
int64 res;
|
||||
|
||||
#else
|
||||
double res;
|
||||
#endif
|
||||
@ -213,7 +220,8 @@ gbt_time_penalty(PG_FUNCTION_ARGS)
|
||||
|
||||
*result = 0.0;
|
||||
|
||||
if ( res > 0 ){
|
||||
if (res > 0)
|
||||
{
|
||||
intr = DatumGetIntervalP(DirectFunctionCall2(
|
||||
time_mi_time,
|
||||
TimeADTGetDatum(origentry->upper),
|
||||
@ -248,4 +256,3 @@ gbt_time_same(PG_FUNCTION_ARGS)
|
||||
*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
|
@ -29,35 +29,40 @@ Datum gbt_ts_penalty(PG_FUNCTION_ARGS);
|
||||
Datum gbt_ts_same(PG_FUNCTION_ARGS);
|
||||
|
||||
|
||||
static bool gbt_tsgt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_tsgt(const void *a, const void *b)
|
||||
{
|
||||
return DatumGetBool(
|
||||
DirectFunctionCall2(timestamp_gt, PointerGetDatum(a), PointerGetDatum(b))
|
||||
);
|
||||
}
|
||||
|
||||
static bool gbt_tsge (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_tsge(const void *a, const void *b)
|
||||
{
|
||||
return DatumGetBool(
|
||||
DirectFunctionCall2(timestamp_ge, PointerGetDatum(a), PointerGetDatum(b))
|
||||
);
|
||||
}
|
||||
|
||||
static bool gbt_tseq (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_tseq(const void *a, const void *b)
|
||||
{
|
||||
return DatumGetBool(
|
||||
DirectFunctionCall2(timestamp_eq, PointerGetDatum(a), PointerGetDatum(b))
|
||||
);
|
||||
}
|
||||
|
||||
static bool gbt_tsle (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_tsle(const void *a, const void *b)
|
||||
{
|
||||
return DatumGetBool(
|
||||
DirectFunctionCall2(timestamp_le, PointerGetDatum(a), PointerGetDatum(b))
|
||||
);
|
||||
}
|
||||
|
||||
static bool gbt_tslt (const void *a, const void *b)
|
||||
static bool
|
||||
gbt_tslt(const void *a, const void *b)
|
||||
{
|
||||
return DatumGetBool(
|
||||
DirectFunctionCall2(timestamp_lt, PointerGetDatum(a), PointerGetDatum(b))
|
||||
@ -68,12 +73,10 @@ static bool gbt_tslt (const void *a, const void *b)
|
||||
static int
|
||||
gbt_tskey_cmp(const void *a, const void *b)
|
||||
{
|
||||
if ( gbt_tsgt( (void*)&(((Nsrt *) a)->t[0]) , (void*)&(((Nsrt *) b)->t[0]) ) ){
|
||||
if (gbt_tsgt((void *) &(((Nsrt *) a)->t[0]), (void *) &(((Nsrt *) b)->t[0])))
|
||||
return 1;
|
||||
} else
|
||||
if ( gbt_tslt( (void*)&(((Nsrt *) a)->t[0]) , (void*)&(((Nsrt *) b)->t[0]) ) ){
|
||||
else if (gbt_tslt((void *) &(((Nsrt *) a)->t[0]), (void *) &(((Nsrt *) b)->t[0])))
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -97,9 +100,11 @@ static const gbtree_ninfo tinfo =
|
||||
|
||||
|
||||
|
||||
static Timestamp * tstz_to_ts_gmt ( Timestamp * gmt, TimestampTz * ts )
|
||||
static Timestamp *
|
||||
tstz_to_ts_gmt(Timestamp *gmt, TimestampTz *ts)
|
||||
{
|
||||
int val, tz ;
|
||||
int val,
|
||||
tz;
|
||||
|
||||
*gmt = *ts;
|
||||
DecodeSpecial(0, "gmt", &val);
|
||||
@ -127,6 +132,7 @@ gbt_ts_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
GISTENTRY *retval = NULL;
|
||||
|
||||
PG_RETURN_POINTER(gbt_num_compress(retval, entry, &tinfo));
|
||||
}
|
||||
|
||||
@ -201,6 +207,7 @@ gbt_ts_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
||||
void *out = palloc(sizeof(tsKEY));
|
||||
|
||||
*(int *) PG_GETARG_POINTER(1) = sizeof(tsKEY);
|
||||
PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
|
||||
}
|
||||
@ -214,8 +221,10 @@ gbt_ts_penalty(PG_FUNCTION_ARGS)
|
||||
tsKEY *newentry = (tsKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
|
||||
float *result = (float *) PG_GETARG_POINTER(2);
|
||||
Interval *intr;
|
||||
|
||||
#ifdef HAVE_INT64_TIMESTAMP
|
||||
int64 res;
|
||||
|
||||
#else
|
||||
double res;
|
||||
#endif
|
||||
@ -243,7 +252,8 @@ gbt_ts_penalty(PG_FUNCTION_ARGS)
|
||||
|
||||
*result = 0.0;
|
||||
|
||||
if ( res > 0 ){
|
||||
if (res > 0)
|
||||
{
|
||||
intr = DatumGetIntervalP(DirectFunctionCall2(
|
||||
timestamp_mi,
|
||||
TimestampGetDatum(origentry->upper),
|
||||
@ -280,4 +290,3 @@ gbt_ts_same(PG_FUNCTION_ARGS)
|
||||
*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,8 @@ gbt_num_compress( GISTENTRY *retval , GISTENTRY *entry , const gbtree_ninfo *
|
||||
if (entry->leafkey)
|
||||
{
|
||||
|
||||
union {
|
||||
union
|
||||
{
|
||||
int16 i2;
|
||||
int32 i4;
|
||||
TimeADT ts;
|
||||
@ -51,7 +52,8 @@ gbt_num_compress( GISTENTRY *retval , GISTENTRY *entry , const gbtree_ninfo *
|
||||
retval = palloc(sizeof(GISTENTRY));
|
||||
gistentryinit(*retval, PointerGetDatum(r), entry->rel, entry->page,
|
||||
entry->offset, (2 * tinfo->size), FALSE);
|
||||
} else
|
||||
}
|
||||
else
|
||||
retval = entry;
|
||||
|
||||
return retval;
|
||||
@ -70,7 +72,8 @@ gbt_num_union( GBT_NUMKEY * out, const GistEntryVector * entryvec, const gbtree_
|
||||
int i,
|
||||
numranges;
|
||||
GBT_NUMKEY *cur;
|
||||
GBT_NUMKEY_R o, c;
|
||||
GBT_NUMKEY_R o,
|
||||
c;
|
||||
|
||||
numranges = entryvec->n;
|
||||
cur = (GBT_NUMKEY *) DatumGetPointer((entryvec->vector[0].key));
|
||||
@ -101,10 +104,12 @@ gbt_num_union( GBT_NUMKEY * out, const GistEntryVector * entryvec, const gbtree_
|
||||
** The GiST same method for numerical values
|
||||
*/
|
||||
|
||||
extern bool gbt_num_same ( const GBT_NUMKEY * a, const GBT_NUMKEY * b, const gbtree_ninfo * tinfo )
|
||||
extern bool
|
||||
gbt_num_same(const GBT_NUMKEY * a, const GBT_NUMKEY * b, const gbtree_ninfo * tinfo)
|
||||
{
|
||||
|
||||
GBT_NUMKEY_R b1, b2 ;
|
||||
GBT_NUMKEY_R b1,
|
||||
b2;
|
||||
|
||||
b1.lower = &(((GBT_NUMKEY *) a)[0]);
|
||||
b1.upper = &(((GBT_NUMKEY *) a)[tinfo->size]);
|
||||
@ -139,6 +144,7 @@ gbt_num_bin_union(Datum * u , GBT_NUMKEY * e , const gbtree_ninfo * tinfo )
|
||||
else
|
||||
{
|
||||
GBT_NUMKEY_R ur;
|
||||
|
||||
ur.lower = &(((GBT_NUMKEY *) DatumGetPointer(*u))[0]);
|
||||
ur.upper = &(((GBT_NUMKEY *) DatumGetPointer(*u))[tinfo->size]);
|
||||
if ((*tinfo->f_gt) ((void *) ur.lower, (void *) rd.lower))
|
||||
|
@ -4,7 +4,8 @@ typedef char GBT_NUMKEY;
|
||||
/* Better readable key */
|
||||
typedef struct
|
||||
{
|
||||
const GBT_NUMKEY * lower, * upper;
|
||||
const GBT_NUMKEY *lower,
|
||||
*upper;
|
||||
} GBT_NUMKEY_R;
|
||||
|
||||
|
||||
|
@ -4,9 +4,12 @@
|
||||
|
||||
/* Returns a better readable representaion of variable key ( sets pointer ) */
|
||||
|
||||
extern GBT_VARKEY_R gbt_var_key_readable ( const GBT_VARKEY * k ){
|
||||
extern GBT_VARKEY_R
|
||||
gbt_var_key_readable(const GBT_VARKEY * k)
|
||||
{
|
||||
|
||||
GBT_VARKEY_R r;
|
||||
|
||||
r.lower = (bytea *) &(((char *) k)[VARHDRSZ]);
|
||||
if (VARSIZE(k) > (VARHDRSZ + (VARSIZE(r.lower))))
|
||||
r.upper = (bytea *) &(((char *) k)[VARHDRSZ + INTALIGN(VARSIZE(r.lower))]);
|
||||
@ -16,17 +19,22 @@ extern GBT_VARKEY_R gbt_var_key_readable ( const GBT_VARKEY * k ){
|
||||
}
|
||||
|
||||
|
||||
extern GBT_VARKEY * gbt_var_key_copy ( const GBT_VARKEY_R * u , bool force_node ){
|
||||
extern GBT_VARKEY *
|
||||
gbt_var_key_copy(const GBT_VARKEY_R * u, bool force_node)
|
||||
{
|
||||
|
||||
GBT_VARKEY *r = NULL;
|
||||
|
||||
if ( u->lower == u->upper && !force_node ){ /* leaf key mode */
|
||||
if (u->lower == u->upper && !force_node)
|
||||
{ /* leaf key mode */
|
||||
|
||||
r = (GBT_VARKEY *) palloc(VARSIZE(u->lower) + VARHDRSZ);
|
||||
memcpy((void *) VARDATA(r), (void *) u->lower, VARSIZE(u->lower));
|
||||
r->vl_len = VARSIZE(u->lower) + VARHDRSZ;
|
||||
|
||||
} else { /* node key mode */
|
||||
}
|
||||
else
|
||||
{ /* node key mode */
|
||||
|
||||
r = (GBT_VARKEY *) palloc(INTALIGN(VARSIZE(u->lower)) + VARSIZE(u->upper) + VARHDRSZ);
|
||||
memcpy((void *) VARDATA(r), (void *) u->lower, VARSIZE(u->lower));
|
||||
@ -39,15 +47,14 @@ extern GBT_VARKEY * gbt_var_key_copy ( const GBT_VARKEY_R * u , bool force_node
|
||||
}
|
||||
|
||||
|
||||
static GBT_VARKEY * gbt_var_leaf2node ( GBT_VARKEY * leaf, const gbtree_vinfo * tinfo )
|
||||
static GBT_VARKEY *
|
||||
gbt_var_leaf2node(GBT_VARKEY * leaf, const gbtree_vinfo * tinfo)
|
||||
{
|
||||
|
||||
GBT_VARKEY *out = leaf;
|
||||
|
||||
if (tinfo->f_l2n)
|
||||
{
|
||||
out = (*tinfo->f_l2n) (leaf);
|
||||
}
|
||||
|
||||
return out;
|
||||
|
||||
@ -57,7 +64,8 @@ static GBT_VARKEY * gbt_var_leaf2node ( GBT_VARKEY * leaf, const gbtree_vinfo *
|
||||
/*
|
||||
* returns the common prefix length of a node key
|
||||
*/
|
||||
static int32 gbt_var_node_cp_len ( const GBT_VARKEY * node , const gbtree_vinfo * tinfo )
|
||||
static int32
|
||||
gbt_var_node_cp_len(const GBT_VARKEY * node, const gbtree_vinfo * tinfo)
|
||||
{
|
||||
int32 i;
|
||||
int32 s = (tinfo->str) ? (1) : (0);
|
||||
@ -72,9 +80,7 @@ static int32 gbt_var_node_cp_len ( const GBT_VARKEY * node , const gbtree_vinfo
|
||||
for (i = 0; i < ml; i++)
|
||||
{
|
||||
if (*p1 != *p2)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
p1++;
|
||||
p2++;
|
||||
}
|
||||
@ -87,7 +93,8 @@ static int32 gbt_var_node_cp_len ( const GBT_VARKEY * node , const gbtree_vinfo
|
||||
* returns true, if query matches prefix using common prefix
|
||||
*/
|
||||
|
||||
static bool gbt_bytea_pf_match ( const bytea * pf , const bytea * query , const gbtree_vinfo * tinfo )
|
||||
static bool
|
||||
gbt_bytea_pf_match(const bytea *pf, const bytea *query, const gbtree_vinfo * tinfo)
|
||||
{
|
||||
|
||||
int k;
|
||||
@ -95,14 +102,17 @@ static bool gbt_bytea_pf_match ( const bytea * pf , const bytea * query , const
|
||||
bool out = FALSE;
|
||||
int32 qlen = VARSIZE(query) - VARHDRSZ - s;
|
||||
int32 nlen = VARSIZE(pf) - VARHDRSZ - s;
|
||||
|
||||
if (nlen <= qlen)
|
||||
{
|
||||
char *q = VARDATA(query);
|
||||
char *n = VARDATA(pf);
|
||||
|
||||
out = TRUE;
|
||||
for (k = 0; k < nlen; k++)
|
||||
{
|
||||
if ( *n != *q ){
|
||||
if (*n != *q)
|
||||
{
|
||||
out = FALSE;
|
||||
break;
|
||||
}
|
||||
@ -124,7 +134,8 @@ static bool gbt_bytea_pf_match ( const bytea * pf , const bytea * query , const
|
||||
* returns true, if query matches node using common prefix
|
||||
*/
|
||||
|
||||
static bool gbt_var_node_pf_match ( const GBT_VARKEY_R * node , const bytea * query , const gbtree_vinfo * tinfo )
|
||||
static bool
|
||||
gbt_var_node_pf_match(const GBT_VARKEY_R * node, const bytea *query, const gbtree_vinfo * tinfo)
|
||||
{
|
||||
|
||||
return (
|
||||
@ -138,7 +149,8 @@ static bool gbt_var_node_pf_match ( const GBT_VARKEY_R * node , const bytea * qu
|
||||
/*
|
||||
* truncates / compresses the node key
|
||||
*/
|
||||
static GBT_VARKEY * gbt_var_node_truncate ( const GBT_VARKEY * node , int32 length , const gbtree_vinfo * tinfo )
|
||||
static GBT_VARKEY *
|
||||
gbt_var_node_truncate(const GBT_VARKEY * node, int32 length, const gbtree_vinfo * tinfo)
|
||||
{
|
||||
|
||||
int32 s = (tinfo->str) ? (1) : (0);
|
||||
@ -194,12 +206,14 @@ gbt_var_bin_union ( Datum * u , GBT_VARKEY * e , const gbtree_vinfo * tinfo )
|
||||
|
||||
GBT_VARKEY_R ro = gbt_var_key_readable((GBT_VARKEY *) DatumGetPointer(*u));
|
||||
|
||||
if ( (*tinfo->f_cmp) ( (bytea*)ro.lower, (bytea*)eo.lower ) > 0 ) {
|
||||
if ((*tinfo->f_cmp) ((bytea *) ro.lower, (bytea *) eo.lower) > 0)
|
||||
{
|
||||
nr.lower = eo.lower;
|
||||
nr.upper = ro.upper;
|
||||
nk = gbt_var_key_copy(&nr, TRUE);
|
||||
}
|
||||
if ( (*tinfo->f_cmp) ( (bytea*)ro.upper, (bytea*)eo.upper ) < 0 ) {
|
||||
if ((*tinfo->f_cmp) ((bytea *) ro.upper, (bytea *) eo.upper) < 0)
|
||||
{
|
||||
nr.upper = eo.upper;
|
||||
nr.lower = ro.lower;
|
||||
nk = gbt_var_key_copy(&nr, TRUE);
|
||||
@ -243,14 +257,15 @@ gbt_var_compress ( GISTENTRY *entry , const gbtree_vinfo * tinfo )
|
||||
u.lower = u.upper = leaf;
|
||||
r = gbt_var_key_copy(&u, FALSE);
|
||||
|
||||
if ( tstd != leaf ){
|
||||
if (tstd != leaf)
|
||||
pfree(leaf);
|
||||
}
|
||||
retval = palloc(sizeof(GISTENTRY));
|
||||
gistentryinit(*retval, PointerGetDatum(r),
|
||||
entry->rel, entry->page,
|
||||
entry->offset, VARSIZE(r), TRUE);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = entry;
|
||||
|
||||
|
||||
@ -278,14 +293,16 @@ gbt_var_union ( const GistEntryVector * entryvec , int32 * size , const gbtree_
|
||||
cur = (GBT_VARKEY *) DatumGetPointer(PG_DETOAST_DATUM((entryvec->vector[0].key)));
|
||||
rk = gbt_var_key_readable(cur);
|
||||
out = PointerGetDatum(gbt_var_key_copy(&rk, TRUE));
|
||||
if ( tst != cur ) pfree ( cur );
|
||||
if (tst != cur)
|
||||
pfree(cur);
|
||||
|
||||
for (i = 1; i < numranges; i++)
|
||||
{
|
||||
tst = (GBT_VARKEY *) DatumGetPointer((entryvec->vector[i].key));
|
||||
cur = (GBT_VARKEY *) DatumGetPointer(PG_DETOAST_DATUM((entryvec->vector[i].key)));
|
||||
gbt_var_bin_union(&out, cur, tinfo);
|
||||
if ( tst != cur ) pfree ( cur );
|
||||
if (tst != cur)
|
||||
pfree(cur);
|
||||
}
|
||||
|
||||
|
||||
@ -307,24 +324,32 @@ gbt_var_union ( const GistEntryVector * entryvec , int32 * size , const gbtree_
|
||||
}
|
||||
|
||||
|
||||
extern bool gbt_var_same ( bool * result, const Datum d1 , const Datum d2 , const gbtree_vinfo * tinfo ){
|
||||
extern bool
|
||||
gbt_var_same(bool *result, const Datum d1, const Datum d2, const gbtree_vinfo * tinfo)
|
||||
{
|
||||
|
||||
GBT_VARKEY *tst1 = (GBT_VARKEY *) DatumGetPointer(d1);
|
||||
GBT_VARKEY *t1 = (GBT_VARKEY *) DatumGetPointer(PG_DETOAST_DATUM(d1));
|
||||
GBT_VARKEY *tst2 = (GBT_VARKEY *) DatumGetPointer(d2);
|
||||
GBT_VARKEY *t2 = (GBT_VARKEY *) DatumGetPointer(PG_DETOAST_DATUM(d2));
|
||||
GBT_VARKEY_R r1, r2;
|
||||
GBT_VARKEY_R r1,
|
||||
r2;
|
||||
|
||||
r1 = gbt_var_key_readable(t1);
|
||||
r2 = gbt_var_key_readable(t2);
|
||||
|
||||
if (t1 && t2){
|
||||
if (t1 && t2)
|
||||
{
|
||||
*result = (((*tinfo->f_cmp) ((bytea *) r1.lower, (bytea *) r2.lower) == 0
|
||||
&& (*tinfo->f_cmp) ((bytea *) r1.upper, (bytea *) r2.upper) == 0) ? TRUE : FALSE);
|
||||
} else
|
||||
}
|
||||
else
|
||||
*result = (t1 == NULL && t2 == NULL) ? TRUE : FALSE;
|
||||
|
||||
if ( tst1 != t1 ) pfree (t1);
|
||||
if ( tst2 != t2 ) pfree (t2);
|
||||
if (tst1 != t1)
|
||||
pfree(t1);
|
||||
if (tst2 != t2)
|
||||
pfree(t2);
|
||||
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
@ -339,7 +364,8 @@ gbt_var_penalty ( float * res , const GISTENTRY * o , const GISTENTRY * n, const
|
||||
GBT_VARKEY *orge = (GBT_VARKEY *) DatumGetPointer(PG_DETOAST_DATUM(o->key));
|
||||
GBT_VARKEY *newt = (GBT_VARKEY *) DatumGetPointer(n->key);
|
||||
GBT_VARKEY *newe = (GBT_VARKEY *) DatumGetPointer(PG_DETOAST_DATUM(n->key));
|
||||
GBT_VARKEY_R ok , nk;
|
||||
GBT_VARKEY_R ok,
|
||||
nk;
|
||||
GBT_VARKEY *tmp = NULL;
|
||||
int32 s = (tinfo->str) ? (1) : (0);
|
||||
|
||||
@ -355,10 +381,8 @@ gbt_var_penalty ( float * res , const GISTENTRY * o , const GISTENTRY * n, const
|
||||
ok = gbt_var_key_readable(orge);
|
||||
|
||||
if ((VARSIZE(ok.lower) - VARHDRSZ) == s && (VARSIZE(ok.upper) - VARHDRSZ) == s)
|
||||
{
|
||||
*res = 0.0;
|
||||
} else
|
||||
if ( ! (
|
||||
else if (!(
|
||||
(
|
||||
((*tinfo->f_cmp) (nk.lower, ok.lower) >= 0 || gbt_bytea_pf_match(ok.lower, nk.lower, tinfo)) &&
|
||||
((*tinfo->f_cmp) (nk.upper, ok.upper) <= 0 || gbt_bytea_pf_match(ok.upper, nk.upper, tinfo))
|
||||
@ -367,23 +391,31 @@ gbt_var_penalty ( float * res , const GISTENTRY * o , const GISTENTRY * n, const
|
||||
{
|
||||
Datum d = PointerGetDatum(0);
|
||||
double dres = 0.0;
|
||||
int32 ol, ul;
|
||||
int32 ol,
|
||||
ul;
|
||||
|
||||
gbt_var_bin_union(&d, orge, tinfo);
|
||||
ol = gbt_var_node_cp_len((GBT_VARKEY *) DatumGetPointer(d), tinfo);
|
||||
gbt_var_bin_union(&d, newe, tinfo);
|
||||
ul = gbt_var_node_cp_len((GBT_VARKEY *) DatumGetPointer(d), tinfo);
|
||||
|
||||
if ( ul < ol ) {
|
||||
if (ul < ol)
|
||||
{
|
||||
dres = (ol - ul); /* lost of common prefix len */
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
GBT_VARKEY_R uk = gbt_var_key_readable((GBT_VARKEY *) DatumGetPointer(d));
|
||||
|
||||
if (tinfo->str)
|
||||
{
|
||||
dres = (VARDATA(ok.lower)[ul] - VARDATA(uk.lower)[ul]) +
|
||||
(VARDATA(uk.upper)[ul] - VARDATA(ok.upper)[ul]);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
char tmp[4];
|
||||
|
||||
tmp[0] = ((VARSIZE(ok.lower) - VARHDRSZ) == ul) ? (CHAR_MIN) : (VARDATA(ok.lower)[ul]);
|
||||
tmp[1] = ((VARSIZE(uk.lower) - VARHDRSZ) == ul) ? (CHAR_MIN) : (VARDATA(uk.lower)[ul]);
|
||||
tmp[2] = ((VARSIZE(ok.upper) - VARHDRSZ) == ul) ? (CHAR_MIN) : (VARDATA(ok.upper)[ul]);
|
||||
@ -404,13 +436,11 @@ gbt_var_penalty ( float * res , const GISTENTRY * o , const GISTENTRY * n, const
|
||||
if (tmp && tmp != newe)
|
||||
pfree(tmp);
|
||||
|
||||
if ( newe != newt ){
|
||||
if (newe != newt)
|
||||
pfree(newe);
|
||||
}
|
||||
|
||||
if ( orge != orgt ){
|
||||
if (orge != orgt)
|
||||
pfree(orge);
|
||||
}
|
||||
return res;
|
||||
|
||||
}
|
||||
@ -461,9 +491,11 @@ gbt_var_picksplit( const GistEntryVector *entryvec, GIST_SPLITVEC *v, const gbtr
|
||||
for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
|
||||
{
|
||||
GBT_VARKEY_R ro;
|
||||
|
||||
tst = (char *) DatumGetPointer((entryvec->vector[i].key));
|
||||
cur = (char *) DatumGetPointer(PG_DETOAST_DATUM((entryvec->vector[i].key)));
|
||||
if ( tst != cur ){
|
||||
if (tst != cur)
|
||||
{
|
||||
pfr[pfrcntr] = cur;
|
||||
pfrcntr++;
|
||||
}
|
||||
@ -474,9 +506,9 @@ gbt_var_picksplit( const GistEntryVector *entryvec, GIST_SPLITVEC *v, const gbtr
|
||||
arr[i].t = sv[svcntr];
|
||||
if (sv[svcntr] != (GBT_VARKEY *) cur)
|
||||
svcntr++;
|
||||
} else {
|
||||
arr[i].t = ( GBT_VARKEY *) cur;
|
||||
}
|
||||
else
|
||||
arr[i].t = (GBT_VARKEY *) cur;
|
||||
arr[i].i = i;
|
||||
}
|
||||
|
||||
@ -506,24 +538,18 @@ gbt_var_picksplit( const GistEntryVector *entryvec, GIST_SPLITVEC *v, const gbtr
|
||||
}
|
||||
|
||||
/* Free detoasted keys */
|
||||
for ( i=0 ; i<pfrcntr; i++ ){
|
||||
for (i = 0; i < pfrcntr; i++)
|
||||
pfree(pfr[i]);
|
||||
}
|
||||
|
||||
/* Free strxfrm'ed leafs */
|
||||
for ( i=0 ; i<svcntr; i++ ){
|
||||
for (i = 0; i < svcntr; i++)
|
||||
pfree(sv[i]);
|
||||
}
|
||||
|
||||
if (pfr)
|
||||
{
|
||||
pfree(pfr);
|
||||
}
|
||||
|
||||
if (sv)
|
||||
{
|
||||
pfree(sv);
|
||||
}
|
||||
|
||||
/* Truncate (=compress) key */
|
||||
|
||||
|
@ -5,7 +5,8 @@ typedef bytea GBT_VARKEY;
|
||||
/* Better readable key */
|
||||
typedef struct
|
||||
{
|
||||
bytea * lower, * upper;
|
||||
bytea *lower,
|
||||
*upper;
|
||||
} GBT_VARKEY_R;
|
||||
|
||||
/* used for key sorting */
|
||||
|
@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
* pending.c
|
||||
* $Id: pending.c,v 1.18 2004/05/26 00:08:26 wieck Exp $
|
||||
* $PostgreSQL: pgsql/contrib/dbmirror/pending.c,v 1.18 2004/05/26 00:08:26 wieck Exp $
|
||||
* $Id: pending.c,v 1.19 2004/08/29 05:06:35 momjian Exp $
|
||||
* $PostgreSQL: pgsql/contrib/dbmirror/pending.c,v 1.19 2004/08/29 05:06:35 momjian Exp $
|
||||
*
|
||||
* This file contains a trigger for Postgresql-7.x to record changes to tables
|
||||
* to a pending table for mirroring.
|
||||
@ -77,7 +77,6 @@ PG_FUNCTION_INFO_V1(recordchange);
|
||||
#define debug_msg2(x,y)
|
||||
#define debug_msg(x)
|
||||
#define debug_msg3(x,y,z)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -590,7 +589,8 @@ packageData(HeapTuple tTupleData, TupleDesc tTupleDesc, Oid tableOid,
|
||||
|
||||
PG_FUNCTION_INFO_V1(setval);
|
||||
|
||||
Datum setval(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
setval(PG_FUNCTION_ARGS)
|
||||
{
|
||||
|
||||
|
||||
@ -750,9 +750,7 @@ saveSequenceUpdate(const text * sequenceName,
|
||||
|
||||
|
||||
if (insertPlan == NULL || insertDataPlan == NULL)
|
||||
{
|
||||
ereport(ERROR, (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), errmsg("dbmirror:nextval error creating plan")));
|
||||
}
|
||||
|
||||
insertDatum[1] = Int32GetDatum(GetCurrentTransactionId());
|
||||
insertDatum[0] = PointerGetDatum(sequenceName);
|
||||
@ -775,4 +773,3 @@ saveSequenceUpdate(const text * sequenceName,
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
@ -50,6 +50,7 @@ database_size(PG_FUNCTION_ARGS)
|
||||
|
||||
Oid dbid;
|
||||
int64 totalsize;
|
||||
|
||||
#ifdef SYMLINK
|
||||
Relation dbrel;
|
||||
HeapScanDesc scan;
|
||||
@ -72,6 +73,7 @@ database_size(PG_FUNCTION_ARGS)
|
||||
while ((tuple = heap_getnext(scan, ForwardScanDirection)))
|
||||
{
|
||||
Oid spcid = HeapTupleGetOid(tuple);
|
||||
|
||||
if (spcid != GLOBALTABLESPACE_OID)
|
||||
totalsize += get_tablespace_size(dbid, spcid, true);
|
||||
}
|
||||
|
@ -48,8 +48,8 @@
|
||||
|
||||
|
||||
/*
|
||||
* $Revision: 1.2 $
|
||||
* $Id: dmetaphone.c,v 1.2 2004/08/20 19:48:14 momjian Exp $
|
||||
* $Revision: 1.3 $
|
||||
* $Id: dmetaphone.c,v 1.3 2004/08/29 05:06:35 momjian Exp $
|
||||
*/
|
||||
|
||||
|
||||
@ -109,7 +109,6 @@ The remaining code is authored by Andrew Dunstan <amdunstan@ncshp.org> and
|
||||
|
||||
/* turn off assertions for embedded function */
|
||||
#define NDEBUG
|
||||
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
@ -138,9 +137,14 @@ PG_FUNCTION_INFO_V1(dmetaphone);
|
||||
Datum
|
||||
dmetaphone(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text * arg, * result;
|
||||
int alen, rsize;
|
||||
char * aptr, *codes[2], * code, * rptr;
|
||||
text *arg,
|
||||
*result;
|
||||
int alen,
|
||||
rsize;
|
||||
char *aptr,
|
||||
*codes[2],
|
||||
*code,
|
||||
*rptr;
|
||||
|
||||
#ifdef DMETAPHONE_NOSTRICT
|
||||
if (PG_ARGISNULL(0))
|
||||
@ -150,11 +154,10 @@ dmetaphone(PG_FUNCTION_ARGS)
|
||||
alen = VARSIZE(arg) - VARHDRSZ;
|
||||
|
||||
/*
|
||||
* Postgres' string values might not have trailing nuls.
|
||||
* The VARSIZE will not include the nul in any case
|
||||
* so we copy things out and add a trailing nul.
|
||||
* When we copy back we ignore the nul
|
||||
* (and we don't make space for it).
|
||||
* Postgres' string values might not have trailing nuls. The VARSIZE
|
||||
* will not include the nul in any case so we copy things out and add
|
||||
* a trailing nul. When we copy back we ignore the nul (and we don't
|
||||
* make space for it).
|
||||
*/
|
||||
|
||||
aptr = palloc(alen + 1);
|
||||
@ -183,9 +186,14 @@ PG_FUNCTION_INFO_V1(dmetaphone_alt);
|
||||
Datum
|
||||
dmetaphone_alt(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text * arg, * result;
|
||||
int alen, rsize;
|
||||
char * aptr, * codes[2], * code, * rptr;
|
||||
text *arg,
|
||||
*result;
|
||||
int alen,
|
||||
rsize;
|
||||
char *aptr,
|
||||
*codes[2],
|
||||
*code,
|
||||
*rptr;
|
||||
|
||||
#ifdef DMETAPHONE_NOSTRICT
|
||||
if (PG_ARGISNULL(0))
|
||||
@ -240,7 +248,6 @@ dmetaphone_alt(PG_FUNCTION_ARGS)
|
||||
(v = (t*)realloc((v),((n)*sizeof(t))))
|
||||
|
||||
#define META_FREE(x) free((x))
|
||||
|
||||
#endif /* defined DMETAPHONE_MAIN */
|
||||
|
||||
|
||||
@ -254,6 +261,7 @@ typedef struct
|
||||
int bufsize;
|
||||
int free_string_on_destroy;
|
||||
}
|
||||
|
||||
metastring;
|
||||
|
||||
/*
|
||||
@ -315,10 +323,8 @@ MakeUpper(metastring * s)
|
||||
char *i;
|
||||
|
||||
for (i = s->str; *i; i++)
|
||||
{
|
||||
*i = toupper(*i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
@ -414,9 +420,7 @@ MetaphAdd(metastring * s, char *new_str)
|
||||
|
||||
add_length = strlen(new_str);
|
||||
if ((s->length + add_length) > (s->bufsize - 1))
|
||||
{
|
||||
IncreaseBuffer(s, add_length);
|
||||
}
|
||||
|
||||
strcat(s->str, new_str);
|
||||
s->length += add_length;
|
||||
@ -574,8 +578,10 @@ DoubleMetaphone(char *str, char **codes)
|
||||
|| ((StringAt(original, (current - 1), 1,
|
||||
"A", "O", "U", "E", "")
|
||||
|| (current == 0))
|
||||
/* e.g., 'wachtler', 'wechsler',
|
||||
but not 'tichner' */
|
||||
|
||||
/*
|
||||
* e.g., 'wachtler', 'wechsler', but not 'tichner'
|
||||
*/
|
||||
&& StringAt(original, (current + 2), 1, "L", "R",
|
||||
"N", "M", "B", "H", "F", "V", "W",
|
||||
" ", "")))
|
||||
@ -696,8 +702,7 @@ DoubleMetaphone(char *str, char **codes)
|
||||
/* name sent in 'mac caffrey', 'mac gregor */
|
||||
if (StringAt(original, (current + 1), 2, " C", " Q", " G", ""))
|
||||
current += 3;
|
||||
else
|
||||
if (StringAt(original, (current + 1), 1, "C", "K", "Q", "")
|
||||
else if (StringAt(original, (current + 1), 1, "C", "K", "Q", "")
|
||||
&& !StringAt(original, (current + 1), 2,
|
||||
"CE", "CI", ""))
|
||||
current += 2;
|
||||
@ -780,8 +785,11 @@ DoubleMetaphone(char *str, char **codes)
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Parker's rule (with some further refinements) -
|
||||
e.g., 'hugh' */
|
||||
|
||||
/*
|
||||
* Parker's rule (with some further refinements) -
|
||||
* e.g., 'hugh'
|
||||
*/
|
||||
if (
|
||||
((current > 1)
|
||||
&& StringAt(original, (current - 2), 1,
|
||||
@ -800,8 +808,10 @@ DoubleMetaphone(char *str, char **codes)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* e.g., 'laugh', 'McLaughlin', 'cough',
|
||||
'gough', 'rough', 'tough' */
|
||||
/*
|
||||
* e.g., 'laugh', 'McLaughlin', 'cough', 'gough',
|
||||
* 'rough', 'tough'
|
||||
*/
|
||||
if ((current > 2)
|
||||
&& (GetAt(original, current - 1) == 'U')
|
||||
&& StringAt(original, (current - 3), 1, "C",
|
||||
@ -939,7 +949,8 @@ DoubleMetaphone(char *str, char **codes)
|
||||
MetaphAdd(secondary, "H");
|
||||
current += 2;
|
||||
}
|
||||
else /* also takes care of 'HH' */
|
||||
else
|
||||
/* also takes care of 'HH' */
|
||||
current += 1;
|
||||
break;
|
||||
|
||||
@ -1174,10 +1185,11 @@ DoubleMetaphone(char *str, char **codes)
|
||||
break;
|
||||
}
|
||||
|
||||
/* german & anglicisations, e.g. 'smith' match 'schmidt',
|
||||
'snider' match 'schneider'
|
||||
also, -sz- in slavic language altho in hungarian it is
|
||||
pronounced 's' */
|
||||
/*
|
||||
* german & anglicisations, e.g. 'smith' match 'schmidt',
|
||||
* 'snider' match 'schneider' also, -sz- in slavic
|
||||
* language altho in hungarian it is pronounced 's'
|
||||
*/
|
||||
if (((current == 0)
|
||||
&& StringAt(original, (current + 1), 1,
|
||||
"M", "N", "L", "W", ""))
|
||||
@ -1428,8 +1440,11 @@ DoubleMetaphone(char *str, char **codes)
|
||||
default:
|
||||
current += 1;
|
||||
}
|
||||
/* printf("PRIMARY: %s\n", primary->str);
|
||||
printf("SECONDARY: %s\n", secondary->str); */
|
||||
|
||||
/*
|
||||
* printf("PRIMARY: %s\n", primary->str); printf("SECONDARY:
|
||||
* %s\n", secondary->str);
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
@ -1454,6 +1469,7 @@ DoubleMetaphone(char *str, char **codes)
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char *codes[2];
|
||||
|
||||
if (argc > 1)
|
||||
{
|
||||
DoubleMetaphone(argv[1], codes);
|
||||
|
@ -39,7 +39,8 @@ Datum _intbig_out(PG_FUNCTION_ARGS);
|
||||
|
||||
|
||||
Datum
|
||||
_intbig_in(PG_FUNCTION_ARGS) {
|
||||
_intbig_in(PG_FUNCTION_ARGS)
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("_intbig_in() not implemented")));
|
||||
@ -47,7 +48,8 @@ _intbig_in(PG_FUNCTION_ARGS) {
|
||||
}
|
||||
|
||||
Datum
|
||||
_intbig_out(PG_FUNCTION_ARGS) {
|
||||
_intbig_out(PG_FUNCTION_ARGS)
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("_intbig_out() not implemented")));
|
||||
@ -64,7 +66,8 @@ _intbig_overlap(GISTTYPE *a, ArrayType *b)
|
||||
int num = ARRNELEMS(b);
|
||||
int4 *ptr = ARRPTR(b);
|
||||
|
||||
while(num--) {
|
||||
while (num--)
|
||||
{
|
||||
if (GETBIT(GETSIGN(a), HASHVAL(*ptr)))
|
||||
return true;
|
||||
ptr++;
|
||||
@ -79,7 +82,8 @@ _intbig_contains(GISTTYPE *a, ArrayType *b)
|
||||
int num = ARRNELEMS(b);
|
||||
int4 *ptr = ARRPTR(b);
|
||||
|
||||
while(num--) {
|
||||
while (num--)
|
||||
{
|
||||
if (!GETBIT(GETSIGN(a), HASHVAL(*ptr)))
|
||||
return false;
|
||||
ptr++;
|
||||
@ -89,7 +93,8 @@ _intbig_contains(GISTTYPE *a, ArrayType *b)
|
||||
}
|
||||
|
||||
Datum
|
||||
g_intbig_same(PG_FUNCTION_ARGS) {
|
||||
g_intbig_same(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTTYPE *a = (GISTTYPE *) PG_GETARG_POINTER(0);
|
||||
GISTTYPE *b = (GISTTYPE *) PG_GETARG_POINTER(1);
|
||||
bool *result = (bool *) PG_GETARG_POINTER(2);
|
||||
@ -100,13 +105,16 @@ g_intbig_same(PG_FUNCTION_ARGS) {
|
||||
*result = false;
|
||||
else if (ISALLTRUE(b))
|
||||
*result = false;
|
||||
else {
|
||||
else
|
||||
{
|
||||
int4 i;
|
||||
BITVECP sa = GETSIGN(a),
|
||||
sb = GETSIGN(b);
|
||||
|
||||
*result = true;
|
||||
LOOPBYTE(
|
||||
if (sa[i] != sb[i]) {
|
||||
if (sa[i] != sb[i])
|
||||
{
|
||||
*result = false;
|
||||
break;
|
||||
}
|
||||
@ -120,7 +128,8 @@ g_intbig_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
|
||||
if (entry->leafkey) {
|
||||
if (entry->leafkey)
|
||||
{
|
||||
GISTENTRY *retval;
|
||||
ArrayType *in = (ArrayType *) PG_DETOAST_DATUM(entry->key);
|
||||
int4 *ptr;
|
||||
@ -134,7 +143,8 @@ g_intbig_compress(PG_FUNCTION_ARGS)
|
||||
memset(res, 0, CALCGTSIZE(0));
|
||||
res->len = CALCGTSIZE(0);
|
||||
|
||||
while(num--) {
|
||||
while (num--)
|
||||
{
|
||||
HASH(GETSIGN(res), *ptr);
|
||||
ptr++;
|
||||
}
|
||||
@ -148,7 +158,9 @@ g_intbig_compress(PG_FUNCTION_ARGS)
|
||||
pfree(in);
|
||||
|
||||
PG_RETURN_POINTER(retval);
|
||||
} else if ( !ISALLTRUE(DatumGetPointer(entry->key)) ) {
|
||||
}
|
||||
else if (!ISALLTRUE(DatumGetPointer(entry->key)))
|
||||
{
|
||||
GISTENTRY *retval;
|
||||
int i;
|
||||
BITVECP sign = GETSIGN(DatumGetPointer(entry->key));
|
||||
@ -176,8 +188,11 @@ g_intbig_compress(PG_FUNCTION_ARGS)
|
||||
|
||||
|
||||
static int4
|
||||
sizebitvec(BITVECP sign) {
|
||||
int4 size = 0, i;
|
||||
sizebitvec(BITVECP sign)
|
||||
{
|
||||
int4 size = 0,
|
||||
i;
|
||||
|
||||
LOOPBYTE(
|
||||
size += SUMBIT(sign);
|
||||
sign = (BITVECP) (((char *) sign) + 1);
|
||||
@ -186,8 +201,10 @@ sizebitvec(BITVECP sign) {
|
||||
}
|
||||
|
||||
static int
|
||||
hemdistsign(BITVECP a, BITVECP b) {
|
||||
int i,dist=0;
|
||||
hemdistsign(BITVECP a, BITVECP b)
|
||||
{
|
||||
int i,
|
||||
dist = 0;
|
||||
|
||||
LOOPBIT(
|
||||
if (GETBIT(a, i) != GETBIT(b, i))
|
||||
@ -197,13 +214,16 @@ hemdistsign(BITVECP a, BITVECP b) {
|
||||
}
|
||||
|
||||
static int
|
||||
hemdist(GISTTYPE *a, GISTTYPE *b) {
|
||||
if ( ISALLTRUE(a) ) {
|
||||
hemdist(GISTTYPE * a, GISTTYPE * b)
|
||||
{
|
||||
if (ISALLTRUE(a))
|
||||
{
|
||||
if (ISALLTRUE(b))
|
||||
return 0;
|
||||
else
|
||||
return SIGLENBIT - sizebitvec(GETSIGN(b));
|
||||
} else if (ISALLTRUE(b))
|
||||
}
|
||||
else if (ISALLTRUE(b))
|
||||
return SIGLENBIT - sizebitvec(GETSIGN(a));
|
||||
|
||||
return hemdistsign(GETSIGN(a), GETSIGN(b));
|
||||
@ -230,17 +250,21 @@ unionkey(BITVECP sbase, GISTTYPE * add)
|
||||
}
|
||||
|
||||
Datum
|
||||
g_intbig_union(PG_FUNCTION_ARGS) {
|
||||
g_intbig_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
||||
int *size = (int *) PG_GETARG_POINTER(1);
|
||||
BITVEC base;
|
||||
int4 i, len;
|
||||
int4 i,
|
||||
len;
|
||||
int4 flag = 0;
|
||||
GISTTYPE *result;
|
||||
|
||||
MemSet((void *) base, 0, sizeof(BITVEC));
|
||||
for (i = 0; i < entryvec->n; i++) {
|
||||
if (unionkey(base, GETENTRY(entryvec, i))) {
|
||||
for (i = 0; i < entryvec->n; i++)
|
||||
{
|
||||
if (unionkey(base, GETENTRY(entryvec, i)))
|
||||
{
|
||||
flag = ALLISTRUE;
|
||||
break;
|
||||
}
|
||||
@ -257,7 +281,8 @@ g_intbig_union(PG_FUNCTION_ARGS) {
|
||||
}
|
||||
|
||||
Datum
|
||||
g_intbig_penalty(PG_FUNCTION_ARGS) {
|
||||
g_intbig_penalty(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0); /* always ISSIGNKEY */
|
||||
GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
|
||||
float *penalty = (float *) PG_GETARG_POINTER(2);
|
||||
@ -269,19 +294,22 @@ g_intbig_penalty(PG_FUNCTION_ARGS) {
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
OffsetNumber pos;
|
||||
int4 cost;
|
||||
} SPLITCOST;
|
||||
|
||||
static int
|
||||
comparecost(const void *a, const void *b) {
|
||||
comparecost(const void *a, const void *b)
|
||||
{
|
||||
return ((SPLITCOST *) a)->cost - ((SPLITCOST *) b)->cost;
|
||||
}
|
||||
|
||||
|
||||
Datum
|
||||
g_intbig_picksplit(PG_FUNCTION_ARGS) {
|
||||
g_intbig_picksplit(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
||||
GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
|
||||
OffsetNumber k,
|
||||
@ -290,7 +318,8 @@ g_intbig_picksplit(PG_FUNCTION_ARGS) {
|
||||
*datum_r;
|
||||
BITVECP union_l,
|
||||
union_r;
|
||||
int4 size_alpha, size_beta;
|
||||
int4 size_alpha,
|
||||
size_beta;
|
||||
int4 size_waste,
|
||||
waste = -1;
|
||||
int4 nbytes;
|
||||
@ -310,11 +339,14 @@ g_intbig_picksplit(PG_FUNCTION_ARGS) {
|
||||
v->spl_left = (OffsetNumber *) palloc(nbytes);
|
||||
v->spl_right = (OffsetNumber *) palloc(nbytes);
|
||||
|
||||
for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k)) {
|
||||
for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k))
|
||||
{
|
||||
_k = GETENTRY(entryvec, k);
|
||||
for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j)) {
|
||||
for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j))
|
||||
{
|
||||
size_waste = hemdist(_k, GETENTRY(entryvec, j));
|
||||
if (size_waste > waste ) {
|
||||
if (size_waste > waste)
|
||||
{
|
||||
waste = size_waste;
|
||||
seed_1 = k;
|
||||
seed_2 = j;
|
||||
@ -398,10 +430,13 @@ g_intbig_picksplit(PG_FUNCTION_ARGS) {
|
||||
|
||||
if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.00001))
|
||||
{
|
||||
if (ISALLTRUE(datum_l) || ISALLTRUE(_j) ) {
|
||||
if (ISALLTRUE(datum_l) || ISALLTRUE(_j))
|
||||
{
|
||||
if (!ISALLTRUE(datum_l))
|
||||
MemSet((void *) union_l, 0xff, sizeof(BITVEC));
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = GETSIGN(_j);
|
||||
LOOPBYTE(
|
||||
union_l[i] |= ptr[i];
|
||||
@ -412,10 +447,13 @@ g_intbig_picksplit(PG_FUNCTION_ARGS) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ISALLTRUE(datum_r) || ISALLTRUE(_j) ) {
|
||||
if (ISALLTRUE(datum_r) || ISALLTRUE(_j))
|
||||
{
|
||||
if (!ISALLTRUE(datum_r))
|
||||
MemSet((void *) union_r, 0xff, sizeof(BITVEC));
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = GETSIGN(_j);
|
||||
LOOPBYTE(
|
||||
union_r[i] |= ptr[i];
|
||||
@ -446,7 +484,8 @@ g_intbig_consistent(PG_FUNCTION_ARGS)
|
||||
if (ISALLTRUE(DatumGetPointer(entry->key)))
|
||||
PG_RETURN_BOOL(true);
|
||||
|
||||
if (strategy == BooleanSearchStrategy) {
|
||||
if (strategy == BooleanSearchStrategy)
|
||||
{
|
||||
PG_RETURN_BOOL(signconsistent((QUERYTYPE *) query,
|
||||
GETSIGN(DatumGetPointer(entry->key)),
|
||||
false));
|
||||
@ -462,14 +501,19 @@ g_intbig_consistent(PG_FUNCTION_ARGS)
|
||||
retval = _intbig_overlap((GISTTYPE *) DatumGetPointer(entry->key), query);
|
||||
break;
|
||||
case RTSameStrategyNumber:
|
||||
if (GIST_LEAF(entry)) {
|
||||
int i,num=ARRNELEMS(query);
|
||||
if (GIST_LEAF(entry))
|
||||
{
|
||||
int i,
|
||||
num = ARRNELEMS(query);
|
||||
int4 *ptr = ARRPTR(query);
|
||||
BITVEC qp;
|
||||
BITVECP dq, de;
|
||||
BITVECP dq,
|
||||
de;
|
||||
|
||||
memset(qp, 0, sizeof(BITVEC));
|
||||
|
||||
while(num--) {
|
||||
while (num--)
|
||||
{
|
||||
HASH(qp, *ptr);
|
||||
ptr++;
|
||||
}
|
||||
@ -478,27 +522,34 @@ g_intbig_consistent(PG_FUNCTION_ARGS)
|
||||
dq = qp;
|
||||
retval = true;
|
||||
LOOPBYTE(
|
||||
if ( de[i] != dq[i] ) {
|
||||
if (de[i] != dq[i])
|
||||
{
|
||||
retval = false;
|
||||
break;
|
||||
}
|
||||
);
|
||||
|
||||
} else
|
||||
}
|
||||
else
|
||||
retval = _intbig_contains((GISTTYPE *) DatumGetPointer(entry->key), query);
|
||||
break;
|
||||
case RTContainsStrategyNumber:
|
||||
retval = _intbig_contains((GISTTYPE *) DatumGetPointer(entry->key), query);
|
||||
break;
|
||||
case RTContainedByStrategyNumber:
|
||||
if (GIST_LEAF(entry)) {
|
||||
int i,num=ARRNELEMS(query);
|
||||
if (GIST_LEAF(entry))
|
||||
{
|
||||
int i,
|
||||
num = ARRNELEMS(query);
|
||||
int4 *ptr = ARRPTR(query);
|
||||
BITVEC qp;
|
||||
BITVECP dq, de;
|
||||
BITVECP dq,
|
||||
de;
|
||||
|
||||
memset(qp, 0, sizeof(BITVEC));
|
||||
|
||||
while(num--) {
|
||||
while (num--)
|
||||
{
|
||||
HASH(qp, *ptr);
|
||||
ptr++;
|
||||
}
|
||||
@ -507,13 +558,15 @@ g_intbig_consistent(PG_FUNCTION_ARGS)
|
||||
dq = qp;
|
||||
retval = true;
|
||||
LOOPBYTE(
|
||||
if ( de[i] & ~dq[i] ) {
|
||||
if (de[i] & ~dq[i])
|
||||
{
|
||||
retval = false;
|
||||
break;
|
||||
}
|
||||
);
|
||||
|
||||
} else
|
||||
}
|
||||
else
|
||||
retval = _intbig_overlap((GISTTYPE *) DatumGetPointer(entry->key), query);
|
||||
break;
|
||||
default:
|
||||
@ -521,5 +574,3 @@ g_intbig_consistent(PG_FUNCTION_ARGS)
|
||||
}
|
||||
PG_RETURN_BOOL(retval);
|
||||
}
|
||||
|
||||
|
||||
|
@ -175,7 +175,8 @@ _ltree_union(PG_FUNCTION_ARGS)
|
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
||||
int *size = (int *) PG_GETARG_POINTER(1);
|
||||
ABITVEC base;
|
||||
int4 i,len;
|
||||
int4 i,
|
||||
len;
|
||||
int4 flag = 0;
|
||||
ltree_gist *result;
|
||||
|
||||
@ -213,8 +214,10 @@ sizebitvec(BITVECP sign)
|
||||
}
|
||||
|
||||
static int
|
||||
hemdistsign(BITVECP a, BITVECP b) {
|
||||
int i,dist=0;
|
||||
hemdistsign(BITVECP a, BITVECP b)
|
||||
{
|
||||
int i,
|
||||
dist = 0;
|
||||
|
||||
ALOOPBIT(
|
||||
if (GETBIT(a, i) != GETBIT(b, i))
|
||||
@ -224,13 +227,16 @@ hemdistsign(BITVECP a, BITVECP b) {
|
||||
}
|
||||
|
||||
static int
|
||||
hemdist(ltree_gist *a, ltree_gist *b) {
|
||||
if ( LTG_ISALLTRUE(a) ) {
|
||||
hemdist(ltree_gist * a, ltree_gist * b)
|
||||
{
|
||||
if (LTG_ISALLTRUE(a))
|
||||
{
|
||||
if (LTG_ISALLTRUE(b))
|
||||
return 0;
|
||||
else
|
||||
return ASIGLENBIT - sizebitvec(LTG_SIGN(b));
|
||||
} else if (LTG_ISALLTRUE(b))
|
||||
}
|
||||
else if (LTG_ISALLTRUE(b))
|
||||
return ASIGLENBIT - sizebitvec(LTG_SIGN(a));
|
||||
|
||||
return hemdistsign(LTG_SIGN(a), LTG_SIGN(b));
|
||||
@ -271,7 +277,8 @@ _ltree_picksplit(PG_FUNCTION_ARGS)
|
||||
*datum_r;
|
||||
BITVECP union_l,
|
||||
union_r;
|
||||
int4 size_alpha, size_beta;
|
||||
int4 size_alpha,
|
||||
size_beta;
|
||||
int4 size_waste,
|
||||
waste = -1;
|
||||
int4 nbytes;
|
||||
@ -291,11 +298,14 @@ _ltree_picksplit(PG_FUNCTION_ARGS)
|
||||
v->spl_left = (OffsetNumber *) palloc(nbytes);
|
||||
v->spl_right = (OffsetNumber *) palloc(nbytes);
|
||||
|
||||
for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k)) {
|
||||
for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k))
|
||||
{
|
||||
_k = GETENTRY(entryvec, k);
|
||||
for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j)) {
|
||||
for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j))
|
||||
{
|
||||
size_waste = hemdist(_k, GETENTRY(entryvec, j));
|
||||
if (size_waste > waste ) {
|
||||
if (size_waste > waste)
|
||||
{
|
||||
waste = size_waste;
|
||||
seed_1 = k;
|
||||
seed_2 = j;
|
||||
@ -379,10 +389,13 @@ _ltree_picksplit(PG_FUNCTION_ARGS)
|
||||
|
||||
if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.00001))
|
||||
{
|
||||
if (LTG_ISALLTRUE(datum_l) || LTG_ISALLTRUE(_j) ) {
|
||||
if (LTG_ISALLTRUE(datum_l) || LTG_ISALLTRUE(_j))
|
||||
{
|
||||
if (!LTG_ISALLTRUE(datum_l))
|
||||
MemSet((void *) union_l, 0xff, sizeof(ABITVEC));
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = LTG_SIGN(_j);
|
||||
ALOOPBYTE(
|
||||
union_l[i] |= ptr[i];
|
||||
@ -393,10 +406,13 @@ _ltree_picksplit(PG_FUNCTION_ARGS)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LTG_ISALLTRUE(datum_r) || LTG_ISALLTRUE(_j) ) {
|
||||
if (LTG_ISALLTRUE(datum_r) || LTG_ISALLTRUE(_j))
|
||||
{
|
||||
if (!LTG_ISALLTRUE(datum_r))
|
||||
MemSet((void *) union_r, 0xff, sizeof(ABITVEC));
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = LTG_SIGN(_j);
|
||||
ALOOPBYTE(
|
||||
union_r[i] |= ptr[i];
|
||||
@ -498,7 +514,8 @@ gist_qe(ltree_gist * key, lquery * query)
|
||||
}
|
||||
|
||||
static bool
|
||||
_arrq_cons(ltree_gist *key, ArrayType *_query) {
|
||||
_arrq_cons(ltree_gist * key, ArrayType *_query)
|
||||
{
|
||||
lquery *query = (lquery *) ARR_DATA_PTR(_query);
|
||||
int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
|
||||
|
||||
@ -507,7 +524,8 @@ _arrq_cons(ltree_gist *key, ArrayType *_query) {
|
||||
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
||||
errmsg("array must be one-dimensional")));
|
||||
|
||||
while (num > 0) {
|
||||
while (num > 0)
|
||||
{
|
||||
if (gist_qe(key, query))
|
||||
return true;
|
||||
num--;
|
||||
|
@ -602,7 +602,8 @@ gist_qtxt(ltree_gist * key, ltxtquery * query)
|
||||
}
|
||||
|
||||
static bool
|
||||
arrq_cons(ltree_gist *key, ArrayType *_query) {
|
||||
arrq_cons(ltree_gist * key, ArrayType *_query)
|
||||
{
|
||||
lquery *query = (lquery *) ARR_DATA_PTR(_query);
|
||||
int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
|
||||
|
||||
@ -611,7 +612,8 @@ arrq_cons(ltree_gist *key, ArrayType *_query) {
|
||||
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
||||
errmsg("array must be one-dimensional")));
|
||||
|
||||
while (num > 0) {
|
||||
while (num > 0)
|
||||
{
|
||||
if (gist_qe(key, query) && gist_between(key, query))
|
||||
return true;
|
||||
num--;
|
||||
|
@ -230,9 +230,9 @@ update_table_list(db_info * dbi)
|
||||
t = PQntuples(res);
|
||||
|
||||
/*
|
||||
* First: use the tbl_list as the outer loop and the result set as
|
||||
* the inner loop, this will determine what tables should be
|
||||
* removed
|
||||
* First: use the tbl_list as the outer loop and the result
|
||||
* set as the inner loop, this will determine what tables
|
||||
* should be removed
|
||||
*/
|
||||
while (tbl_elem != NULL)
|
||||
{
|
||||
@ -501,9 +501,9 @@ update_db_list(Dllist *db_list)
|
||||
t = PQntuples(res);
|
||||
|
||||
/*
|
||||
* First: use the db_list as the outer loop and the result set as
|
||||
* the inner loop, this will determine what databases should be
|
||||
* removed
|
||||
* First: use the db_list as the outer loop and the result set
|
||||
* as the inner loop, this will determine what databases
|
||||
* should be removed
|
||||
*/
|
||||
while (db_elem != NULL)
|
||||
{
|
||||
@ -539,8 +539,8 @@ update_db_list(Dllist *db_list)
|
||||
* the table_list */
|
||||
|
||||
/*
|
||||
* Then loop use result set as outer loop and db_list as the inner
|
||||
* loop to determine what databases are new
|
||||
* Then loop use result set as outer loop and db_list as the
|
||||
* inner loop to determine what databases are new
|
||||
*/
|
||||
for (i = 0; i < t; i++)
|
||||
{
|
||||
@ -611,9 +611,7 @@ xid_wraparound_check(db_info * dbi)
|
||||
res = send_query("VACUUM", dbi);
|
||||
/* FIXME: Perhaps should add a check for PQ_COMMAND_OK */
|
||||
if (res != NULL)
|
||||
{
|
||||
PQclear(res);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@ -1114,19 +1112,21 @@ main(int argc, char *argv[])
|
||||
atol(PQgetvalue(res, j, PQfnumber(res, "n_tup_upd"))));
|
||||
|
||||
/*
|
||||
* Check numDeletes to see if we need to
|
||||
* vacuum, if so: Run vacuum analyze
|
||||
* (adding analyze is small so we might as
|
||||
* well) Update table thresholds and
|
||||
* related information if numDeletes is
|
||||
* not big enough for vacuum then check
|
||||
* numInserts for analyze
|
||||
* Check numDeletes to see if we need
|
||||
* to vacuum, if so: Run vacuum
|
||||
* analyze (adding analyze is small so
|
||||
* we might as well) Update table
|
||||
* thresholds and related information
|
||||
* if numDeletes is not big enough for
|
||||
* vacuum then check numInserts for
|
||||
* analyze
|
||||
*/
|
||||
if (tbl->curr_vacuum_count - tbl->CountAtLastVacuum >= tbl->vacuum_threshold)
|
||||
{
|
||||
/*
|
||||
* if relisshared = t and database !=
|
||||
* template1 then only do an analyze
|
||||
* if relisshared = t and database
|
||||
* != template1 then only do an
|
||||
* analyze
|
||||
*/
|
||||
if (tbl->relisshared > 0 && strcmp("template1", dbs->dbname))
|
||||
snprintf(buf, sizeof(buf), "ANALYZE %s", tbl->table_name);
|
||||
@ -1158,8 +1158,9 @@ main(int argc, char *argv[])
|
||||
print_table_info(tbl);
|
||||
}
|
||||
|
||||
break; /* once we have found a match, no
|
||||
* need to keep checking. */
|
||||
break; /* once we have found a
|
||||
* match, no need to keep
|
||||
* checking. */
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* -------------------------------------------------------------------------
|
||||
* pg_dumplo
|
||||
*
|
||||
* $PostgreSQL: pgsql/contrib/pg_dumplo/utils.c,v 1.8 2003/11/29 19:51:35 pgsql Exp $
|
||||
* $PostgreSQL: pgsql/contrib/pg_dumplo/utils.c,v 1.9 2004/08/29 05:06:36 momjian Exp $
|
||||
*
|
||||
* Karel Zak 1999-2000
|
||||
* -------------------------------------------------------------------------
|
||||
|
@ -31,7 +31,8 @@ typedef char trgm[3];
|
||||
} while(0);
|
||||
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
int4 len;
|
||||
uint8 flag;
|
||||
char data[1];
|
||||
|
@ -75,7 +75,8 @@ makesign(BITVECP sign, TRGM * a)
|
||||
|
||||
MemSet((void *) sign, 0, sizeof(BITVEC));
|
||||
SETBIT(sign, SIGLENBIT); /* set last unused bit */
|
||||
for (k = 0; k < len; k++) {
|
||||
for (k = 0; k < len; k++)
|
||||
{
|
||||
CPTRGM(((char *) &tmp), ptr + k);
|
||||
HASH(sign, tmp);
|
||||
}
|
||||
@ -142,20 +143,28 @@ gtrgm_consistent(PG_FUNCTION_ARGS)
|
||||
TRGM *qtrg = generate_trgm(VARDATA(query), VARSIZE(query) - VARHDRSZ);
|
||||
int res = false;
|
||||
|
||||
if ( GIST_LEAF( (GISTENTRY *) PG_GETARG_POINTER(0) ) ) { /* all leafs contains orig trgm */
|
||||
if (GIST_LEAF((GISTENTRY *) PG_GETARG_POINTER(0)))
|
||||
{ /* 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 */
|
||||
}
|
||||
else if (ISALLTRUE(key))
|
||||
{ /* non-leaf contains signature */
|
||||
res = true;
|
||||
} else { /* non-leaf contains signature */
|
||||
}
|
||||
else
|
||||
{ /* non-leaf contains signature */
|
||||
int4 count = 0;
|
||||
int4 k, len = ARRNELEM(qtrg);
|
||||
int4 k,
|
||||
len = ARRNELEM(qtrg);
|
||||
trgm *ptr = GETARR(qtrg);
|
||||
BITVECP sign = GETSIGN(key);
|
||||
int4 tmp = 0;
|
||||
|
||||
for (k = 0; k < len; k++) {
|
||||
for (k = 0; k < len; k++)
|
||||
{
|
||||
CPTRGM(((char *) &tmp), ptr + k);
|
||||
count += GETBIT(sign, HASHVAL(tmp));
|
||||
}
|
||||
@ -193,7 +202,8 @@ unionkey(BITVECP sbase, TRGM * add)
|
||||
trgm *ptr = GETARR(add);
|
||||
int4 tmp = 0;
|
||||
|
||||
for (i = 0; i < ARRNELEM(add); i++) {
|
||||
for (i = 0; i < ARRNELEM(add); i++)
|
||||
{
|
||||
CPTRGM(((char *) &tmp), ptr + i);
|
||||
HASH(sbase, tmp);
|
||||
}
|
||||
@ -305,8 +315,10 @@ sizebitvec(BITVECP sign)
|
||||
}
|
||||
|
||||
static int
|
||||
hemdistsign(BITVECP a, BITVECP b) {
|
||||
int i,dist=0;
|
||||
hemdistsign(BITVECP a, BITVECP b)
|
||||
{
|
||||
int i,
|
||||
dist = 0;
|
||||
|
||||
LOOPBIT(
|
||||
if (GETBIT(a, i) != GETBIT(b, i))
|
||||
@ -316,13 +328,16 @@ hemdistsign(BITVECP a, BITVECP b) {
|
||||
}
|
||||
|
||||
static int
|
||||
hemdist(TRGM *a, TRGM *b) {
|
||||
if ( ISALLTRUE(a) ) {
|
||||
hemdist(TRGM * a, TRGM * b)
|
||||
{
|
||||
if (ISALLTRUE(a))
|
||||
{
|
||||
if (ISALLTRUE(b))
|
||||
return 0;
|
||||
else
|
||||
return SIGLENBIT - sizebitvec(GETSIGN(b));
|
||||
} else if (ISALLTRUE(b))
|
||||
}
|
||||
else if (ISALLTRUE(b))
|
||||
return SIGLENBIT - sizebitvec(GETSIGN(a));
|
||||
|
||||
return hemdistsign(GETSIGN(a), GETSIGN(b));
|
||||
@ -340,17 +355,19 @@ gtrgm_penalty(PG_FUNCTION_ARGS)
|
||||
|
||||
*penalty = 0.0;
|
||||
|
||||
if (ISARRKEY(newval)) {
|
||||
if (ISARRKEY(newval))
|
||||
{
|
||||
BITVEC sign;
|
||||
|
||||
makesign(sign, newval);
|
||||
|
||||
if (ISALLTRUE(origval))
|
||||
*penalty = ((float) (SIGLENBIT - sizebitvec(sign))) / (float) (SIGLENBIT + 1);
|
||||
else
|
||||
*penalty = hemdistsign(sign, orig);
|
||||
} else {
|
||||
*penalty=hemdist(origval,newval);
|
||||
}
|
||||
else
|
||||
*penalty = hemdist(origval, newval);
|
||||
PG_RETURN_POINTER(penalty);
|
||||
}
|
||||
|
||||
@ -390,13 +407,16 @@ comparecost(const void *a, const void *b)
|
||||
|
||||
|
||||
static int
|
||||
hemdistcache(CACHESIGN *a, CACHESIGN *b) {
|
||||
if ( a->allistrue ) {
|
||||
hemdistcache(CACHESIGN * a, CACHESIGN * b)
|
||||
{
|
||||
if (a->allistrue)
|
||||
{
|
||||
if (b->allistrue)
|
||||
return 0;
|
||||
else
|
||||
return SIGLENBIT - sizebitvec(b->sign);
|
||||
} else if (b->allistrue)
|
||||
}
|
||||
else if (b->allistrue)
|
||||
return SIGLENBIT - sizebitvec(a->sign);
|
||||
|
||||
return hemdistsign(a->sign, b->sign);
|
||||
@ -435,13 +455,16 @@ gtrgm_picksplit(PG_FUNCTION_ARGS)
|
||||
cache = (CACHESIGN *) palloc(sizeof(CACHESIGN) * (maxoff + 2));
|
||||
fillcache(&cache[FirstOffsetNumber], GETENTRY(entryvec, FirstOffsetNumber));
|
||||
|
||||
for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k)) {
|
||||
for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j)) {
|
||||
for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k))
|
||||
{
|
||||
for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j))
|
||||
{
|
||||
if (k == FirstOffsetNumber)
|
||||
fillcache(&cache[j], GETENTRY(entryvec, j));
|
||||
|
||||
size_waste = hemdistcache(&(cache[j]), &(cache[k]));
|
||||
if (size_waste > waste) {
|
||||
if (size_waste > waste)
|
||||
{
|
||||
waste = size_waste;
|
||||
seed_1 = k;
|
||||
seed_2 = j;
|
||||
@ -454,27 +477,34 @@ gtrgm_picksplit(PG_FUNCTION_ARGS)
|
||||
right = v->spl_right;
|
||||
v->spl_nright = 0;
|
||||
|
||||
if (seed_1 == 0 || seed_2 == 0) {
|
||||
if (seed_1 == 0 || seed_2 == 0)
|
||||
{
|
||||
seed_1 = 1;
|
||||
seed_2 = 2;
|
||||
}
|
||||
|
||||
/* form initial .. */
|
||||
if (cache[seed_1].allistrue) {
|
||||
if (cache[seed_1].allistrue)
|
||||
{
|
||||
datum_l = (TRGM *) palloc(CALCGTSIZE(SIGNKEY | ALLISTRUE, 0));
|
||||
datum_l->len = CALCGTSIZE(SIGNKEY | ALLISTRUE, 0);
|
||||
datum_l->flag = SIGNKEY | ALLISTRUE;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
datum_l = (TRGM *) palloc(CALCGTSIZE(SIGNKEY, 0));
|
||||
datum_l->len = CALCGTSIZE(SIGNKEY, 0);
|
||||
datum_l->flag = SIGNKEY;
|
||||
memcpy((void *) GETSIGN(datum_l), (void *) cache[seed_1].sign, sizeof(BITVEC));
|
||||
}
|
||||
if (cache[seed_2].allistrue) {
|
||||
if (cache[seed_2].allistrue)
|
||||
{
|
||||
datum_r = (TRGM *) palloc(CALCGTSIZE(SIGNKEY | ALLISTRUE, 0));
|
||||
datum_r->len = CALCGTSIZE(SIGNKEY | ALLISTRUE, 0);
|
||||
datum_r->flag = SIGNKEY | ALLISTRUE;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
datum_r = (TRGM *) palloc(CALCGTSIZE(SIGNKEY, 0));
|
||||
datum_r->len = CALCGTSIZE(SIGNKEY, 0);
|
||||
datum_r->flag = SIGNKEY;
|
||||
@ -487,7 +517,8 @@ gtrgm_picksplit(PG_FUNCTION_ARGS)
|
||||
fillcache(&cache[maxoff], GETENTRY(entryvec, maxoff));
|
||||
/* sort before ... */
|
||||
costvector = (SPLITCOST *) palloc(sizeof(SPLITCOST) * maxoff);
|
||||
for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j)) {
|
||||
for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j))
|
||||
{
|
||||
costvector[j - 1].pos = j;
|
||||
size_alpha = hemdistcache(&(cache[seed_1]), &(cache[j]));
|
||||
size_beta = hemdistcache(&(cache[seed_2]), &(cache[j]));
|
||||
@ -495,45 +526,55 @@ gtrgm_picksplit(PG_FUNCTION_ARGS)
|
||||
}
|
||||
qsort((void *) costvector, maxoff, sizeof(SPLITCOST), comparecost);
|
||||
|
||||
for (k = 0; k < maxoff; k++) {
|
||||
for (k = 0; k < maxoff; k++)
|
||||
{
|
||||
j = costvector[k].pos;
|
||||
if (j == seed_1) {
|
||||
if (j == seed_1)
|
||||
{
|
||||
*left++ = j;
|
||||
v->spl_nleft++;
|
||||
continue;
|
||||
} else if (j == seed_2) {
|
||||
}
|
||||
else if (j == seed_2)
|
||||
{
|
||||
*right++ = j;
|
||||
v->spl_nright++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ISALLTRUE(datum_l) || cache[j].allistrue) {
|
||||
if (ISALLTRUE(datum_l) || cache[j].allistrue)
|
||||
{
|
||||
if (ISALLTRUE(datum_l) && cache[j].allistrue)
|
||||
size_alpha = 0;
|
||||
else
|
||||
size_alpha = SIGLENBIT - sizebitvec(
|
||||
(cache[j].allistrue) ? GETSIGN(datum_l) : GETSIGN(cache[j].sign)
|
||||
);
|
||||
} else {
|
||||
size_alpha=hemdistsign(cache[j].sign,GETSIGN(datum_l));
|
||||
}
|
||||
else
|
||||
size_alpha = hemdistsign(cache[j].sign, GETSIGN(datum_l));
|
||||
|
||||
if (ISALLTRUE(datum_r) || cache[j].allistrue) {
|
||||
if (ISALLTRUE(datum_r) || cache[j].allistrue)
|
||||
{
|
||||
if (ISALLTRUE(datum_r) && cache[j].allistrue)
|
||||
size_beta = 0;
|
||||
else
|
||||
size_beta = SIGLENBIT - sizebitvec(
|
||||
(cache[j].allistrue) ? GETSIGN(datum_r) : GETSIGN(cache[j].sign)
|
||||
);
|
||||
} else {
|
||||
size_beta=hemdistsign(cache[j].sign,GETSIGN(datum_r));
|
||||
}
|
||||
else
|
||||
size_beta = hemdistsign(cache[j].sign, GETSIGN(datum_r));
|
||||
|
||||
if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.1)) {
|
||||
if (ISALLTRUE(datum_l) || cache[j].allistrue) {
|
||||
if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.1))
|
||||
{
|
||||
if (ISALLTRUE(datum_l) || cache[j].allistrue)
|
||||
{
|
||||
if (!ISALLTRUE(datum_l))
|
||||
MemSet((void *) GETSIGN(datum_l), 0xff, sizeof(BITVEC));
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = cache[j].sign;
|
||||
LOOPBYTE(
|
||||
union_l[i] |= ptr[i];
|
||||
@ -541,11 +582,16 @@ gtrgm_picksplit(PG_FUNCTION_ARGS)
|
||||
}
|
||||
*left++ = j;
|
||||
v->spl_nleft++;
|
||||
} else {
|
||||
if (ISALLTRUE(datum_r) || cache[j].allistrue) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ISALLTRUE(datum_r) || cache[j].allistrue)
|
||||
{
|
||||
if (!ISALLTRUE(datum_r))
|
||||
MemSet((void *) GETSIGN(datum_r), 0xff, sizeof(BITVEC));
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = cache[j].sign;
|
||||
LOOPBYTE(
|
||||
union_r[i] |= ptr[i];
|
||||
|
@ -8,8 +8,10 @@ float4 trgm_limit = 0.3;
|
||||
PG_FUNCTION_INFO_V1(set_limit);
|
||||
Datum set_limit(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
set_limit(PG_FUNCTION_ARGS) {
|
||||
set_limit(PG_FUNCTION_ARGS)
|
||||
{
|
||||
float4 nlimit = PG_GETARG_FLOAT4(0);
|
||||
|
||||
if (nlimit < 0 || nlimit > 1.0)
|
||||
elog(ERROR, "Wrong limit, should be between 0 and 1");
|
||||
trgm_limit = nlimit;
|
||||
@ -19,7 +21,8 @@ set_limit(PG_FUNCTION_ARGS) {
|
||||
PG_FUNCTION_INFO_V1(show_limit);
|
||||
Datum show_limit(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
show_limit(PG_FUNCTION_ARGS) {
|
||||
show_limit(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_FLOAT4(trgm_limit);
|
||||
}
|
||||
|
||||
@ -27,21 +30,26 @@ show_limit(PG_FUNCTION_ARGS) {
|
||||
#define INWORD 1
|
||||
|
||||
static int
|
||||
comp_trgm(const void *a, const void *b) {
|
||||
comp_trgm(const void *a, const void *b)
|
||||
{
|
||||
return CMPTRGM(a, b);
|
||||
}
|
||||
|
||||
static int
|
||||
unique_array (trgm *a, int len) {
|
||||
trgm *curend, *tmp;
|
||||
unique_array(trgm * a, int len)
|
||||
{
|
||||
trgm *curend,
|
||||
*tmp;
|
||||
|
||||
curend = tmp = a;
|
||||
while (tmp - a < len)
|
||||
if ( CMPTRGM(tmp, curend) ) {
|
||||
if (CMPTRGM(tmp, curend))
|
||||
{
|
||||
curend++;
|
||||
CPTRGM(curend, tmp);
|
||||
tmp++;
|
||||
} else
|
||||
}
|
||||
else
|
||||
tmp++;
|
||||
|
||||
return curend + 1 - a;
|
||||
@ -49,12 +57,16 @@ unique_array (trgm *a, int len) {
|
||||
|
||||
|
||||
TRGM *
|
||||
generate_trgm(char *str, int slen) {
|
||||
generate_trgm(char *str, int slen)
|
||||
{
|
||||
TRGM *trg;
|
||||
char *buf,*sptr,*bufptr;
|
||||
char *buf,
|
||||
*sptr,
|
||||
*bufptr;
|
||||
trgm *tptr;
|
||||
int state = WORDWAIT;
|
||||
int wl,len;
|
||||
int wl,
|
||||
len;
|
||||
|
||||
trg = (TRGM *) palloc(TRGMHRDSIZE + sizeof(trgm) * (slen / 2 + 1) * 3);
|
||||
trg->flag = ARRKEY;
|
||||
@ -68,42 +80,50 @@ generate_trgm(char *str, int slen) {
|
||||
buf = palloc(sizeof(char) * (slen + 4));
|
||||
sptr = str;
|
||||
|
||||
if ( LPADDING > 0 ) {
|
||||
if (LPADDING > 0)
|
||||
{
|
||||
*buf = ' ';
|
||||
if (LPADDING > 1)
|
||||
*(buf + 1) = ' ';
|
||||
}
|
||||
|
||||
bufptr = buf + LPADDING;
|
||||
while( sptr-str < slen ) {
|
||||
if ( state == WORDWAIT ) {
|
||||
while (sptr - str < slen)
|
||||
{
|
||||
if (state == WORDWAIT)
|
||||
{
|
||||
if (
|
||||
#ifdef KEEPONLYALNUM
|
||||
isalnum((unsigned char) *sptr)
|
||||
#else
|
||||
!isspace((unsigned char) *sptr)
|
||||
#endif
|
||||
) {
|
||||
)
|
||||
{
|
||||
*bufptr = *sptr; /* start put word in buffer */
|
||||
bufptr++;
|
||||
state = INWORD;
|
||||
if (sptr - str == slen - 1 /* last char */ )
|
||||
goto gettrg;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (
|
||||
#ifdef KEEPONLYALNUM
|
||||
!isalnum((unsigned char) *sptr)
|
||||
#else
|
||||
isspace((unsigned char) *sptr)
|
||||
#endif
|
||||
) {
|
||||
)
|
||||
{
|
||||
gettrg:
|
||||
/* word in buffer, so count trigrams */
|
||||
*bufptr = ' ';
|
||||
*(bufptr + 1) = ' ';
|
||||
wl = bufptr - (buf + LPADDING) - 2 + LPADDING + RPADDING;
|
||||
if ( wl<=0 ) {
|
||||
if (wl <= 0)
|
||||
{
|
||||
bufptr = buf + LPADDING;
|
||||
state = WORDWAIT;
|
||||
sptr++;
|
||||
@ -111,10 +131,13 @@ gettrg:
|
||||
}
|
||||
|
||||
#ifdef IGNORECASE
|
||||
do { /* lower word */
|
||||
do
|
||||
{ /* lower word */
|
||||
int wwl = bufptr - buf;
|
||||
|
||||
bufptr = buf + LPADDING;
|
||||
while( bufptr-buf < wwl ) {
|
||||
while (bufptr - buf < wwl)
|
||||
{
|
||||
*bufptr = tolower((unsigned char) *bufptr);
|
||||
bufptr++;
|
||||
}
|
||||
@ -122,14 +145,17 @@ gettrg:
|
||||
#endif
|
||||
bufptr = buf;
|
||||
/* set trigrams */
|
||||
while( bufptr-buf < wl ) {
|
||||
while (bufptr - buf < wl)
|
||||
{
|
||||
CPTRGM(tptr, bufptr);
|
||||
bufptr++;
|
||||
tptr++;
|
||||
}
|
||||
bufptr = buf + LPADDING;
|
||||
state = WORDWAIT;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
*bufptr = *sptr; /* put in buffer */
|
||||
bufptr++;
|
||||
if (sptr - str == slen - 1)
|
||||
@ -144,7 +170,8 @@ gettrg:
|
||||
if ((len = tptr - GETARR(trg)) == 0)
|
||||
return trg;
|
||||
|
||||
if ( len>0 ) {
|
||||
if (len > 0)
|
||||
{
|
||||
qsort((void *) GETARR(trg), len, sizeof(trgm), comp_trgm);
|
||||
len = unique_array(GETARR(trg), len);
|
||||
}
|
||||
@ -158,7 +185,8 @@ gettrg:
|
||||
PG_FUNCTION_INFO_V1(show_trgm);
|
||||
Datum show_trgm(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
show_trgm(PG_FUNCTION_ARGS) {
|
||||
show_trgm(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *in = PG_GETARG_TEXT_P(0);
|
||||
TRGM *trg;
|
||||
Datum *d;
|
||||
@ -169,8 +197,10 @@ show_trgm(PG_FUNCTION_ARGS) {
|
||||
d = (Datum *) palloc(sizeof(Datum) * (1 + ARRNELEM(trg)));
|
||||
|
||||
ptr = GETARR(trg);
|
||||
while( ptr-GETARR(trg) < ARRNELEM(trg) ) {
|
||||
while (ptr - GETARR(trg) < ARRNELEM(trg))
|
||||
{
|
||||
text *item = (text *) palloc(VARHDRSZ + 3);
|
||||
|
||||
VARATT_SIZEP(item) = VARHDRSZ + 3;
|
||||
CPTRGM(VARDATA(item), ptr);
|
||||
d[ptr - GETARR(trg)] = PointerGetDatum(item);
|
||||
@ -187,7 +217,8 @@ show_trgm(PG_FUNCTION_ARGS) {
|
||||
);
|
||||
|
||||
ptr = GETARR(trg);
|
||||
while( ptr-GETARR(trg) < ARRNELEM(trg) ) {
|
||||
while (ptr - GETARR(trg) < ARRNELEM(trg))
|
||||
{
|
||||
pfree(DatumGetPointer(d[ptr - GETARR(trg)]));
|
||||
ptr++;
|
||||
}
|
||||
@ -200,10 +231,13 @@ show_trgm(PG_FUNCTION_ARGS) {
|
||||
}
|
||||
|
||||
float4
|
||||
cnt_sml(TRGM *trg1, TRGM *trg2) {
|
||||
trgm *ptr1, *ptr2;
|
||||
cnt_sml(TRGM * trg1, TRGM * trg2)
|
||||
{
|
||||
trgm *ptr1,
|
||||
*ptr2;
|
||||
int count = 0;
|
||||
int len1, len2;
|
||||
int len1,
|
||||
len2;
|
||||
|
||||
ptr1 = GETARR(trg1);
|
||||
ptr2 = GETARR(trg2);
|
||||
@ -211,13 +245,16 @@ cnt_sml(TRGM *trg1, TRGM *trg2) {
|
||||
len1 = ARRNELEM(trg1);
|
||||
len2 = ARRNELEM(trg2);
|
||||
|
||||
while( ptr1 - GETARR(trg1) < len1 && ptr2 - GETARR(trg2) < len2 ) {
|
||||
while (ptr1 - GETARR(trg1) < len1 && ptr2 - GETARR(trg2) < len2)
|
||||
{
|
||||
int res = CMPTRGM(ptr1, ptr2);
|
||||
if ( res < 0 ) {
|
||||
|
||||
if (res < 0)
|
||||
ptr1++;
|
||||
} else if ( res > 0 ) {
|
||||
else if (res > 0)
|
||||
ptr2++;
|
||||
} else {
|
||||
else
|
||||
{
|
||||
ptr1++;
|
||||
ptr2++;
|
||||
count++;
|
||||
@ -235,10 +272,12 @@ cnt_sml(TRGM *trg1, TRGM *trg2) {
|
||||
PG_FUNCTION_INFO_V1(similarity);
|
||||
Datum similarity(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
similarity(PG_FUNCTION_ARGS) {
|
||||
similarity(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *in1 = PG_GETARG_TEXT_P(0);
|
||||
text *in2 = PG_GETARG_TEXT_P(1);
|
||||
TRGM *trg1, *trg2;
|
||||
TRGM *trg1,
|
||||
*trg2;
|
||||
float4 res;
|
||||
|
||||
trg1 = generate_trgm(VARDATA(in1), VARSIZE(in1) - VARHDRSZ);
|
||||
@ -257,13 +296,13 @@ similarity(PG_FUNCTION_ARGS) {
|
||||
PG_FUNCTION_INFO_V1(similarity_op);
|
||||
Datum similarity_op(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
similarity_op(PG_FUNCTION_ARGS) {
|
||||
similarity_op(PG_FUNCTION_ARGS)
|
||||
{
|
||||
float4 res = DatumGetFloat4(DirectFunctionCall2(
|
||||
similarity,
|
||||
PG_GETARG_DATUM(0),
|
||||
PG_GETARG_DATUM(1)
|
||||
));
|
||||
|
||||
PG_RETURN_BOOL(res >= trgm_limit);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* $PostgreSQL: pgsql/contrib/pgbench/pgbench.c,v 1.31 2004/06/14 11:00:12 ishii Exp $
|
||||
* $PostgreSQL: pgsql/contrib/pgbench/pgbench.c,v 1.32 2004/08/29 05:06:36 momjian Exp $
|
||||
*
|
||||
* pgbench: a simple TPC-B like benchmark program for PostgreSQL
|
||||
* written by Tatsuo Ishii
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* $PostgreSQL: pgsql/contrib/pgstattuple/pgstattuple.c,v 1.15 2004/05/08 19:09:24 tgl Exp $
|
||||
* $PostgreSQL: pgsql/contrib/pgstattuple/pgstattuple.c,v 1.16 2004/08/29 05:06:37 momjian Exp $
|
||||
*
|
||||
* Copyright (c) 2001,2002 Tatsuo Ishii
|
||||
*
|
||||
@ -189,9 +189,9 @@ pgstattuple_real(Relation rel)
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare a values array for constructing the tuple. This should be an
|
||||
* array of C strings which will be processed later by the appropriate
|
||||
* "in" functions.
|
||||
* Prepare a values array for constructing the tuple. This should be
|
||||
* an array of C strings which will be processed later by the
|
||||
* appropriate "in" functions.
|
||||
*/
|
||||
values = (char **) palloc(NCOLUMNS * sizeof(char *));
|
||||
for (i = 0; i < NCOLUMNS; i++)
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/contrib/rtree_gist/rtree_gist.c,v 1.9 2004/03/30 15:45:33 teodor Exp $
|
||||
* $PostgreSQL: pgsql/contrib/rtree_gist/rtree_gist.c,v 1.10 2004/08/29 05:06:37 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -755,8 +755,8 @@ seg_cmp(SEG * a, SEG * b)
|
||||
* a->lower == b->lower, so consider type of boundary.
|
||||
*
|
||||
* A '-' lower bound is < any other kind (this could only be relevant if
|
||||
* -HUGE_VAL is used as a regular data value). A '<' lower bound is < any
|
||||
* other kind except '-'. A '>' lower bound is > any other kind.
|
||||
* -HUGE_VAL is used as a regular data value). A '<' lower bound is <
|
||||
* any other kind except '-'. A '>' lower bound is > any other kind.
|
||||
*/
|
||||
if (a->l_ext != b->l_ext)
|
||||
{
|
||||
@ -813,8 +813,8 @@ seg_cmp(SEG * a, SEG * b)
|
||||
* a->upper == b->upper, so consider type of boundary.
|
||||
*
|
||||
* A '-' upper bound is > any other kind (this could only be relevant if
|
||||
* HUGE_VAL is used as a regular data value). A '<' upper bound is < any
|
||||
* other kind. A '>' upper bound is > any other kind except '-'.
|
||||
* HUGE_VAL is used as a regular data value). A '<' upper bound is <
|
||||
* any other kind. A '>' upper bound is > any other kind except '-'.
|
||||
*/
|
||||
if (a->u_ext != b->u_ext)
|
||||
{
|
||||
|
@ -329,7 +329,8 @@ gtxtidx_union(PG_FUNCTION_ARGS)
|
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
||||
int *size = (int *) PG_GETARG_POINTER(1);
|
||||
BITVEC base;
|
||||
int4 i,len;
|
||||
int4 i,
|
||||
len;
|
||||
int4 flag = 0;
|
||||
GISTTYPE *result;
|
||||
|
||||
|
@ -241,10 +241,14 @@ pushval_morph(QPRS_STATE * state, int typeval, char *strval, int lenval)
|
||||
lemm = lemmatize(token, &lenlemm, type);
|
||||
if (lemm)
|
||||
{
|
||||
if ( lemm==token ) {
|
||||
char *ptrs=token,*ptrd;
|
||||
if (lemm == token)
|
||||
{
|
||||
char *ptrs = token,
|
||||
*ptrd;
|
||||
|
||||
ptrd = lemm = palloc(lenlemm + 1);
|
||||
while(ptrs-token<lenlemm) {
|
||||
while (ptrs - token < lenlemm)
|
||||
{
|
||||
*ptrd = tolower((unsigned char) *ptrs);
|
||||
ptrs++;
|
||||
ptrd++;
|
||||
|
@ -122,7 +122,8 @@ text_cmp(text *a, text *b)
|
||||
}
|
||||
|
||||
char *
|
||||
get_namespace(Oid funcoid) {
|
||||
get_namespace(Oid funcoid)
|
||||
{
|
||||
HeapTuple tuple;
|
||||
Form_pg_proc proc;
|
||||
Form_pg_namespace nsp;
|
||||
@ -147,7 +148,8 @@ get_namespace(Oid funcoid) {
|
||||
}
|
||||
|
||||
Oid
|
||||
get_oidnamespace(Oid funcoid) {
|
||||
get_oidnamespace(Oid funcoid)
|
||||
{
|
||||
HeapTuple tuple;
|
||||
Form_pg_proc proc;
|
||||
Oid nspoid;
|
||||
@ -161,4 +163,3 @@ get_oidnamespace(Oid funcoid) {
|
||||
|
||||
return nspoid;
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,8 @@ int text_cmp(text *a, text *b);
|
||||
|
||||
void ts_error(int state, const char *format,...);
|
||||
|
||||
extern Oid TSNSP_FunctionOid; /* oid of called function, needed only for determ namespace, no more */
|
||||
extern Oid TSNSP_FunctionOid; /* oid of called function, needed only for
|
||||
* determ namespace, no more */
|
||||
char *get_namespace(Oid funcoid);
|
||||
Oid get_oidnamespace(Oid funcoid);
|
||||
|
||||
|
@ -143,7 +143,8 @@ name2id_dict(text *name)
|
||||
int stat;
|
||||
Oid id = findSNMap_t(&(DList.name2id_map), name);
|
||||
void *plan;
|
||||
char buf[1024], *nsp;
|
||||
char buf[1024],
|
||||
*nsp;
|
||||
|
||||
arg[0] = TEXTOID;
|
||||
pars[0] = PointerGetDatum(name);
|
||||
@ -245,6 +246,7 @@ lexize_byname(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *dictname = PG_GETARG_TEXT_P(0);
|
||||
Datum res;
|
||||
|
||||
SET_FUNCOID();
|
||||
|
||||
res = DirectFunctionCall3(
|
||||
@ -279,6 +281,7 @@ Datum
|
||||
set_curdict_byname(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *dictname = PG_GETARG_TEXT_P(0);
|
||||
|
||||
SET_FUNCOID();
|
||||
DirectFunctionCall1(
|
||||
set_curdict,
|
||||
@ -294,6 +297,7 @@ Datum
|
||||
lexize_bycurrent(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum res;
|
||||
|
||||
SET_FUNCOID();
|
||||
if (currect_dictionary_id == 0)
|
||||
ereport(ERROR,
|
||||
|
@ -329,7 +329,8 @@ gtsvector_union(PG_FUNCTION_ARGS)
|
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
||||
int *size = (int *) PG_GETARG_POINTER(1);
|
||||
BITVEC base;
|
||||
int4 i,len;
|
||||
int4 i,
|
||||
len;
|
||||
int4 flag = 0;
|
||||
GISTTYPE *result;
|
||||
|
||||
@ -425,8 +426,10 @@ sizebitvec(BITVECP sign)
|
||||
}
|
||||
|
||||
static int
|
||||
hemdistsign(BITVECP a, BITVECP b) {
|
||||
int i,dist=0;
|
||||
hemdistsign(BITVECP a, BITVECP b)
|
||||
{
|
||||
int i,
|
||||
dist = 0;
|
||||
|
||||
LOOPBIT(
|
||||
if (GETBIT(a, i) != GETBIT(b, i))
|
||||
@ -436,13 +439,16 @@ hemdistsign(BITVECP a, BITVECP b) {
|
||||
}
|
||||
|
||||
static int
|
||||
hemdist(GISTTYPE *a, GISTTYPE *b) {
|
||||
if ( ISALLTRUE(a) ) {
|
||||
hemdist(GISTTYPE * a, GISTTYPE * b)
|
||||
{
|
||||
if (ISALLTRUE(a))
|
||||
{
|
||||
if (ISALLTRUE(b))
|
||||
return 0;
|
||||
else
|
||||
return SIGLENBIT - sizebitvec(GETSIGN(b));
|
||||
} else if (ISALLTRUE(b))
|
||||
}
|
||||
else if (ISALLTRUE(b))
|
||||
return SIGLENBIT - sizebitvec(GETSIGN(a));
|
||||
|
||||
return hemdistsign(GETSIGN(a), GETSIGN(b));
|
||||
@ -460,17 +466,19 @@ gtsvector_penalty(PG_FUNCTION_ARGS)
|
||||
|
||||
*penalty = 0.0;
|
||||
|
||||
if (ISARRKEY(newval)) {
|
||||
if (ISARRKEY(newval))
|
||||
{
|
||||
BITVEC sign;
|
||||
|
||||
makesign(sign, newval);
|
||||
|
||||
if (ISALLTRUE(origval))
|
||||
*penalty = ((float) (SIGLENBIT - sizebitvec(sign))) / (float) (SIGLENBIT + 1);
|
||||
else
|
||||
*penalty = hemdistsign(sign, orig);
|
||||
} else {
|
||||
*penalty=hemdist(origval,newval);
|
||||
}
|
||||
else
|
||||
*penalty = hemdist(origval, newval);
|
||||
PG_RETURN_POINTER(penalty);
|
||||
}
|
||||
|
||||
@ -510,13 +518,16 @@ comparecost(const void *a, const void *b)
|
||||
|
||||
|
||||
static int
|
||||
hemdistcache(CACHESIGN *a, CACHESIGN *b) {
|
||||
if ( a->allistrue ) {
|
||||
hemdistcache(CACHESIGN * a, CACHESIGN * b)
|
||||
{
|
||||
if (a->allistrue)
|
||||
{
|
||||
if (b->allistrue)
|
||||
return 0;
|
||||
else
|
||||
return SIGLENBIT - sizebitvec(b->sign);
|
||||
} else if (b->allistrue)
|
||||
}
|
||||
else if (b->allistrue)
|
||||
return SIGLENBIT - sizebitvec(a->sign);
|
||||
|
||||
return hemdistsign(a->sign, b->sign);
|
||||
@ -556,13 +567,16 @@ gtsvector_picksplit(PG_FUNCTION_ARGS)
|
||||
cache = (CACHESIGN *) palloc(sizeof(CACHESIGN) * (maxoff + 2));
|
||||
fillcache(&cache[FirstOffsetNumber], GETENTRY(entryvec, FirstOffsetNumber));
|
||||
|
||||
for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k)) {
|
||||
for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j)) {
|
||||
for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k))
|
||||
{
|
||||
for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j))
|
||||
{
|
||||
if (k == FirstOffsetNumber)
|
||||
fillcache(&cache[j], GETENTRY(entryvec, j));
|
||||
|
||||
size_waste = hemdistcache(&(cache[j]), &(cache[k]));
|
||||
if (size_waste > waste) {
|
||||
if (size_waste > waste)
|
||||
{
|
||||
waste = size_waste;
|
||||
seed_1 = k;
|
||||
seed_2 = j;
|
||||
@ -575,27 +589,34 @@ gtsvector_picksplit(PG_FUNCTION_ARGS)
|
||||
right = v->spl_right;
|
||||
v->spl_nright = 0;
|
||||
|
||||
if (seed_1 == 0 || seed_2 == 0) {
|
||||
if (seed_1 == 0 || seed_2 == 0)
|
||||
{
|
||||
seed_1 = 1;
|
||||
seed_2 = 2;
|
||||
}
|
||||
|
||||
/* form initial .. */
|
||||
if (cache[seed_1].allistrue) {
|
||||
if (cache[seed_1].allistrue)
|
||||
{
|
||||
datum_l = (GISTTYPE *) palloc(CALCGTSIZE(SIGNKEY | ALLISTRUE, 0));
|
||||
datum_l->len = CALCGTSIZE(SIGNKEY | ALLISTRUE, 0);
|
||||
datum_l->flag = SIGNKEY | ALLISTRUE;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
datum_l = (GISTTYPE *) palloc(CALCGTSIZE(SIGNKEY, 0));
|
||||
datum_l->len = CALCGTSIZE(SIGNKEY, 0);
|
||||
datum_l->flag = SIGNKEY;
|
||||
memcpy((void *) GETSIGN(datum_l), (void *) cache[seed_1].sign, sizeof(BITVEC));
|
||||
}
|
||||
if (cache[seed_2].allistrue) {
|
||||
if (cache[seed_2].allistrue)
|
||||
{
|
||||
datum_r = (GISTTYPE *) palloc(CALCGTSIZE(SIGNKEY | ALLISTRUE, 0));
|
||||
datum_r->len = CALCGTSIZE(SIGNKEY | ALLISTRUE, 0);
|
||||
datum_r->flag = SIGNKEY | ALLISTRUE;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
datum_r = (GISTTYPE *) palloc(CALCGTSIZE(SIGNKEY, 0));
|
||||
datum_r->len = CALCGTSIZE(SIGNKEY, 0);
|
||||
datum_r->flag = SIGNKEY;
|
||||
@ -608,7 +629,8 @@ gtsvector_picksplit(PG_FUNCTION_ARGS)
|
||||
fillcache(&cache[maxoff], GETENTRY(entryvec, maxoff));
|
||||
/* sort before ... */
|
||||
costvector = (SPLITCOST *) palloc(sizeof(SPLITCOST) * maxoff);
|
||||
for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j)) {
|
||||
for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j))
|
||||
{
|
||||
costvector[j - 1].pos = j;
|
||||
size_alpha = hemdistcache(&(cache[seed_1]), &(cache[j]));
|
||||
size_beta = hemdistcache(&(cache[seed_2]), &(cache[j]));
|
||||
@ -616,45 +638,55 @@ gtsvector_picksplit(PG_FUNCTION_ARGS)
|
||||
}
|
||||
qsort((void *) costvector, maxoff, sizeof(SPLITCOST), comparecost);
|
||||
|
||||
for (k = 0; k < maxoff; k++) {
|
||||
for (k = 0; k < maxoff; k++)
|
||||
{
|
||||
j = costvector[k].pos;
|
||||
if (j == seed_1) {
|
||||
if (j == seed_1)
|
||||
{
|
||||
*left++ = j;
|
||||
v->spl_nleft++;
|
||||
continue;
|
||||
} else if (j == seed_2) {
|
||||
}
|
||||
else if (j == seed_2)
|
||||
{
|
||||
*right++ = j;
|
||||
v->spl_nright++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ISALLTRUE(datum_l) || cache[j].allistrue) {
|
||||
if (ISALLTRUE(datum_l) || cache[j].allistrue)
|
||||
{
|
||||
if (ISALLTRUE(datum_l) && cache[j].allistrue)
|
||||
size_alpha = 0;
|
||||
else
|
||||
size_alpha = SIGLENBIT - sizebitvec(
|
||||
(cache[j].allistrue) ? GETSIGN(datum_l) : GETSIGN(cache[j].sign)
|
||||
);
|
||||
} else {
|
||||
size_alpha=hemdistsign(cache[j].sign,GETSIGN(datum_l));
|
||||
}
|
||||
else
|
||||
size_alpha = hemdistsign(cache[j].sign, GETSIGN(datum_l));
|
||||
|
||||
if (ISALLTRUE(datum_r) || cache[j].allistrue) {
|
||||
if (ISALLTRUE(datum_r) || cache[j].allistrue)
|
||||
{
|
||||
if (ISALLTRUE(datum_r) && cache[j].allistrue)
|
||||
size_beta = 0;
|
||||
else
|
||||
size_beta = SIGLENBIT - sizebitvec(
|
||||
(cache[j].allistrue) ? GETSIGN(datum_r) : GETSIGN(cache[j].sign)
|
||||
);
|
||||
} else {
|
||||
size_beta=hemdistsign(cache[j].sign,GETSIGN(datum_r));
|
||||
}
|
||||
else
|
||||
size_beta = hemdistsign(cache[j].sign, GETSIGN(datum_r));
|
||||
|
||||
if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.1)) {
|
||||
if (ISALLTRUE(datum_l) || cache[j].allistrue) {
|
||||
if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.1))
|
||||
{
|
||||
if (ISALLTRUE(datum_l) || cache[j].allistrue)
|
||||
{
|
||||
if (!ISALLTRUE(datum_l))
|
||||
MemSet((void *) GETSIGN(datum_l), 0xff, sizeof(BITVEC));
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = cache[j].sign;
|
||||
LOOPBYTE(
|
||||
union_l[i] |= ptr[i];
|
||||
@ -662,11 +694,16 @@ gtsvector_picksplit(PG_FUNCTION_ARGS)
|
||||
}
|
||||
*left++ = j;
|
||||
v->spl_nleft++;
|
||||
} else {
|
||||
if (ISALLTRUE(datum_r) || cache[j].allistrue) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ISALLTRUE(datum_r) || cache[j].allistrue)
|
||||
{
|
||||
if (!ISALLTRUE(datum_r))
|
||||
MemSet((void *) GETSIGN(datum_r), 0xff, sizeof(BITVEC));
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = cache[j].sign;
|
||||
LOOPBYTE(
|
||||
union_r[i] |= ptr[i];
|
||||
|
@ -7,7 +7,8 @@
|
||||
#include "common.h"
|
||||
|
||||
int
|
||||
RS_isRegis(const char *str) {
|
||||
RS_isRegis(const char *str)
|
||||
{
|
||||
unsigned char *ptr = (unsigned char *) str;
|
||||
|
||||
while (ptr && *ptr)
|
||||
@ -24,8 +25,10 @@ RS_isRegis(const char *str) {
|
||||
#define RS_IN_WAIT 4
|
||||
|
||||
static RegisNode *
|
||||
newRegisNode(RegisNode *prev, int len) {
|
||||
newRegisNode(RegisNode * prev, int len)
|
||||
{
|
||||
RegisNode *ptr;
|
||||
|
||||
ptr = (RegisNode *) malloc(RNHDRSZ + len + 1);
|
||||
if (!ptr)
|
||||
ts_error(ERROR, "No memory");
|
||||
@ -36,18 +39,24 @@ newRegisNode(RegisNode *prev, int len) {
|
||||
}
|
||||
|
||||
int
|
||||
RS_compile(Regis *r, int issuffix, const char *str) {
|
||||
int i,len = strlen(str);
|
||||
RS_compile(Regis * r, int issuffix, const char *str)
|
||||
{
|
||||
int i,
|
||||
len = strlen(str);
|
||||
int state = RS_IN_WAIT;
|
||||
RegisNode *ptr = NULL;
|
||||
|
||||
memset(r, 0, sizeof(Regis));
|
||||
r->issuffix = (issuffix) ? 1 : 0;
|
||||
|
||||
for(i=0;i<len;i++) {
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
unsigned char c = *(((unsigned char *) str) + i);
|
||||
if ( state == RS_IN_WAIT ) {
|
||||
if ( isalpha(c) ) {
|
||||
|
||||
if (state == RS_IN_WAIT)
|
||||
{
|
||||
if (isalpha(c))
|
||||
{
|
||||
if (ptr)
|
||||
ptr = newRegisNode(ptr, len);
|
||||
else
|
||||
@ -55,39 +64,54 @@ RS_compile(Regis *r, int issuffix, const char *str) {
|
||||
ptr->data[0] = c;
|
||||
ptr->type = RSF_ONEOF;
|
||||
ptr->len = 1;
|
||||
} else if ( c=='[' ) {
|
||||
}
|
||||
else if (c == '[')
|
||||
{
|
||||
if (ptr)
|
||||
ptr = newRegisNode(ptr, len);
|
||||
else
|
||||
ptr = r->node = newRegisNode(NULL, len);
|
||||
ptr->type = RSF_ONEOF;
|
||||
state = RS_IN_ONEOF;
|
||||
} else
|
||||
}
|
||||
else
|
||||
ts_error(ERROR, "Error in regis: %s at pos %d\n", str, i + 1);
|
||||
} else if ( state == RS_IN_ONEOF ) {
|
||||
if ( c=='^' ) {
|
||||
}
|
||||
else if (state == RS_IN_ONEOF)
|
||||
{
|
||||
if (c == '^')
|
||||
{
|
||||
ptr->type = RSF_NONEOF;
|
||||
state = RS_IN_NONEOF;
|
||||
} else if ( isalpha(c) ) {
|
||||
}
|
||||
else if (isalpha(c))
|
||||
{
|
||||
ptr->data[0] = c;
|
||||
ptr->len = 1;
|
||||
state = RS_IN_ONEOF_IN;
|
||||
} else
|
||||
}
|
||||
else
|
||||
ts_error(ERROR, "Error in regis: %s at pos %d\n", str, i + 1);
|
||||
} else if ( state == RS_IN_ONEOF_IN || state == RS_IN_NONEOF ) {
|
||||
if ( isalpha(c) ) {
|
||||
}
|
||||
else if (state == RS_IN_ONEOF_IN || state == RS_IN_NONEOF)
|
||||
{
|
||||
if (isalpha(c))
|
||||
{
|
||||
ptr->data[ptr->len] = c;
|
||||
ptr->len++;
|
||||
} else if ( c==']' ) {
|
||||
}
|
||||
else if (c == ']')
|
||||
state = RS_IN_WAIT;
|
||||
} else
|
||||
else
|
||||
ts_error(ERROR, "Error in regis: %s at pos %d\n", str, i + 1);
|
||||
} else
|
||||
}
|
||||
else
|
||||
ts_error(ERROR, "Internal error in RS_compile: %d\n", state);
|
||||
}
|
||||
|
||||
ptr = r->node;
|
||||
while(ptr) {
|
||||
while (ptr)
|
||||
{
|
||||
r->nchar++;
|
||||
ptr = ptr->next;
|
||||
}
|
||||
@ -96,10 +120,13 @@ RS_compile(Regis *r, int issuffix, const char *str) {
|
||||
}
|
||||
|
||||
void
|
||||
RS_free(Regis *r) {
|
||||
RegisNode *ptr=r->node,*tmp;
|
||||
RS_free(Regis * r)
|
||||
{
|
||||
RegisNode *ptr = r->node,
|
||||
*tmp;
|
||||
|
||||
while(ptr) {
|
||||
while (ptr)
|
||||
{
|
||||
tmp = ptr->next;
|
||||
free(ptr);
|
||||
ptr = tmp;
|
||||
@ -109,7 +136,8 @@ RS_free(Regis *r) {
|
||||
}
|
||||
|
||||
int
|
||||
RS_execute(Regis *r, const char *str, int len) {
|
||||
RS_execute(Regis * r, const char *str, int len)
|
||||
{
|
||||
RegisNode *ptr = r->node;
|
||||
unsigned char *c;
|
||||
|
||||
@ -124,20 +152,26 @@ RS_execute(Regis *r, const char *str, int len) {
|
||||
else
|
||||
c = (unsigned char *) str;
|
||||
|
||||
while(ptr) {
|
||||
switch(ptr->type) {
|
||||
while (ptr)
|
||||
{
|
||||
switch (ptr->type)
|
||||
{
|
||||
case RSF_ONEOF:
|
||||
if ( ptr->len==0 ) {
|
||||
if (ptr->len == 0)
|
||||
{
|
||||
if (*c != *(ptr->data))
|
||||
return 0;
|
||||
} else if ( strchr((char*)ptr->data, *c) == NULL )
|
||||
}
|
||||
else if (strchr((char *) ptr->data, *c) == NULL)
|
||||
return 0;
|
||||
break;
|
||||
case RSF_NONEOF:
|
||||
if ( ptr->len==0 ) {
|
||||
if (ptr->len == 0)
|
||||
{
|
||||
if (*c == *(ptr->data))
|
||||
return 0;
|
||||
} else if ( strchr((char*)ptr->data, *c) != NULL )
|
||||
}
|
||||
else if (strchr((char *) ptr->data, *c) != NULL)
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
|
@ -3,7 +3,8 @@
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
typedef struct RegisNode {
|
||||
typedef struct RegisNode
|
||||
{
|
||||
uint32
|
||||
type:2,
|
||||
len:16,
|
||||
@ -17,7 +18,8 @@ typedef struct RegisNode {
|
||||
#define RSF_ONEOF 1
|
||||
#define RSF_NONEOF 2
|
||||
|
||||
typedef struct Regis {
|
||||
typedef struct Regis
|
||||
{
|
||||
RegisNode *node;
|
||||
uint32
|
||||
issuffix:1,
|
||||
@ -29,6 +31,8 @@ int RS_isRegis(const char *str);
|
||||
|
||||
int RS_compile(Regis * r, int issuffix, const char *str);
|
||||
void RS_free(Regis * r);
|
||||
|
||||
/*×ÏÚ×ÒÁÝÁÅÔ 1 ÅÓÌÉ ÍÁÔÞÉÔÓÑ */
|
||||
int RS_execute(Regis * r, const char *str, int len);
|
||||
|
||||
#endif
|
||||
|
@ -41,12 +41,15 @@ strlower(char *str)
|
||||
}
|
||||
|
||||
static char *
|
||||
strnduplicate(char *s, int len) {
|
||||
strnduplicate(char *s, int len)
|
||||
{
|
||||
char *d = (char *) palloc(len + 1);
|
||||
|
||||
memcpy(d, s, len);
|
||||
d[len] = '\0';
|
||||
return d;
|
||||
}
|
||||
|
||||
/* backward string compaire for suffix tree operations */
|
||||
static int
|
||||
strbcmp(const unsigned char *s1, const unsigned char *s2)
|
||||
@ -189,16 +192,22 @@ static int
|
||||
FindWord(IspellDict * Conf, const char *word, int affixflag, char compoundonly)
|
||||
{
|
||||
SPNode *node = Conf->Dictionary;
|
||||
SPNodeData *StopLow, *StopHigh, *StopMiddle;
|
||||
SPNodeData *StopLow,
|
||||
*StopHigh,
|
||||
*StopMiddle;
|
||||
uint8 *ptr = (uint8 *) word;
|
||||
|
||||
while( node && *ptr) {
|
||||
while (node && *ptr)
|
||||
{
|
||||
StopLow = node->data;
|
||||
StopHigh = node->data + node->length;
|
||||
while (StopLow < StopHigh) {
|
||||
while (StopLow < StopHigh)
|
||||
{
|
||||
StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
|
||||
if ( StopMiddle->val == *ptr ) {
|
||||
if ( *(ptr+1)=='\0' && StopMiddle->isword ) {
|
||||
if (StopMiddle->val == *ptr)
|
||||
{
|
||||
if (*(ptr + 1) == '\0' && StopMiddle->isword)
|
||||
{
|
||||
if (compoundonly && !StopMiddle->compoundallow)
|
||||
return 0;
|
||||
if ((affixflag == 0) || (strchr(Conf->AffixData[StopMiddle->affix], affixflag) != NULL))
|
||||
@ -207,11 +216,11 @@ FindWord(IspellDict * Conf, const char *word, int affixflag, char compoundonly)
|
||||
node = StopMiddle->node;
|
||||
ptr++;
|
||||
break;
|
||||
} else if ( StopMiddle->val < *ptr ) {
|
||||
StopLow = StopMiddle + 1;
|
||||
} else {
|
||||
StopHigh = StopMiddle;
|
||||
}
|
||||
else if (StopMiddle->val < *ptr)
|
||||
StopLow = StopMiddle + 1;
|
||||
else
|
||||
StopHigh = StopMiddle;
|
||||
}
|
||||
if (StopLow >= StopHigh)
|
||||
break;
|
||||
@ -237,15 +246,20 @@ NIAddAffix(IspellDict * Conf, int flag, char flagflags, const char *mask, const
|
||||
MEMOUT(Conf->Affix);
|
||||
}
|
||||
|
||||
if ( strcmp(mask,".")==0 ) {
|
||||
if (strcmp(mask, ".") == 0)
|
||||
{
|
||||
Conf->Affix[Conf->naffixes].issimple = 1;
|
||||
Conf->Affix[Conf->naffixes].isregis = 0;
|
||||
*(Conf->Affix[Conf->naffixes].mask) = '\0';
|
||||
} else if ( RS_isRegis(mask) ) {
|
||||
}
|
||||
else if (RS_isRegis(mask))
|
||||
{
|
||||
Conf->Affix[Conf->naffixes].issimple = 0;
|
||||
Conf->Affix[Conf->naffixes].isregis = 1;
|
||||
strcpy(Conf->Affix[Conf->naffixes].mask, mask);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Conf->Affix[Conf->naffixes].issimple = 0;
|
||||
Conf->Affix[Conf->naffixes].isregis = 0;
|
||||
if (type == FF_SUFFIX)
|
||||
@ -308,11 +322,15 @@ NIImportAffixes(IspellDict * Conf, const char *filename)
|
||||
|
||||
while (fgets(str, sizeof(str), affix))
|
||||
{
|
||||
if (STRNCASECMP(str, "compoundwords")==0) {
|
||||
if (STRNCASECMP(str, "compoundwords") == 0)
|
||||
{
|
||||
s = strchr(str, 'l');
|
||||
if ( s ) {
|
||||
while( *s!=' ' ) s++;
|
||||
while( *s==' ' ) s++;
|
||||
if (s)
|
||||
{
|
||||
while (*s != ' ')
|
||||
s++;
|
||||
while (*s == ' ')
|
||||
s++;
|
||||
Conf->compoundcontrol = *s;
|
||||
continue;
|
||||
}
|
||||
@ -333,16 +351,21 @@ NIImportAffixes(IspellDict * Conf, const char *filename)
|
||||
{
|
||||
s = str + 5;
|
||||
flagflags = 0;
|
||||
while( *s==' ' ) s++;
|
||||
if ( *s=='*' ) {
|
||||
while (*s == ' ')
|
||||
s++;
|
||||
if (*s == '*')
|
||||
{
|
||||
flagflags |= FF_CROSSPRODUCT;
|
||||
s++;
|
||||
} else if ( *s=='~' ) {
|
||||
}
|
||||
else if (*s == '~')
|
||||
{
|
||||
flagflags |= FF_COMPOUNDONLYAFX;
|
||||
s++;
|
||||
}
|
||||
|
||||
if ( *s=='\\' ) s++;
|
||||
if (*s == '\\')
|
||||
s++;
|
||||
|
||||
flag = *s;
|
||||
continue;
|
||||
@ -388,11 +411,13 @@ NIImportAffixes(IspellDict * Conf, const char *filename)
|
||||
}
|
||||
|
||||
static int
|
||||
MergeAffix(IspellDict *Conf, int a1, int a2) {
|
||||
MergeAffix(IspellDict * Conf, int a1, int a2)
|
||||
{
|
||||
int naffix = 0;
|
||||
char **ptr = Conf->AffixData;
|
||||
|
||||
while(*ptr) {
|
||||
while (*ptr)
|
||||
{
|
||||
naffix++;
|
||||
ptr++;
|
||||
}
|
||||
@ -410,7 +435,8 @@ MergeAffix(IspellDict *Conf, int a1, int a2) {
|
||||
|
||||
|
||||
static SPNode *
|
||||
mkSPNode(IspellDict *Conf, int low, int high, int level) {
|
||||
mkSPNode(IspellDict * Conf, int low, int high, int level)
|
||||
{
|
||||
int i;
|
||||
int nchar = 0;
|
||||
char lastchar = '\0';
|
||||
@ -419,7 +445,8 @@ mkSPNode(IspellDict *Conf, int low, int high, int level) {
|
||||
int lownew = low;
|
||||
|
||||
for (i = low; i < high; i++)
|
||||
if ( Conf->Spell[i].p.d.len>level && lastchar!=Conf->Spell[i].word[level] ) {
|
||||
if (Conf->Spell[i].p.d.len > level && lastchar != Conf->Spell[i].word[level])
|
||||
{
|
||||
nchar++;
|
||||
lastchar = Conf->Spell[i].word[level];
|
||||
}
|
||||
@ -435,9 +462,12 @@ mkSPNode(IspellDict *Conf, int low, int high, int level) {
|
||||
|
||||
lastchar = '\0';
|
||||
for (i = low; i < high; i++)
|
||||
if ( Conf->Spell[i].p.d.len>level ) {
|
||||
if ( lastchar!=Conf->Spell[i].word[level] ) {
|
||||
if ( lastchar ) {
|
||||
if (Conf->Spell[i].p.d.len > level)
|
||||
{
|
||||
if (lastchar != Conf->Spell[i].word[level])
|
||||
{
|
||||
if (lastchar)
|
||||
{
|
||||
data->node = mkSPNode(Conf, lownew, i, level + 1);
|
||||
lownew = i;
|
||||
data++;
|
||||
@ -445,18 +475,20 @@ mkSPNode(IspellDict *Conf, int low, int high, int level) {
|
||||
lastchar = Conf->Spell[i].word[level];
|
||||
}
|
||||
data->val = ((uint8 *) (Conf->Spell[i].word))[level];
|
||||
if ( Conf->Spell[i].p.d.len == level+1 ) {
|
||||
if ( data->isword && data->affix!=Conf->Spell[i].p.d.affix) {
|
||||
if (Conf->Spell[i].p.d.len == level + 1)
|
||||
{
|
||||
if (data->isword && data->affix != Conf->Spell[i].p.d.affix)
|
||||
{
|
||||
/*
|
||||
fprintf(stderr,"Word already exists: %s (affixes: '%s' and '%s')\n",
|
||||
Conf->Spell[i].word,
|
||||
Conf->AffixData[data->affix],
|
||||
Conf->AffixData[Conf->Spell[i].p.d.affix]
|
||||
);
|
||||
* fprintf(stderr,"Word already exists: %s (affixes:
|
||||
* '%s' and '%s')\n", Conf->Spell[i].word,
|
||||
* Conf->AffixData[data->affix],
|
||||
* Conf->AffixData[Conf->Spell[i].p.d.affix] );
|
||||
*/
|
||||
/* MergeAffix called a few times */
|
||||
data->affix = MergeAffix(Conf, data->affix, Conf->Spell[i].p.d.affix);
|
||||
} else
|
||||
}
|
||||
else
|
||||
data->affix = Conf->Spell[i].p.d.affix;
|
||||
data->isword = 1;
|
||||
if (strchr(Conf->AffixData[data->affix], Conf->compoundcontrol))
|
||||
@ -493,8 +525,10 @@ NISortDictionary(IspellDict * Conf)
|
||||
MEMOUT(Conf->AffixData[1]);
|
||||
Conf->Spell[0].p.d.affix = 1;
|
||||
Conf->Spell[0].p.d.len = strlen(Conf->Spell[0].word);
|
||||
for (i = 1; i < Conf->nspell; i++) {
|
||||
if ( strcmp(Conf->Spell[i].p.flag, Conf->AffixData[naffix]) ) {
|
||||
for (i = 1; i < Conf->nspell; i++)
|
||||
{
|
||||
if (strcmp(Conf->Spell[i].p.flag, Conf->AffixData[naffix]))
|
||||
{
|
||||
naffix++;
|
||||
Conf->AffixData[naffix] = strdup(Conf->Spell[i].p.flag);
|
||||
MEMOUT(Conf->AffixData[naffix]);
|
||||
@ -513,7 +547,8 @@ NISortDictionary(IspellDict * Conf)
|
||||
}
|
||||
|
||||
static AffixNode *
|
||||
mkANode(IspellDict *Conf, int low, int high, int level, int type) {
|
||||
mkANode(IspellDict * Conf, int low, int high, int level, int type)
|
||||
{
|
||||
int i;
|
||||
int nchar = 0;
|
||||
uint8 lastchar = '\0';
|
||||
@ -522,7 +557,8 @@ mkANode(IspellDict *Conf, int low, int high, int level, int type) {
|
||||
int lownew = low;
|
||||
|
||||
for (i = low; i < high; i++)
|
||||
if ( Conf->Affix[i].replen>level && lastchar!=GETCHAR( Conf->Affix + i, level, type ) ) {
|
||||
if (Conf->Affix[i].replen > level && lastchar != GETCHAR(Conf->Affix + i, level, type))
|
||||
{
|
||||
nchar++;
|
||||
lastchar = GETCHAR(Conf->Affix + i, level, type);
|
||||
}
|
||||
@ -538,9 +574,12 @@ mkANode(IspellDict *Conf, int low, int high, int level, int type) {
|
||||
|
||||
lastchar = '\0';
|
||||
for (i = low; i < high; i++)
|
||||
if ( Conf->Affix[i].replen>level ) {
|
||||
if ( lastchar!=GETCHAR( Conf->Affix + i, level, type ) ) {
|
||||
if ( lastchar ) {
|
||||
if (Conf->Affix[i].replen > level)
|
||||
{
|
||||
if (lastchar != GETCHAR(Conf->Affix + i, level, type))
|
||||
{
|
||||
if (lastchar)
|
||||
{
|
||||
data->node = mkANode(Conf, lownew, i, level + 1, type);
|
||||
lownew = i;
|
||||
data++;
|
||||
@ -548,8 +587,10 @@ mkANode(IspellDict *Conf, int low, int high, int level, int type) {
|
||||
lastchar = GETCHAR(Conf->Affix + i, level, type);
|
||||
}
|
||||
data->val = GETCHAR(Conf->Affix + i, level, type);
|
||||
if ( Conf->Affix[i].replen == level+1 ) { /* affix stopped */
|
||||
if ( !data->naff ) {
|
||||
if (Conf->Affix[i].replen == level + 1)
|
||||
{ /* affix stopped */
|
||||
if (!data->naff)
|
||||
{
|
||||
data->aff = (AFFIX **) malloc(sizeof(AFFIX *) * (high - i + 1));
|
||||
MEMOUT(data->aff);
|
||||
}
|
||||
@ -564,8 +605,10 @@ mkANode(IspellDict *Conf, int low, int high, int level, int type) {
|
||||
}
|
||||
|
||||
static void
|
||||
mkVoidAffix(IspellDict * Conf, int issuffix, int startsuffix) {
|
||||
int i,cnt=0;
|
||||
mkVoidAffix(IspellDict * Conf, int issuffix, int startsuffix)
|
||||
{
|
||||
int i,
|
||||
cnt = 0;
|
||||
int start = (issuffix) ? startsuffix : 0;
|
||||
int end = (issuffix) ? Conf->naffixes : startsuffix;
|
||||
AffixNode *Affix = (AffixNode *) malloc(ANHRDSZ + sizeof(AffixNodeData));
|
||||
@ -575,10 +618,13 @@ mkVoidAffix(IspellDict * Conf, int issuffix, int startsuffix) {
|
||||
Affix->length = 1;
|
||||
Affix->isvoid = 1;
|
||||
|
||||
if (issuffix) {
|
||||
if (issuffix)
|
||||
{
|
||||
Affix->data->node = Conf->Suffix;
|
||||
Conf->Suffix = Affix;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Affix->data->node = Conf->Prefix;
|
||||
Conf->Prefix = Affix;
|
||||
}
|
||||
@ -597,7 +643,8 @@ mkVoidAffix(IspellDict * Conf, int issuffix, int startsuffix) {
|
||||
|
||||
cnt = 0;
|
||||
for (i = start; i < end; i++)
|
||||
if (Conf->Affix[i].replen==0) {
|
||||
if (Conf->Affix[i].replen == 0)
|
||||
{
|
||||
Affix->data->aff[cnt] = Conf->Affix + i;
|
||||
cnt++;
|
||||
}
|
||||
@ -618,12 +665,17 @@ NISortAffixes(IspellDict * Conf)
|
||||
MEMOUT(Conf->CompoundAffix);
|
||||
ptr->affix = NULL;
|
||||
|
||||
for (i = 0; i < Conf->naffixes; i++) {
|
||||
for (i = 0; i < Conf->naffixes; i++)
|
||||
{
|
||||
Affix = &(((AFFIX *) Conf->Affix)[i]);
|
||||
if ( Affix->type == FF_SUFFIX ) {
|
||||
if ( firstsuffix<0 ) firstsuffix=i;
|
||||
if ( Affix->flagflags & FF_COMPOUNDONLYAFX ) {
|
||||
if ( !ptr->affix || strbncmp((ptr-1)->affix, Affix->repl, (ptr-1)->len) ) {
|
||||
if (Affix->type == FF_SUFFIX)
|
||||
{
|
||||
if (firstsuffix < 0)
|
||||
firstsuffix = i;
|
||||
if (Affix->flagflags & FF_COMPOUNDONLYAFX)
|
||||
{
|
||||
if (!ptr->affix || strbncmp((ptr - 1)->affix, Affix->repl, (ptr - 1)->len))
|
||||
{
|
||||
/* leave only unique and minimals suffixes */
|
||||
ptr->affix = Affix->repl;
|
||||
ptr->len = Affix->replen;
|
||||
@ -642,33 +694,40 @@ NISortAffixes(IspellDict * Conf)
|
||||
}
|
||||
|
||||
static AffixNodeData *
|
||||
FinfAffixes(AffixNode *node, const char *word, int wrdlen, int *level, int type) {
|
||||
AffixNodeData *StopLow, *StopHigh, *StopMiddle;
|
||||
FinfAffixes(AffixNode * node, const char *word, int wrdlen, int *level, int type)
|
||||
{
|
||||
AffixNodeData *StopLow,
|
||||
*StopHigh,
|
||||
*StopMiddle;
|
||||
uint8 symbol;
|
||||
|
||||
if ( node->isvoid ) { /* search void affixes */
|
||||
if (node->isvoid)
|
||||
{ /* search void affixes */
|
||||
if (node->data->naff)
|
||||
return node->data;
|
||||
node = node->data->node;
|
||||
}
|
||||
|
||||
while( node && *level<wrdlen) {
|
||||
while (node && *level < wrdlen)
|
||||
{
|
||||
StopLow = node->data;
|
||||
StopHigh = node->data + node->length;
|
||||
while (StopLow < StopHigh) {
|
||||
while (StopLow < StopHigh)
|
||||
{
|
||||
StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
|
||||
symbol = GETWCHAR(word, wrdlen, *level, type);
|
||||
if ( StopMiddle->val == symbol ) {
|
||||
if (StopMiddle->val == symbol)
|
||||
{
|
||||
(*level)++;
|
||||
if (StopMiddle->naff)
|
||||
return StopMiddle;
|
||||
node = StopMiddle->node;
|
||||
break;
|
||||
} else if ( StopMiddle->val < symbol ) {
|
||||
StopLow = StopMiddle + 1;
|
||||
} else {
|
||||
StopHigh = StopMiddle;
|
||||
}
|
||||
else if (StopMiddle->val < symbol)
|
||||
StopLow = StopMiddle + 1;
|
||||
else
|
||||
StopHigh = StopMiddle;
|
||||
}
|
||||
if (StopLow >= StopHigh)
|
||||
break;
|
||||
@ -677,43 +736,57 @@ FinfAffixes(AffixNode *node, const char *word, int wrdlen, int *level, int type)
|
||||
}
|
||||
|
||||
static char *
|
||||
CheckAffix(const char *word, size_t len, AFFIX * Affix, char flagflags, char *newword) {
|
||||
CheckAffix(const char *word, size_t len, AFFIX * Affix, char flagflags, char *newword)
|
||||
{
|
||||
|
||||
if ( flagflags & FF_COMPOUNDONLYAFX ) {
|
||||
if (flagflags & FF_COMPOUNDONLYAFX)
|
||||
{
|
||||
if ((Affix->flagflags & FF_COMPOUNDONLYAFX) == 0)
|
||||
return NULL;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Affix->flagflags & FF_COMPOUNDONLYAFX)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( Affix->type==FF_SUFFIX ) {
|
||||
if (Affix->type == FF_SUFFIX)
|
||||
{
|
||||
strcpy(newword, word);
|
||||
strcpy(newword + len - Affix->replen, Affix->find);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(newword, Affix->find);
|
||||
strcat(newword, word + Affix->replen);
|
||||
}
|
||||
|
||||
if ( Affix->issimple ) {
|
||||
if (Affix->issimple)
|
||||
return newword;
|
||||
} else if ( Affix->isregis ) {
|
||||
if (Affix->compile) {
|
||||
else if (Affix->isregis)
|
||||
{
|
||||
if (Affix->compile)
|
||||
{
|
||||
RS_compile(&(Affix->reg.regis), (Affix->type == FF_SUFFIX) ? 1 : 0, Affix->mask);
|
||||
Affix->compile = 0;
|
||||
}
|
||||
if (RS_execute(&(Affix->reg.regis), newword, -1))
|
||||
return newword;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
regmatch_t subs[2]; /* workaround for apache&linux */
|
||||
int err;
|
||||
pg_wchar *data;
|
||||
size_t data_len;
|
||||
int dat_len;
|
||||
|
||||
if (Affix->compile)
|
||||
{
|
||||
int wmasklen,masklen = strlen(Affix->mask);
|
||||
int wmasklen,
|
||||
masklen = strlen(Affix->mask);
|
||||
pg_wchar *mask;
|
||||
|
||||
mask = (pg_wchar *) palloc((masklen + 1) * sizeof(pg_wchar));
|
||||
wmasklen = pg_mb2wchar_with_len(Affix->mask, mask, masklen);
|
||||
|
||||
@ -721,7 +794,10 @@ CheckAffix(const char *word, size_t len, AFFIX * Affix, char flagflags, char *ne
|
||||
pfree(mask);
|
||||
if (err)
|
||||
{
|
||||
/* regerror(err, &(Affix->reg.regex), regerrstr, ERRSTRSIZE); */
|
||||
/*
|
||||
* regerror(err, &(Affix->reg.regex), regerrstr,
|
||||
* ERRSTRSIZE);
|
||||
*/
|
||||
pg_regfree(&(Affix->reg.regex));
|
||||
return (NULL);
|
||||
}
|
||||
@ -733,7 +809,8 @@ CheckAffix(const char *word, size_t len, AFFIX * Affix, char flagflags, char *ne
|
||||
data = (pg_wchar *) palloc((dat_len + 1) * sizeof(pg_wchar));
|
||||
data_len = pg_mb2wchar_with_len(newword, data, dat_len);
|
||||
|
||||
if (!(err = pg_regexec(&(Affix->reg.regex), data,dat_len,NULL, 1, subs, 0))) {
|
||||
if (!(err = pg_regexec(&(Affix->reg.regex), data, dat_len, NULL, 1, subs, 0)))
|
||||
{
|
||||
pfree(data);
|
||||
return newword;
|
||||
}
|
||||
@ -745,25 +822,33 @@ CheckAffix(const char *word, size_t len, AFFIX * Affix, char flagflags, char *ne
|
||||
|
||||
|
||||
static char **
|
||||
NormalizeSubWord(IspellDict * Conf, char *word, char flag) {
|
||||
AffixNodeData *suffix=NULL, *prefix=NULL;
|
||||
int slevel=0, plevel=0;
|
||||
int wrdlen = strlen(word), swrdlen;
|
||||
NormalizeSubWord(IspellDict * Conf, char *word, char flag)
|
||||
{
|
||||
AffixNodeData *suffix = NULL,
|
||||
*prefix = NULL;
|
||||
int slevel = 0,
|
||||
plevel = 0;
|
||||
int wrdlen = strlen(word),
|
||||
swrdlen;
|
||||
char **forms;
|
||||
char **cur;
|
||||
char newword[2 * MAXNORMLEN] = "";
|
||||
char pnewword[2 * MAXNORMLEN] = "";
|
||||
AffixNode *snode = Conf->Suffix, *pnode;
|
||||
int i,j;
|
||||
AffixNode *snode = Conf->Suffix,
|
||||
*pnode;
|
||||
int i,
|
||||
j;
|
||||
|
||||
if (wrdlen > MAXNORMLEN) return NULL;
|
||||
if (wrdlen > MAXNORMLEN)
|
||||
return NULL;
|
||||
strlower(word);
|
||||
cur = forms = (char **) palloc(MAX_NORM * sizeof(char *));
|
||||
*cur = NULL;
|
||||
|
||||
|
||||
/* Check that the word itself is normal form */
|
||||
if (FindWord(Conf, word, 0, flag & FF_COMPOUNDWORD)) {
|
||||
if (FindWord(Conf, word, 0, flag & FF_COMPOUNDWORD))
|
||||
{
|
||||
*cur = pstrdup(word);
|
||||
cur++;
|
||||
*cur = NULL;
|
||||
@ -772,13 +857,18 @@ NormalizeSubWord(IspellDict * Conf, char *word, char flag) {
|
||||
/* Find all other NORMAL forms of the 'word' (check only prefix) */
|
||||
pnode = Conf->Prefix;
|
||||
plevel = 0;
|
||||
while(pnode) {
|
||||
while (pnode)
|
||||
{
|
||||
prefix = FinfAffixes(pnode, word, wrdlen, &plevel, FF_PREFIX);
|
||||
if (!prefix) break;
|
||||
for(j=0;j<prefix->naff;j++) {
|
||||
if ( CheckAffix(word,wrdlen,prefix->aff[j], flag, newword) ) {
|
||||
if (!prefix)
|
||||
break;
|
||||
for (j = 0; j < prefix->naff; j++)
|
||||
{
|
||||
if (CheckAffix(word, wrdlen, prefix->aff[j], flag, newword))
|
||||
{
|
||||
/* prefix success */
|
||||
if ( FindWord(Conf, newword, prefix->aff[j]->flag, flag&FF_COMPOUNDWORD) && (cur - forms) < (MAX_NORM-1) ) {
|
||||
if (FindWord(Conf, newword, prefix->aff[j]->flag, flag & FF_COMPOUNDWORD) && (cur - forms) < (MAX_NORM - 1))
|
||||
{
|
||||
/* word search success */
|
||||
*cur = pstrdup(newword);
|
||||
cur++;
|
||||
@ -789,16 +879,24 @@ NormalizeSubWord(IspellDict * Conf, char *word, char flag) {
|
||||
pnode = prefix->node;
|
||||
}
|
||||
|
||||
/* Find all other NORMAL forms of the 'word' (check suffix and then prefix)*/
|
||||
while( snode ) {
|
||||
/*
|
||||
* Find all other NORMAL forms of the 'word' (check suffix and then
|
||||
* prefix)
|
||||
*/
|
||||
while (snode)
|
||||
{
|
||||
/* find possible suffix */
|
||||
suffix = FinfAffixes(snode, word, wrdlen, &slevel, FF_SUFFIX);
|
||||
if (!suffix) break;
|
||||
if (!suffix)
|
||||
break;
|
||||
/* foreach suffix check affix */
|
||||
for(i=0;i<suffix->naff;i++) {
|
||||
if ( CheckAffix(word, wrdlen, suffix->aff[i], flag, newword) ) {
|
||||
for (i = 0; i < suffix->naff; i++)
|
||||
{
|
||||
if (CheckAffix(word, wrdlen, suffix->aff[i], flag, newword))
|
||||
{
|
||||
/* suffix success */
|
||||
if ( FindWord(Conf, newword, suffix->aff[i]->flag, flag&FF_COMPOUNDWORD) && (cur - forms) < (MAX_NORM-1) ) {
|
||||
if (FindWord(Conf, newword, suffix->aff[i]->flag, flag & FF_COMPOUNDWORD) && (cur - forms) < (MAX_NORM - 1))
|
||||
{
|
||||
/* word search success */
|
||||
*cur = pstrdup(newword);
|
||||
cur++;
|
||||
@ -808,15 +906,21 @@ NormalizeSubWord(IspellDict * Conf, char *word, char flag) {
|
||||
pnode = Conf->Prefix;
|
||||
plevel = 0;
|
||||
swrdlen = strlen(newword);
|
||||
while(pnode) {
|
||||
while (pnode)
|
||||
{
|
||||
prefix = FinfAffixes(pnode, newword, swrdlen, &plevel, FF_PREFIX);
|
||||
if (!prefix) break;
|
||||
for(j=0;j<prefix->naff;j++) {
|
||||
if ( CheckAffix(newword,swrdlen,prefix->aff[j], flag, pnewword) ) {
|
||||
if (!prefix)
|
||||
break;
|
||||
for (j = 0; j < prefix->naff; j++)
|
||||
{
|
||||
if (CheckAffix(newword, swrdlen, prefix->aff[j], flag, pnewword))
|
||||
{
|
||||
/* prefix success */
|
||||
int ff = (prefix->aff[j]->flagflags & suffix->aff[i]->flagflags & FF_CROSSPRODUCT) ?
|
||||
0 : prefix->aff[j]->flag;
|
||||
if ( FindWord(Conf, pnewword, ff, flag&FF_COMPOUNDWORD) && (cur - forms) < (MAX_NORM-1) ) {
|
||||
|
||||
if (FindWord(Conf, pnewword, ff, flag & FF_COMPOUNDWORD) && (cur - forms) < (MAX_NORM - 1))
|
||||
{
|
||||
/* word search success */
|
||||
*cur = pstrdup(pnewword);
|
||||
cur++;
|
||||
@ -832,23 +936,28 @@ NormalizeSubWord(IspellDict * Conf, char *word, char flag) {
|
||||
snode = suffix->node;
|
||||
}
|
||||
|
||||
if (cur == forms) {
|
||||
if (cur == forms)
|
||||
{
|
||||
pfree(forms);
|
||||
return (NULL);
|
||||
}
|
||||
return (forms);
|
||||
}
|
||||
|
||||
typedef struct SplitVar {
|
||||
typedef struct SplitVar
|
||||
{
|
||||
int nstem;
|
||||
char **stem;
|
||||
struct SplitVar *next;
|
||||
} SplitVar;
|
||||
|
||||
static int
|
||||
CheckCompoundAffixes(CMPDAffix **ptr, char *word, int len) {
|
||||
while( (*ptr)->affix ) {
|
||||
if ( len > (*ptr)->len && strncmp((*ptr)->affix, word, (*ptr)->len)==0 ) {
|
||||
CheckCompoundAffixes(CMPDAffix ** ptr, char *word, int len)
|
||||
{
|
||||
while ((*ptr)->affix)
|
||||
{
|
||||
if (len > (*ptr)->len && strncmp((*ptr)->affix, word, (*ptr)->len) == 0)
|
||||
{
|
||||
len = (*ptr)->len;
|
||||
(*ptr)++;
|
||||
return len;
|
||||
@ -859,29 +968,36 @@ CheckCompoundAffixes(CMPDAffix **ptr, char *word, int len) {
|
||||
}
|
||||
|
||||
static SplitVar *
|
||||
CopyVar(SplitVar *s, int makedup) {
|
||||
CopyVar(SplitVar * s, int makedup)
|
||||
{
|
||||
SplitVar *v = (SplitVar *) palloc(sizeof(SplitVar));
|
||||
|
||||
v->stem = (char **) palloc(sizeof(char *) * (MAX_NORM));
|
||||
v->next = NULL;
|
||||
if ( s ) {
|
||||
if (s)
|
||||
{
|
||||
int i;
|
||||
|
||||
v->nstem = s->nstem;
|
||||
for (i = 0; i < s->nstem; i++)
|
||||
v->stem[i] = (makedup) ? pstrdup(s->stem[i]) : s->stem[i];
|
||||
} else {
|
||||
v->nstem=0;
|
||||
}
|
||||
else
|
||||
v->nstem = 0;
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
static SplitVar *
|
||||
SplitToVariants( IspellDict * Conf, SPNode *snode, SplitVar * orig, char *word, int wordlen, int startpos, int minpos ) {
|
||||
SplitToVariants(IspellDict * Conf, SPNode * snode, SplitVar * orig, char *word, int wordlen, int startpos, int minpos)
|
||||
{
|
||||
SplitVar *var = NULL;
|
||||
SPNodeData *StopLow, *StopHigh, *StopMiddle = NULL;
|
||||
SPNodeData *StopLow,
|
||||
*StopHigh,
|
||||
*StopMiddle = NULL;
|
||||
SPNode *node = (snode) ? snode : Conf->Dictionary;
|
||||
int level=(snode) ? minpos : startpos; /* recursive minpos==level*/
|
||||
int level = (snode) ? minpos : startpos; /* recursive
|
||||
* minpos==level */
|
||||
int lenaff;
|
||||
CMPDAffix *caff;
|
||||
char *notprobed;
|
||||
@ -890,26 +1006,31 @@ SplitToVariants( IspellDict * Conf, SPNode *snode, SplitVar * orig, char *word,
|
||||
memset(notprobed, 1, wordlen);
|
||||
var = CopyVar(orig, 1);
|
||||
|
||||
while( node && level<wordlen) {
|
||||
while (node && level < wordlen)
|
||||
{
|
||||
StopLow = node->data;
|
||||
StopHigh = node->data + node->length;
|
||||
while (StopLow < StopHigh) {
|
||||
while (StopLow < StopHigh)
|
||||
{
|
||||
StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
|
||||
if ( StopMiddle->val == ((uint8*)(word))[level] ) {
|
||||
if (StopMiddle->val == ((uint8 *) (word))[level])
|
||||
break;
|
||||
} else if ( StopMiddle->val < ((uint8*)(word))[level] ) {
|
||||
else if (StopMiddle->val < ((uint8 *) (word))[level])
|
||||
StopLow = StopMiddle + 1;
|
||||
} else {
|
||||
else
|
||||
StopHigh = StopMiddle;
|
||||
}
|
||||
}
|
||||
if (StopLow >= StopHigh)
|
||||
break;
|
||||
|
||||
/* find word with epenthetic */
|
||||
caff = Conf->CompoundAffix;
|
||||
while ( level>startpos && (lenaff=CheckCompoundAffixes( &caff, word + level, wordlen - level ))>0 ) {
|
||||
/* there is one of compound suffixes, so check word for existings */
|
||||
while (level > startpos && (lenaff = CheckCompoundAffixes(&caff, word + level, wordlen - level)) > 0)
|
||||
{
|
||||
/*
|
||||
* there is one of compound suffixes, so check word for
|
||||
* existings
|
||||
*/
|
||||
char buf[MAXNORMLEN];
|
||||
char **subres;
|
||||
|
||||
@ -925,7 +1046,8 @@ SplitToVariants( IspellDict * Conf, SPNode *snode, SplitVar * orig, char *word,
|
||||
buf[lenaff] = '\0';
|
||||
|
||||
subres = NormalizeSubWord(Conf, buf, FF_COMPOUNDWORD | FF_COMPOUNDONLYAFX);
|
||||
if ( subres ) {
|
||||
if (subres)
|
||||
{
|
||||
/* Yes, it was a word from dictionary */
|
||||
SplitVar *new = CopyVar(var, 0);
|
||||
SplitVar *ptr = var;
|
||||
@ -933,7 +1055,8 @@ SplitToVariants( IspellDict * Conf, SPNode *snode, SplitVar * orig, char *word,
|
||||
|
||||
notprobed[startpos + lenaff - 1] = 0;
|
||||
|
||||
while(*sptr) {
|
||||
while (*sptr)
|
||||
{
|
||||
new->stem[new->nstem] = *sptr;
|
||||
new->nstem++;
|
||||
sptr++;
|
||||
@ -950,19 +1073,25 @@ SplitToVariants( IspellDict * Conf, SPNode *snode, SplitVar * orig, char *word,
|
||||
}
|
||||
|
||||
/* find infinitive */
|
||||
if ( StopMiddle->isword && StopMiddle->compoundallow && notprobed[level] ) {
|
||||
if (StopMiddle->isword && StopMiddle->compoundallow && notprobed[level])
|
||||
{
|
||||
/* ok, we found full compoundallowed word */
|
||||
if ( level>minpos ) {
|
||||
if (level > minpos)
|
||||
{
|
||||
/* and its length more than minimal */
|
||||
if ( wordlen==level+1 ) {
|
||||
if (wordlen == level + 1)
|
||||
{
|
||||
/* well, it was last word */
|
||||
var->stem[var->nstem] = strnduplicate(word + startpos, wordlen - startpos);
|
||||
var->nstem++;
|
||||
pfree(notprobed);
|
||||
return var;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* then we will search more big word at the same point */
|
||||
SplitVar *ptr = var;
|
||||
|
||||
while (ptr->next)
|
||||
ptr = ptr->next;
|
||||
ptr->next = SplitToVariants(Conf, node, var, word, wordlen, startpos, level);
|
||||
@ -987,35 +1116,46 @@ SplitToVariants( IspellDict * Conf, SPNode *snode, SplitVar * orig, char *word,
|
||||
}
|
||||
|
||||
char **
|
||||
NINormalizeWord(IspellDict * Conf, char *word) {
|
||||
NINormalizeWord(IspellDict * Conf, char *word)
|
||||
{
|
||||
char **res = NormalizeSubWord(Conf, word, 0);
|
||||
|
||||
if ( Conf->compoundcontrol != '\t' ) {
|
||||
if (Conf->compoundcontrol != '\t')
|
||||
{
|
||||
int wordlen = strlen(word);
|
||||
SplitVar *ptr, *var = SplitToVariants(Conf,NULL,NULL, word, wordlen, 0, -1);
|
||||
SplitVar *ptr,
|
||||
*var = SplitToVariants(Conf, NULL, NULL, word, wordlen, 0, -1);
|
||||
char **cur = res;
|
||||
int i;
|
||||
|
||||
while(var) {
|
||||
if ( var->nstem > 1 ) {
|
||||
while (var)
|
||||
{
|
||||
if (var->nstem > 1)
|
||||
{
|
||||
char **subres = NormalizeSubWord(Conf, var->stem[var->nstem - 1], FF_COMPOUNDWORD);
|
||||
if ( subres ) {
|
||||
|
||||
if (subres)
|
||||
{
|
||||
char **ptr = subres;
|
||||
|
||||
if ( cur ) {
|
||||
if (cur)
|
||||
{
|
||||
while (*cur)
|
||||
cur++;
|
||||
} else {
|
||||
res=cur=(char **) palloc(MAX_NORM * sizeof(char *));
|
||||
}
|
||||
else
|
||||
res = cur = (char **) palloc(MAX_NORM * sizeof(char *));
|
||||
|
||||
for(i=0;i<var->nstem-1;i++) {
|
||||
for (i = 0; i < var->nstem - 1; i++)
|
||||
{
|
||||
*cur = var->stem[i];
|
||||
cur++;
|
||||
}
|
||||
while(*ptr) {
|
||||
while (*ptr)
|
||||
{
|
||||
*cur = *ptr;
|
||||
cur++; ptr++;
|
||||
cur++;
|
||||
ptr++;
|
||||
}
|
||||
*cur = NULL;
|
||||
pfree(subres);
|
||||
@ -1035,12 +1175,16 @@ NINormalizeWord(IspellDict * Conf, char *word) {
|
||||
}
|
||||
|
||||
|
||||
static void freeSPNode(SPNode *node) {
|
||||
static void
|
||||
freeSPNode(SPNode * node)
|
||||
{
|
||||
SPNodeData *data;
|
||||
|
||||
if (!node) return;
|
||||
if (!node)
|
||||
return;
|
||||
data = node->data;
|
||||
while( node->length ) {
|
||||
while (node->length)
|
||||
{
|
||||
freeSPNode(data->node);
|
||||
data++;
|
||||
node->length--;
|
||||
@ -1048,12 +1192,16 @@ static void freeSPNode(SPNode *node) {
|
||||
free(node);
|
||||
}
|
||||
|
||||
static void freeANode(AffixNode *node) {
|
||||
static void
|
||||
freeANode(AffixNode * node)
|
||||
{
|
||||
AffixNodeData *data;
|
||||
|
||||
if (!node) return;
|
||||
if (!node)
|
||||
return;
|
||||
data = node->data;
|
||||
while( node->length ) {
|
||||
while (node->length)
|
||||
{
|
||||
freeANode(data->node);
|
||||
if (data->naff)
|
||||
free(data->aff);
|
||||
@ -1071,8 +1219,10 @@ NIFree(IspellDict * Conf)
|
||||
AFFIX *Affix = (AFFIX *) Conf->Affix;
|
||||
char **aff = Conf->AffixData;
|
||||
|
||||
if ( aff ) {
|
||||
while(*aff) {
|
||||
if (aff)
|
||||
{
|
||||
while (*aff)
|
||||
{
|
||||
free(*aff);
|
||||
aff++;
|
||||
}
|
||||
@ -1082,21 +1232,25 @@ NIFree(IspellDict * Conf)
|
||||
|
||||
for (i = 0; i < Conf->naffixes; i++)
|
||||
{
|
||||
if (Affix[i].compile == 0) {
|
||||
if (Affix[i].compile == 0)
|
||||
{
|
||||
if (Affix[i].isregis)
|
||||
RS_free(&(Affix[i].reg.regis));
|
||||
else
|
||||
pg_regfree(&(Affix[i].reg.regex));
|
||||
}
|
||||
}
|
||||
if (Conf->Spell) {
|
||||
if (Conf->Spell)
|
||||
{
|
||||
for (i = 0; i < Conf->nspell; i++)
|
||||
free(Conf->Spell[i].word);
|
||||
free(Conf->Spell);
|
||||
}
|
||||
|
||||
if (Conf->Affix) free(Conf->Affix);
|
||||
if ( Conf->CompoundAffix ) free(Conf->CompoundAffix);
|
||||
if (Conf->Affix)
|
||||
free(Conf->Affix);
|
||||
if (Conf->CompoundAffix)
|
||||
free(Conf->CompoundAffix);
|
||||
freeSPNode(Conf->Dictionary);
|
||||
freeANode(Conf->Suffix);
|
||||
freeANode(Conf->Prefix);
|
||||
|
@ -10,7 +10,8 @@
|
||||
struct SPNode;
|
||||
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
uint32
|
||||
val:8,
|
||||
isword:1,
|
||||
@ -19,7 +20,8 @@ typedef struct {
|
||||
struct SPNode *node;
|
||||
} SPNodeData;
|
||||
|
||||
typedef struct SPNode {
|
||||
typedef struct SPNode
|
||||
{
|
||||
uint32 length;
|
||||
SPNodeData data[1];
|
||||
} SPNode;
|
||||
@ -30,9 +32,11 @@ typedef struct SPNode {
|
||||
typedef struct spell_struct
|
||||
{
|
||||
char *word;
|
||||
union {
|
||||
union
|
||||
{
|
||||
char flag[16];
|
||||
struct {
|
||||
struct
|
||||
{
|
||||
int affix;
|
||||
int len;
|
||||
} d;
|
||||
@ -53,7 +57,8 @@ typedef struct aff_struct
|
||||
char mask[32];
|
||||
char find[16];
|
||||
char repl[16];
|
||||
union {
|
||||
union
|
||||
{
|
||||
regex_t regex;
|
||||
Regis regis;
|
||||
} reg;
|
||||
@ -67,7 +72,8 @@ typedef struct aff_struct
|
||||
|
||||
struct AffixNode;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
uint32
|
||||
val:8,
|
||||
naff:24;
|
||||
@ -75,7 +81,8 @@ typedef struct {
|
||||
struct AffixNode *node;
|
||||
} AffixNodeData;
|
||||
|
||||
typedef struct AffixNode {
|
||||
typedef struct AffixNode
|
||||
{
|
||||
uint32 isvoid:1,
|
||||
length:31;
|
||||
AffixNodeData data[1];
|
||||
@ -83,7 +90,8 @@ typedef struct AffixNode {
|
||||
|
||||
#define ANHRDSZ (sizeof(uint32))
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
char *affix;
|
||||
int len;
|
||||
} CMPDAffix;
|
||||
|
@ -484,6 +484,7 @@ exectsq(PG_FUNCTION_ARGS)
|
||||
QUERYTYPE *query = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(1)));
|
||||
CHKVAL chkval;
|
||||
bool result;
|
||||
|
||||
SET_FUNCOID();
|
||||
if (!val->size || !query->size)
|
||||
{
|
||||
@ -865,6 +866,7 @@ to_tsquery(PG_FUNCTION_ARGS)
|
||||
QUERYTYPE *query;
|
||||
ITEM *res;
|
||||
int4 len;
|
||||
|
||||
SET_FUNCOID();
|
||||
|
||||
str = text2char(in);
|
||||
@ -888,6 +890,7 @@ to_tsquery_name(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *name = PG_GETARG_TEXT_P(0);
|
||||
Datum res;
|
||||
|
||||
SET_FUNCOID();
|
||||
res = DirectFunctionCall2(to_tsquery,
|
||||
Int32GetDatum(name2id_cfg(name)),
|
||||
|
@ -301,7 +301,8 @@ parsetext_v2(TSCfgInfo * cfg, PRSTEXT * prs, char *buf, int4 buflen)
|
||||
PointerGetDatum(&lenlemm)))) != 0)
|
||||
{
|
||||
|
||||
if (lenlemm >= MAXSTRLEN) {
|
||||
if (lenlemm >= MAXSTRLEN)
|
||||
{
|
||||
#ifdef IGNORE_LONGLEXEME
|
||||
ereport(NOTICE,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
@ -435,7 +436,8 @@ hlparsetext(TSCfgInfo * cfg, HLPRSTEXT * prs, QUERYTYPE * query, char *buf, int4
|
||||
PointerGetDatum(&lenlemm)))) != 0)
|
||||
{
|
||||
|
||||
if (lenlemm >= MAXSTRLEN) {
|
||||
if (lenlemm >= MAXSTRLEN)
|
||||
{
|
||||
#ifdef IGNORE_LONGLEXEME
|
||||
ereport(NOTICE,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
@ -532,9 +534,8 @@ genhl(HLPRSTEXT * prs)
|
||||
ptr += prs->stopsellen;
|
||||
}
|
||||
}
|
||||
} else
|
||||
|
||||
if (!wrd->repeated)
|
||||
}
|
||||
else if (!wrd->repeated)
|
||||
pfree(wrd->word);
|
||||
|
||||
wrd++;
|
||||
@ -605,6 +606,7 @@ Datum
|
||||
set_curcfg_byname(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *name = PG_GETARG_TEXT_P(0);
|
||||
|
||||
SET_FUNCOID();
|
||||
DirectFunctionCall1(
|
||||
set_curcfg,
|
||||
@ -632,4 +634,3 @@ reset_tsearch(PG_FUNCTION_ARGS)
|
||||
ts_error(NOTICE, "TSearch cache cleaned");
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
|
@ -34,12 +34,14 @@ tsstat_out(PG_FUNCTION_ARGS)
|
||||
}
|
||||
|
||||
static int
|
||||
check_weight(tsvector *txt, WordEntry *wptr, int8 weight) {
|
||||
check_weight(tsvector * txt, WordEntry * wptr, int8 weight)
|
||||
{
|
||||
int len = POSDATALEN(txt, wptr);
|
||||
int num = 0;
|
||||
WordEntryPos *ptr = POSDATAPTR(txt, wptr);
|
||||
|
||||
while (len--) {
|
||||
while (len--)
|
||||
{
|
||||
if (weight & (1 << ptr->weight))
|
||||
num++;
|
||||
ptr++;
|
||||
@ -123,9 +125,9 @@ formstat(tsstat * stat, tsvector * txt, WordEntry ** entry, uint32 len)
|
||||
}
|
||||
nptr = STATPTR(newstat) + (StopLow - STATPTR(stat));
|
||||
memcpy(STATPTR(newstat), STATPTR(stat), sizeof(StatEntry) * (StopLow - STATPTR(stat)));
|
||||
if ( (*ptr)->haspos ) {
|
||||
if ((*ptr)->haspos)
|
||||
nptr->nentry = (stat->weight) ? check_weight(txt, *ptr, stat->weight) : POSDATALEN(txt, *ptr);
|
||||
} else
|
||||
else
|
||||
nptr->nentry = 1;
|
||||
nptr->ndoc = 1;
|
||||
nptr->len = (*ptr)->len;
|
||||
@ -144,9 +146,9 @@ formstat(tsstat * stat, tsvector * txt, WordEntry ** entry, uint32 len)
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( (*ptr)->haspos ) {
|
||||
if ((*ptr)->haspos)
|
||||
nptr->nentry = (stat->weight) ? check_weight(txt, *ptr, stat->weight) : POSDATALEN(txt, *ptr);
|
||||
} else
|
||||
else
|
||||
nptr->nentry = 1;
|
||||
nptr->ndoc = 1;
|
||||
nptr->len = (*ptr)->len;
|
||||
@ -162,9 +164,9 @@ formstat(tsstat * stat, tsvector * txt, WordEntry ** entry, uint32 len)
|
||||
|
||||
while (ptr - entry < len)
|
||||
{
|
||||
if ( (*ptr)->haspos ) {
|
||||
if ((*ptr)->haspos)
|
||||
nptr->nentry = (stat->weight) ? check_weight(txt, *ptr, stat->weight) : POSDATALEN(txt, *ptr);
|
||||
} else
|
||||
else
|
||||
nptr->nentry = 1;
|
||||
nptr->ndoc = 1;
|
||||
nptr->len = (*ptr)->len;
|
||||
@ -222,10 +224,13 @@ ts_accum(PG_FUNCTION_ARGS)
|
||||
sptr++;
|
||||
else if (cmp == 0)
|
||||
{
|
||||
if ( stat->weight == 0 ) {
|
||||
if (stat->weight == 0)
|
||||
{
|
||||
sptr->ndoc++;
|
||||
sptr->nentry += (wptr->haspos) ? POSDATALEN(txt, wptr) : 1;
|
||||
} else if ( wptr->haspos && (n=check_weight(txt, wptr, stat->weight))!=0 ) {
|
||||
}
|
||||
else if (wptr->haspos && (n = check_weight(txt, wptr, stat->weight)) != 0)
|
||||
{
|
||||
sptr->ndoc++;
|
||||
sptr->nentry += n;
|
||||
}
|
||||
@ -234,7 +239,8 @@ ts_accum(PG_FUNCTION_ARGS)
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( stat->weight == 0 || check_weight(txt, wptr, stat->weight)!=0 ) {
|
||||
if (stat->weight == 0 || check_weight(txt, wptr, stat->weight) != 0)
|
||||
{
|
||||
if (cur == len)
|
||||
newentry = SEI_realloc(newentry, &len);
|
||||
newentry[cur] = wptr;
|
||||
@ -246,7 +252,8 @@ ts_accum(PG_FUNCTION_ARGS)
|
||||
|
||||
while (wptr - ARRPTR(txt) < txt->size)
|
||||
{
|
||||
if ( stat->weight == 0 || check_weight(txt, wptr, stat->weight)!=0 ) {
|
||||
if (stat->weight == 0 || check_weight(txt, wptr, stat->weight) != 0)
|
||||
{
|
||||
if (cur == len)
|
||||
newentry = SEI_realloc(newentry, &len);
|
||||
newentry[cur] = wptr;
|
||||
@ -269,10 +276,13 @@ ts_accum(PG_FUNCTION_ARGS)
|
||||
cmp = compareStatWord(sptr, wptr, stat, txt);
|
||||
if (cmp == 0)
|
||||
{
|
||||
if ( stat->weight == 0 ) {
|
||||
if (stat->weight == 0)
|
||||
{
|
||||
sptr->ndoc++;
|
||||
sptr->nentry += (wptr->haspos) ? POSDATALEN(txt, wptr) : 1;
|
||||
} else if ( wptr->haspos && (n=check_weight(txt, wptr, stat->weight))!=0 ) {
|
||||
}
|
||||
else if (wptr->haspos && (n = check_weight(txt, wptr, stat->weight)) != 0)
|
||||
{
|
||||
sptr->ndoc++;
|
||||
sptr->nentry += n;
|
||||
}
|
||||
@ -286,7 +296,8 @@ ts_accum(PG_FUNCTION_ARGS)
|
||||
|
||||
if (StopLow >= StopHigh)
|
||||
{ /* not found */
|
||||
if ( stat->weight == 0 || check_weight(txt, wptr, stat->weight)!=0 ) {
|
||||
if (stat->weight == 0 || check_weight(txt, wptr, stat->weight) != 0)
|
||||
{
|
||||
if (cur == len)
|
||||
newentry = SEI_realloc(newentry, &len);
|
||||
newentry[cur] = wptr;
|
||||
@ -454,11 +465,15 @@ ts_stat_sql(text *txt, text *ws)
|
||||
stat->size = 0;
|
||||
stat->weight = 0;
|
||||
|
||||
if ( ws ) {
|
||||
if (ws)
|
||||
{
|
||||
char *buf;
|
||||
|
||||
buf = VARDATA(ws);
|
||||
while( buf - VARDATA(ws) < VARSIZE(ws) - VARHDRSZ ) {
|
||||
switch (tolower(*buf)) {
|
||||
while (buf - VARDATA(ws) < VARSIZE(ws) - VARHDRSZ)
|
||||
{
|
||||
switch (tolower(*buf))
|
||||
{
|
||||
case 'a':
|
||||
stat->weight |= 1 << 3;
|
||||
break;
|
||||
@ -527,7 +542,8 @@ ts_stat(PG_FUNCTION_ARGS)
|
||||
SPI_connect();
|
||||
stat = ts_stat_sql(txt, ws);
|
||||
PG_FREE_IF_COPY(txt, 0);
|
||||
if (PG_NARGS() > 1 ) PG_FREE_IF_COPY(ws, 1);
|
||||
if (PG_NARGS() > 1)
|
||||
PG_FREE_IF_COPY(ws, 1);
|
||||
ts_setup_firstcall(funcctx, stat);
|
||||
SPI_finish();
|
||||
}
|
||||
|
@ -404,6 +404,7 @@ tsvector_in(PG_FUNCTION_ARGS)
|
||||
*cur;
|
||||
int4 i,
|
||||
buflen = 256;
|
||||
|
||||
SET_FUNCOID();
|
||||
state.prsbuf = buf;
|
||||
state.len = 32;
|
||||
@ -638,7 +639,8 @@ uniqueWORD(TSWORD * a, int4 l)
|
||||
res->alen *= 2;
|
||||
res->pos.apos = (uint16 *) repalloc(res->pos.apos, sizeof(uint16) * res->alen);
|
||||
}
|
||||
if ( res->pos.apos[0]==0 || res->pos.apos[res->pos.apos[0]] != LIMITPOS(ptr->pos.pos) ) {
|
||||
if (res->pos.apos[0] == 0 || res->pos.apos[res->pos.apos[0]] != LIMITPOS(ptr->pos.pos))
|
||||
{
|
||||
res->pos.apos[res->pos.apos[0] + 1] = LIMITPOS(ptr->pos.pos);
|
||||
res->pos.apos[0]++;
|
||||
}
|
||||
@ -753,6 +755,7 @@ to_tsvector_name(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *cfg = PG_GETARG_TEXT_P(0);
|
||||
Datum res;
|
||||
|
||||
SET_FUNCOID();
|
||||
res = DirectFunctionCall3(
|
||||
to_tsvector,
|
||||
@ -769,6 +772,7 @@ Datum
|
||||
to_tsvector_current(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum res;
|
||||
|
||||
SET_FUNCOID();
|
||||
res = DirectFunctionCall3(
|
||||
to_tsvector,
|
||||
@ -947,7 +951,8 @@ tsearch2(PG_FUNCTION_ARGS)
|
||||
}
|
||||
|
||||
static int
|
||||
silly_cmp_tsvector(const tsvector *a, const tsvector *b) {
|
||||
silly_cmp_tsvector(const tsvector * a, const tsvector * b)
|
||||
{
|
||||
if (a->len < b->len)
|
||||
return -1;
|
||||
else if (a->len > b->len)
|
||||
@ -956,14 +961,17 @@ silly_cmp_tsvector(const tsvector *a, const tsvector *b) {
|
||||
return -1;
|
||||
else if (a->size > b->size)
|
||||
return 1;
|
||||
else {
|
||||
else
|
||||
{
|
||||
unsigned char *aptr = (unsigned char *) (a->data) + DATAHDRSIZE;
|
||||
unsigned char *bptr = (unsigned char *) (b->data) + DATAHDRSIZE;
|
||||
|
||||
while( aptr - ( (unsigned char *)(a->data) ) < a->len ) {
|
||||
while (aptr - ((unsigned char *) (a->data)) < a->len)
|
||||
{
|
||||
if (*aptr != *bptr)
|
||||
return (*aptr < *bptr) ? -1 : 1;
|
||||
aptr++; bptr++;
|
||||
aptr++;
|
||||
bptr++;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@ -992,44 +1000,50 @@ PG_FREE_IF_COPY(a,0); \
|
||||
PG_FREE_IF_COPY(b,1); \
|
||||
|
||||
Datum
|
||||
tsvector_cmp(PG_FUNCTION_ARGS) {
|
||||
tsvector_cmp(PG_FUNCTION_ARGS)
|
||||
{
|
||||
RUNCMP
|
||||
PG_RETURN_INT32(res);
|
||||
}
|
||||
|
||||
Datum
|
||||
tsvector_lt(PG_FUNCTION_ARGS) {
|
||||
tsvector_lt(PG_FUNCTION_ARGS)
|
||||
{
|
||||
RUNCMP
|
||||
PG_RETURN_BOOL((res < 0) ? true : false);
|
||||
}
|
||||
|
||||
Datum
|
||||
tsvector_le(PG_FUNCTION_ARGS) {
|
||||
tsvector_le(PG_FUNCTION_ARGS)
|
||||
{
|
||||
RUNCMP
|
||||
PG_RETURN_BOOL((res <= 0) ? true : false);
|
||||
}
|
||||
|
||||
Datum
|
||||
tsvector_eq(PG_FUNCTION_ARGS) {
|
||||
tsvector_eq(PG_FUNCTION_ARGS)
|
||||
{
|
||||
RUNCMP
|
||||
PG_RETURN_BOOL((res == 0) ? true : false);
|
||||
}
|
||||
|
||||
Datum
|
||||
tsvector_ge(PG_FUNCTION_ARGS) {
|
||||
tsvector_ge(PG_FUNCTION_ARGS)
|
||||
{
|
||||
RUNCMP
|
||||
PG_RETURN_BOOL((res >= 0) ? true : false);
|
||||
}
|
||||
|
||||
Datum
|
||||
tsvector_gt(PG_FUNCTION_ARGS) {
|
||||
tsvector_gt(PG_FUNCTION_ARGS)
|
||||
{
|
||||
RUNCMP
|
||||
PG_RETURN_BOOL((res > 0) ? true : false);
|
||||
}
|
||||
|
||||
Datum
|
||||
tsvector_ne(PG_FUNCTION_ARGS) {
|
||||
tsvector_ne(PG_FUNCTION_ARGS)
|
||||
{
|
||||
RUNCMP
|
||||
PG_RETURN_BOOL((res != 0) ? true : false);
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,8 @@ init_prs(Oid id, WParserInfo * prs)
|
||||
Datum pars[1];
|
||||
int stat;
|
||||
void *plan;
|
||||
char buf[1024], *nsp;
|
||||
char buf[1024],
|
||||
*nsp;
|
||||
|
||||
arg[0] = OIDOID;
|
||||
pars[0] = ObjectIdGetDatum(id);
|
||||
@ -140,7 +141,8 @@ name2id_prs(text *name)
|
||||
Datum pars[1];
|
||||
int stat;
|
||||
Oid id = findSNMap_t(&(PList.name2id_map), name);
|
||||
char buf[1024], *nsp;
|
||||
char buf[1024],
|
||||
*nsp;
|
||||
void *plan;
|
||||
|
||||
arg[0] = TEXTOID;
|
||||
@ -242,6 +244,7 @@ token_type(PG_FUNCTION_ARGS)
|
||||
{
|
||||
FuncCallContext *funcctx;
|
||||
Datum result;
|
||||
|
||||
SET_FUNCOID();
|
||||
if (SRF_IS_FIRSTCALL())
|
||||
{
|
||||
@ -263,6 +266,7 @@ token_type_byname(PG_FUNCTION_ARGS)
|
||||
{
|
||||
FuncCallContext *funcctx;
|
||||
Datum result;
|
||||
|
||||
SET_FUNCOID();
|
||||
if (SRF_IS_FIRSTCALL())
|
||||
{
|
||||
@ -287,6 +291,7 @@ token_type_current(PG_FUNCTION_ARGS)
|
||||
{
|
||||
FuncCallContext *funcctx;
|
||||
Datum result;
|
||||
|
||||
SET_FUNCOID();
|
||||
if (SRF_IS_FIRSTCALL())
|
||||
{
|
||||
@ -321,6 +326,7 @@ Datum
|
||||
set_curprs_byname(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *name = PG_GETARG_TEXT_P(0);
|
||||
|
||||
SET_FUNCOID();
|
||||
DirectFunctionCall1(
|
||||
set_curprs,
|
||||
@ -444,6 +450,7 @@ parse(PG_FUNCTION_ARGS)
|
||||
{
|
||||
FuncCallContext *funcctx;
|
||||
Datum result;
|
||||
|
||||
SET_FUNCOID();
|
||||
if (SRF_IS_FIRSTCALL())
|
||||
{
|
||||
@ -468,6 +475,7 @@ parse_byname(PG_FUNCTION_ARGS)
|
||||
{
|
||||
FuncCallContext *funcctx;
|
||||
Datum result;
|
||||
|
||||
SET_FUNCOID();
|
||||
if (SRF_IS_FIRSTCALL())
|
||||
{
|
||||
@ -495,6 +503,7 @@ parse_current(PG_FUNCTION_ARGS)
|
||||
{
|
||||
FuncCallContext *funcctx;
|
||||
Datum result;
|
||||
|
||||
SET_FUNCOID();
|
||||
if (SRF_IS_FIRSTCALL())
|
||||
{
|
||||
@ -566,6 +575,7 @@ headline_byname(PG_FUNCTION_ARGS)
|
||||
text *cfg = PG_GETARG_TEXT_P(0);
|
||||
|
||||
Datum out;
|
||||
|
||||
SET_FUNCOID();
|
||||
out = DirectFunctionCall4(
|
||||
headline,
|
||||
|
@ -192,7 +192,8 @@ prsd_headline(PG_FUNCTION_ARGS)
|
||||
int bestb = -1,
|
||||
beste = -1;
|
||||
int bestlen = -1;
|
||||
int pose = 0, posb,
|
||||
int pose = 0,
|
||||
posb,
|
||||
poslen,
|
||||
curlen;
|
||||
|
||||
@ -239,7 +240,8 @@ prsd_headline(PG_FUNCTION_ARGS)
|
||||
}
|
||||
pfree(map);
|
||||
|
||||
if (highlight==0) {
|
||||
if (highlight == 0)
|
||||
{
|
||||
if (min_words >= max_words)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
@ -255,7 +257,8 @@ prsd_headline(PG_FUNCTION_ARGS)
|
||||
}
|
||||
}
|
||||
|
||||
if (highlight==0) {
|
||||
if (highlight == 0)
|
||||
{
|
||||
while (hlCover(prs, query, &p, &q))
|
||||
{
|
||||
/* find cover len in words */
|
||||
@ -295,8 +298,11 @@ prsd_headline(PG_FUNCTION_ARGS)
|
||||
if (curlen >= min_words)
|
||||
break;
|
||||
}
|
||||
if ( curlen < min_words && i>=prs->curwords ) { /* got end of text and our cover is shoter than min_words */
|
||||
for(i=p; i>= 0; i--) {
|
||||
if (curlen < min_words && i >= prs->curwords)
|
||||
{ /* got end of text and our cover is shoter
|
||||
* than min_words */
|
||||
for (i = p; i >= 0; i--)
|
||||
{
|
||||
if (!NONWORDTOKEN(prs->words[i].type))
|
||||
curlen++;
|
||||
if (prs->words[i].item && !prs->words[i].repeated)
|
||||
@ -348,7 +354,9 @@ prsd_headline(PG_FUNCTION_ARGS)
|
||||
bestb = 0;
|
||||
beste = pose;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
bestb = 0;
|
||||
beste = prs->curwords - 1;
|
||||
}
|
||||
@ -357,10 +365,13 @@ prsd_headline(PG_FUNCTION_ARGS)
|
||||
{
|
||||
if (prs->words[i].item)
|
||||
prs->words[i].selected = 1;
|
||||
if ( highlight==0 ) {
|
||||
if (highlight == 0)
|
||||
{
|
||||
if (HLIDIGNORE(prs->words[i].type))
|
||||
prs->words[i].replace = 1;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (HTMLHLIDIGNORE(prs->words[i].type))
|
||||
prs->words[i].replace = 1;
|
||||
}
|
||||
|
@ -102,12 +102,11 @@ pgxml_errorHandler (void * ctxt, const char *msg, ...)
|
||||
va_end(args);
|
||||
/* Now copy the argument across */
|
||||
if (pgxml_errorMsg == NULL)
|
||||
{
|
||||
pgxml_errorMsg = pstrdup(errbuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
int32 xsize = strlen(pgxml_errorMsg);
|
||||
|
||||
pgxml_errorMsg = repalloc(pgxml_errorMsg,
|
||||
(size_t) (xsize + strlen(errbuf) + 1));
|
||||
strncpy(&pgxml_errorMsg[xsize - 1], errbuf, strlen(errbuf));
|
||||
@ -118,7 +117,8 @@ else
|
||||
}
|
||||
|
||||
/* This function reports the current message at the level specified */
|
||||
void elog_error(int level, char *explain, int force)
|
||||
void
|
||||
elog_error(int level, char *explain, int force)
|
||||
{
|
||||
if (force || (pgxml_errorMsg != NULL))
|
||||
{
|
||||
@ -201,8 +201,11 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset,
|
||||
*/
|
||||
|
||||
/* each representation is surrounded by <tagname> ... </tagname> */
|
||||
/* plainsep is an ordinary (not tag) seperator - if used, then
|
||||
* nodes are cast to string as output method */
|
||||
|
||||
/*
|
||||
* plainsep is an ordinary (not tag) seperator - if used, then nodes
|
||||
* are cast to string as output method
|
||||
*/
|
||||
|
||||
|
||||
xmlBufferPtr buf;
|
||||
@ -222,15 +225,17 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset,
|
||||
for (i = 0; i < nodeset->nodeNr; i++)
|
||||
{
|
||||
|
||||
if (plainsep != NULL) {
|
||||
if (plainsep != NULL)
|
||||
{
|
||||
xmlBufferWriteCHAR(buf,
|
||||
xmlXPathCastNodeToString(nodeset->nodeTab[i]));
|
||||
|
||||
/* If this isn't the last entry, write the plain sep. */
|
||||
if (i < (nodeset->nodeNr)-1) {
|
||||
if (i < (nodeset->nodeNr) - 1)
|
||||
xmlBufferWriteChar(buf, plainsep);
|
||||
}
|
||||
} else {
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
if ((septagname != NULL) && (xmlStrlen(septagname) > 0))
|
||||
@ -294,7 +299,9 @@ PG_FUNCTION_INFO_V1(xpath_nodeset);
|
||||
Datum
|
||||
xpath_nodeset(PG_FUNCTION_ARGS)
|
||||
{
|
||||
xmlChar *xpath, *toptag, *septag;
|
||||
xmlChar *xpath,
|
||||
*toptag,
|
||||
*septag;
|
||||
int32 pathsize;
|
||||
text
|
||||
*xpathsupp,
|
||||
@ -318,21 +325,20 @@ xpath_nodeset(PG_FUNCTION_ARGS)
|
||||
pfree((void *) xpath);
|
||||
|
||||
if (xpres == NULL)
|
||||
{
|
||||
PG_RETURN_NULL();
|
||||
}
|
||||
PG_RETURN_TEXT_P(xpres);
|
||||
}
|
||||
|
||||
// The following function is almost identical, but returns the elements in
|
||||
// a list.
|
||||
/* The following function is almost identical, but returns the elements in */
|
||||
/* a list. */
|
||||
|
||||
PG_FUNCTION_INFO_V1(xpath_list);
|
||||
|
||||
Datum
|
||||
xpath_list(PG_FUNCTION_ARGS)
|
||||
{
|
||||
xmlChar *xpath, *plainsep;
|
||||
xmlChar *xpath,
|
||||
*plainsep;
|
||||
int32 pathsize;
|
||||
text
|
||||
*xpathsupp,
|
||||
@ -355,9 +361,7 @@ xpath_list(PG_FUNCTION_ARGS)
|
||||
pfree((void *) xpath);
|
||||
|
||||
if (xpres == NULL)
|
||||
{
|
||||
PG_RETURN_NULL();
|
||||
}
|
||||
PG_RETURN_TEXT_P(xpres);
|
||||
}
|
||||
|
||||
@ -378,8 +382,10 @@ xpath_string(PG_FUNCTION_ARGS)
|
||||
|
||||
pathsize = VARSIZE(xpathsupp) - VARHDRSZ;
|
||||
|
||||
/* We encapsulate the supplied path with "string()"
|
||||
* = 8 chars + 1 for NUL at end */
|
||||
/*
|
||||
* We encapsulate the supplied path with "string()" = 8 chars + 1 for
|
||||
* NUL at end
|
||||
*/
|
||||
/* We could try casting to string using the libxml function? */
|
||||
|
||||
xpath = (xmlChar *) palloc(pathsize + 9);
|
||||
@ -396,9 +402,7 @@ xpath_string(PG_FUNCTION_ARGS)
|
||||
pfree((void *) xpath);
|
||||
|
||||
if (xpres == NULL)
|
||||
{
|
||||
PG_RETURN_NULL();
|
||||
}
|
||||
PG_RETURN_TEXT_P(xpres);
|
||||
}
|
||||
|
||||
@ -436,9 +440,7 @@ xpath_number(PG_FUNCTION_ARGS)
|
||||
fRes = xmlXPathCastToNumber(res);
|
||||
xmlCleanupParser();
|
||||
if (xmlXPathIsNaN(fRes))
|
||||
{
|
||||
PG_RETURN_NULL();
|
||||
}
|
||||
|
||||
PG_RETURN_FLOAT4(fRes);
|
||||
|
||||
@ -530,7 +532,7 @@ xmlXPathObjectPtr
|
||||
if (res == NULL)
|
||||
{
|
||||
xmlXPathFreeContext(ctxt);
|
||||
// xmlCleanupParser();
|
||||
/* xmlCleanupParser(); */
|
||||
xmlFreeDoc(doctree);
|
||||
|
||||
return NULL;
|
||||
@ -540,7 +542,8 @@ xmlXPathObjectPtr
|
||||
}
|
||||
|
||||
text
|
||||
*pgxml_result_to_text(xmlXPathObjectPtr res,
|
||||
*
|
||||
pgxml_result_to_text(xmlXPathObjectPtr res,
|
||||
xmlChar * toptag,
|
||||
xmlChar * septag,
|
||||
xmlChar * plainsep)
|
||||
@ -550,9 +553,7 @@ text
|
||||
text *xpres;
|
||||
|
||||
if (res == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
switch (res->type)
|
||||
{
|
||||
case XPATH_NODESET:
|
||||
@ -595,7 +596,8 @@ text
|
||||
|
||||
PG_FUNCTION_INFO_V1(xpath_table);
|
||||
|
||||
Datum xpath_table(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
xpath_table(PG_FUNCTION_ARGS)
|
||||
{
|
||||
/* SPI (input tuple) support */
|
||||
SPITupleTable *tuptable;
|
||||
@ -629,13 +631,15 @@ Datum xpath_table(PG_FUNCTION_ARGS)
|
||||
int proc;
|
||||
int i;
|
||||
int j;
|
||||
int rownr; /* For issuing multiple rows from one original document */
|
||||
int rownr; /* For issuing multiple rows from one
|
||||
* original document */
|
||||
int had_values; /* To determine end of nodeset results */
|
||||
|
||||
StringInfo querysql;
|
||||
|
||||
/* We only have a valid tuple description in table function mode */
|
||||
if (rsinfo->expectedDesc == NULL) {
|
||||
if (rsinfo->expectedDesc == NULL)
|
||||
{
|
||||
ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("xpath_table must be called as a table function")));
|
||||
}
|
||||
@ -657,17 +661,19 @@ Datum xpath_table(PG_FUNCTION_ARGS)
|
||||
/* get the requested return tuple description */
|
||||
ret_tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
|
||||
|
||||
/* At the moment we assume that the returned attributes make sense
|
||||
* for the XPath specififed (i.e. we trust the caller).
|
||||
* It's not fatal if they get it wrong - the input function for the
|
||||
* column type will raise an error if the path result can't be converted
|
||||
* into the correct binary representation.
|
||||
/*
|
||||
* At the moment we assume that the returned attributes make sense for
|
||||
* the XPath specififed (i.e. we trust the caller). It's not fatal if
|
||||
* they get it wrong - the input function for the column type will
|
||||
* raise an error if the path result can't be converted into the
|
||||
* correct binary representation.
|
||||
*/
|
||||
|
||||
attinmeta = TupleDescGetAttInMetadata(ret_tupdesc);
|
||||
|
||||
/* We want to materialise because it means that we don't have to
|
||||
* carry libxml2 parser state between invocations of this function
|
||||
/*
|
||||
* We want to materialise because it means that we don't have to carry
|
||||
* libxml2 parser state between invocations of this function
|
||||
*/
|
||||
|
||||
/* check to see if caller supports us returning a tuplestore */
|
||||
@ -676,7 +682,7 @@ Datum xpath_table(PG_FUNCTION_ARGS)
|
||||
errmsg("xpath_table requires Materialize mode, but it is not "
|
||||
"allowed in this context")));
|
||||
|
||||
// Set return mode and allocate value space.
|
||||
/* Set return mode and allocate value space. */
|
||||
rsinfo->returnMode = SFRM_Materialize;
|
||||
rsinfo->setDesc = ret_tupdesc;
|
||||
|
||||
@ -690,10 +696,12 @@ Datum xpath_table(PG_FUNCTION_ARGS)
|
||||
|
||||
numpaths = 0;
|
||||
pos = xpathset;
|
||||
do {
|
||||
do
|
||||
{
|
||||
xpaths[numpaths] = pos;
|
||||
pos = strstr(pos, pathsep);
|
||||
if (pos != NULL) {
|
||||
if (pos != NULL)
|
||||
{
|
||||
*pos = '\0';
|
||||
pos++;
|
||||
}
|
||||
@ -713,13 +721,11 @@ Datum xpath_table(PG_FUNCTION_ARGS)
|
||||
);
|
||||
|
||||
|
||||
if ((ret = SPI_connect()) < 0) {
|
||||
if ((ret = SPI_connect()) < 0)
|
||||
elog(ERROR, "xpath_table: SPI_connect returned %d", ret);
|
||||
}
|
||||
|
||||
if ((ret = SPI_exec(querysql->data,0)) != SPI_OK_SELECT) {
|
||||
if ((ret = SPI_exec(querysql->data, 0)) != SPI_OK_SELECT)
|
||||
elog(ERROR, "xpath_table: SPI execution failed for query %s", querysql->data);
|
||||
}
|
||||
|
||||
proc = SPI_processed;
|
||||
/* elog(DEBUG1,"xpath_table: SPI returned %d rows",proc); */
|
||||
@ -735,7 +741,8 @@ Datum xpath_table(PG_FUNCTION_ARGS)
|
||||
* e.g. 3 columns.
|
||||
*/
|
||||
|
||||
if (spi_tupdesc->natts != 2) {
|
||||
if (spi_tupdesc->natts != 2)
|
||||
{
|
||||
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("Expression returning multiple columns is not valid in parameter list"),
|
||||
errdetail("Expected two columns in SPI result, got %d", spi_tupdesc->natts)));
|
||||
@ -748,7 +755,8 @@ Datum xpath_table(PG_FUNCTION_ARGS)
|
||||
pgxml_parser_init();
|
||||
|
||||
/* For each row i.e. document returned from SPI */
|
||||
for (i=0; i < proc; i++) {
|
||||
for (i = 0; i < proc; i++)
|
||||
{
|
||||
char *pkey;
|
||||
char *xmldoc;
|
||||
|
||||
@ -767,14 +775,14 @@ Datum xpath_table(PG_FUNCTION_ARGS)
|
||||
xmldoc = SPI_getvalue(spi_tuple, spi_tupdesc, 2);
|
||||
|
||||
|
||||
/* Clear the values array, so that not-well-formed documents
|
||||
/*
|
||||
* Clear the values array, so that not-well-formed documents
|
||||
* return NULL in all columns.
|
||||
*/
|
||||
|
||||
/* Note that this also means that spare columns will be NULL. */
|
||||
for (j=0; j < ret_tupdesc->natts; j++) {
|
||||
for (j = 0; j < ret_tupdesc->natts; j++)
|
||||
values[j] = NULL;
|
||||
}
|
||||
|
||||
/* Insert primary key */
|
||||
values[0] = pkey;
|
||||
@ -783,7 +791,8 @@ Datum xpath_table(PG_FUNCTION_ARGS)
|
||||
doctree = xmlParseMemory(xmldoc, strlen(xmldoc));
|
||||
|
||||
if (doctree == NULL)
|
||||
{ /* not well-formed, so output all-NULL tuple */
|
||||
{ /* not well-formed, so output all-NULL
|
||||
* tuple */
|
||||
|
||||
ret_tuple = BuildTupleFromCStrings(attinmeta, values);
|
||||
oldcontext = MemoryContextSwitchTo(per_query_ctx);
|
||||
@ -796,10 +805,12 @@ Datum xpath_table(PG_FUNCTION_ARGS)
|
||||
/* New loop here - we have to deal with nodeset results */
|
||||
rownr = 0;
|
||||
|
||||
do {
|
||||
do
|
||||
{
|
||||
/* Now evaluate the set of xpaths. */
|
||||
had_values = 0;
|
||||
for (j=0; j < numpaths; j++) {
|
||||
for (j = 0; j < numpaths; j++)
|
||||
{
|
||||
|
||||
ctxt = xmlXPathNewContext(doctree);
|
||||
ctxt->node = xmlDocGetRootElement(doctree);
|
||||
@ -827,13 +838,14 @@ Datum xpath_table(PG_FUNCTION_ARGS)
|
||||
{
|
||||
case XPATH_NODESET:
|
||||
/* We see if this nodeset has enough nodes */
|
||||
if ((res->nodesetval != NULL) && (rownr < res->nodesetval->nodeNr)) {
|
||||
if ((res->nodesetval != NULL) && (rownr < res->nodesetval->nodeNr))
|
||||
{
|
||||
resstr =
|
||||
xmlXPathCastNodeToString(res->nodesetval->nodeTab[rownr]);
|
||||
had_values = 1;
|
||||
} else {
|
||||
resstr = NULL;
|
||||
}
|
||||
else
|
||||
resstr = NULL;
|
||||
|
||||
break;
|
||||
|
||||
@ -847,13 +859,17 @@ Datum xpath_table(PG_FUNCTION_ARGS)
|
||||
}
|
||||
|
||||
|
||||
// Insert this into the appropriate column in the result tuple.
|
||||
/*
|
||||
* Insert this into the appropriate column in the
|
||||
* result tuple.
|
||||
*/
|
||||
values[j + 1] = resstr;
|
||||
}
|
||||
xmlXPathFreeContext(ctxt);
|
||||
}
|
||||
// Now add the tuple to the output, if there is one.
|
||||
if (had_values) {
|
||||
/* Now add the tuple to the output, if there is one. */
|
||||
if (had_values)
|
||||
{
|
||||
ret_tuple = BuildTupleFromCStrings(attinmeta, values);
|
||||
oldcontext = MemoryContextSwitchTo(per_query_ctx);
|
||||
tuplestore_puttuple(tupstore, ret_tuple);
|
||||
|
@ -39,7 +39,9 @@ Datum xslt_process(PG_FUNCTION_ARGS);
|
||||
|
||||
PG_FUNCTION_INFO_V1(xslt_process);
|
||||
|
||||
Datum xslt_process(PG_FUNCTION_ARGS) {
|
||||
Datum
|
||||
xslt_process(PG_FUNCTION_ARGS)
|
||||
{
|
||||
|
||||
|
||||
const char *params[MAXPARAMS + 1]; /* +1 for the terminator */
|
||||
@ -62,10 +64,9 @@ Datum xslt_process(PG_FUNCTION_ARGS) {
|
||||
paramstr = PG_GETARG_TEXT_P(2);
|
||||
parse_params(params, paramstr);
|
||||
}
|
||||
else /* No parameters */
|
||||
{
|
||||
else
|
||||
/* No parameters */
|
||||
params[0] = NULL;
|
||||
}
|
||||
|
||||
/* Setup parser */
|
||||
pgxml_parser_init();
|
||||
@ -73,13 +74,9 @@ Datum xslt_process(PG_FUNCTION_ARGS) {
|
||||
/* Check to see if document is a file or a literal */
|
||||
|
||||
if (VARDATA(doct)[0] == '<')
|
||||
{
|
||||
doctree = xmlParseMemory((char *) VARDATA(doct), VARSIZE(doct) - VARHDRSZ);
|
||||
}
|
||||
else
|
||||
{
|
||||
doctree = xmlParseFile(GET_STR(doct));
|
||||
}
|
||||
|
||||
if (doctree == NULL)
|
||||
{
|
||||
@ -105,9 +102,7 @@ Datum xslt_process(PG_FUNCTION_ARGS) {
|
||||
stylesheet = xsltParseStylesheetDoc(ssdoc);
|
||||
}
|
||||
else
|
||||
{
|
||||
stylesheet = xsltParseStylesheetFile(GET_STR(ssheet));
|
||||
}
|
||||
|
||||
|
||||
if (stylesheet == NULL)
|
||||
@ -129,9 +124,8 @@ Datum xslt_process(PG_FUNCTION_ARGS) {
|
||||
xsltCleanupGlobals();
|
||||
xmlCleanupParser();
|
||||
|
||||
if (resstat < 0) {
|
||||
if (resstat < 0)
|
||||
PG_RETURN_NULL();
|
||||
}
|
||||
|
||||
tres = palloc(reslen + VARHDRSZ);
|
||||
memcpy(VARDATA(tres), resstr, reslen);
|
||||
@ -141,7 +135,8 @@ Datum xslt_process(PG_FUNCTION_ARGS) {
|
||||
}
|
||||
|
||||
|
||||
void parse_params(const char **params, text *paramstr)
|
||||
void
|
||||
parse_params(const char **params, text *paramstr)
|
||||
{
|
||||
char *pos;
|
||||
char *pstr;
|
||||
@ -158,10 +153,13 @@ void parse_params(const char **params, text *paramstr)
|
||||
{
|
||||
params[i] = pos;
|
||||
pos = strstr(pos, nvsep);
|
||||
if (pos != NULL) {
|
||||
if (pos != NULL)
|
||||
{
|
||||
*pos = '\0';
|
||||
pos++;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
params[i] = NULL;
|
||||
break;
|
||||
}
|
||||
@ -169,16 +167,15 @@ void parse_params(const char **params, text *paramstr)
|
||||
i++;
|
||||
params[i] = pos;
|
||||
pos = strstr(pos, itsep);
|
||||
if (pos != NULL) {
|
||||
if (pos != NULL)
|
||||
{
|
||||
*pos = '\0';
|
||||
pos++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
}
|
||||
if (i < MAXPARAMS)
|
||||
{
|
||||
params[i + 1] = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.93 2004/08/29 04:12:17 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.94 2004/08/29 05:06:39 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* The old interface functions have been converted to macros
|
||||
@ -468,13 +468,15 @@ heap_getsysattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
|
||||
break;
|
||||
|
||||
/*
|
||||
* If the attribute number is 0, then we are supposed to return
|
||||
* the entire tuple as a row-type Datum. (Using zero for this
|
||||
* purpose is unclean since it risks confusion with "invalid attr"
|
||||
* result codes, but it's not worth changing now.)
|
||||
* If the attribute number is 0, then we are supposed to
|
||||
* return the entire tuple as a row-type Datum. (Using zero
|
||||
* for this purpose is unclean since it risks confusion with
|
||||
* "invalid attr" result codes, but it's not worth changing
|
||||
* now.)
|
||||
*
|
||||
* We have to make a copy of the tuple so we can safely insert the
|
||||
* Datum overhead fields, which are not set in on-disk tuples.
|
||||
* We have to make a copy of the tuple so we can safely insert
|
||||
* the Datum overhead fields, which are not set in on-disk
|
||||
* tuples.
|
||||
*/
|
||||
case InvalidAttrNumber:
|
||||
{
|
||||
@ -683,9 +685,9 @@ heap_modifytuple(HeapTuple tuple,
|
||||
* allocate and fill values and nulls arrays from either the tuple or
|
||||
* the repl information, as appropriate.
|
||||
*
|
||||
* NOTE: it's debatable whether to use heap_deformtuple() here or
|
||||
* just heap_getattr() only the non-replaced colums. The latter could
|
||||
* win if there are many replaced columns and few non-replaced ones.
|
||||
* NOTE: it's debatable whether to use heap_deformtuple() here or just
|
||||
* heap_getattr() only the non-replaced colums. The latter could win
|
||||
* if there are many replaced columns and few non-replaced ones.
|
||||
* However, heap_deformtuple costs only O(N) while the heap_getattr
|
||||
* way would cost O(N^2) if there are many non-replaced columns, so it
|
||||
* seems better to err on the side of linear cost.
|
||||
@ -763,10 +765,11 @@ heap_deformtuple(HeapTuple tuple,
|
||||
bool slow = false; /* can we use/set attcacheoff? */
|
||||
|
||||
natts = tup->t_natts;
|
||||
|
||||
/*
|
||||
* In inheritance situations, it is possible that the given tuple actually
|
||||
* has more fields than the caller is expecting. Don't run off the end
|
||||
* of the caller's arrays.
|
||||
* In inheritance situations, it is possible that the given tuple
|
||||
* actually has more fields than the caller is expecting. Don't run
|
||||
* off the end of the caller's arrays.
|
||||
*/
|
||||
natts = Min(natts, tdesc_natts);
|
||||
|
||||
@ -787,9 +790,7 @@ heap_deformtuple(HeapTuple tuple,
|
||||
nulls[attnum] = ' ';
|
||||
|
||||
if (!slow && att[attnum]->attcacheoff >= 0)
|
||||
{
|
||||
off = att[attnum]->attcacheoff;
|
||||
}
|
||||
else
|
||||
{
|
||||
off = att_align(off, att[attnum]->attalign);
|
||||
@ -807,8 +808,8 @@ heap_deformtuple(HeapTuple tuple,
|
||||
}
|
||||
|
||||
/*
|
||||
* If tuple doesn't have all the atts indicated by tupleDesc, read
|
||||
* the rest as null
|
||||
* If tuple doesn't have all the atts indicated by tupleDesc, read the
|
||||
* rest as null
|
||||
*/
|
||||
for (; attnum < tdesc_natts; attnum++)
|
||||
{
|
||||
|
@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/common/indextuple.c,v 1.70 2004/08/29 04:12:17 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/common/indextuple.c,v 1.71 2004/08/29 05:06:39 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -9,7 +9,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/common/printtup.c,v 1.84 2004/08/29 04:12:17 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/common/printtup.c,v 1.85 2004/08/29 05:06:39 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.105 2004/08/29 04:12:17 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.106 2004/08/29 05:06:39 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* some of the executor utility code such as "ExecTypeFromTL" should be
|
||||
@ -52,8 +52,8 @@ CreateTemplateTupleDesc(int natts, bool hasoid)
|
||||
|
||||
/*
|
||||
* Allocate enough memory for the tuple descriptor, and zero the
|
||||
* attrs[] array since TupleDescInitEntry assumes that the array
|
||||
* is filled with NULL pointers.
|
||||
* attrs[] array since TupleDescInitEntry assumes that the array is
|
||||
* filled with NULL pointers.
|
||||
*/
|
||||
desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
|
||||
|
||||
@ -420,8 +420,8 @@ TupleDescInitEntry(TupleDesc desc,
|
||||
|
||||
/*
|
||||
* Note: attributeName can be NULL, because the planner doesn't always
|
||||
* fill in valid resname values in targetlists, particularly for resjunk
|
||||
* attributes.
|
||||
* fill in valid resname values in targetlists, particularly for
|
||||
* resjunk attributes.
|
||||
*/
|
||||
if (attributeName != NULL)
|
||||
namestrcpy(&(att->attname), attributeName);
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.110 2004/08/29 04:12:17 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.111 2004/08/29 05:06:40 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -940,8 +940,8 @@ gistunionsubkey(Relation r, GISTSTATE *giststate, IndexTuple *itvec, GIST_SPLITV
|
||||
else
|
||||
{
|
||||
/*
|
||||
* evec->vector[0].bytes may be not
|
||||
* defined, so form union with itself
|
||||
* evec->vector[0].bytes may be not defined, so form union
|
||||
* with itself
|
||||
*/
|
||||
if (reallen == 1)
|
||||
{
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistget.c,v 1.41 2004/08/29 04:12:17 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistget.c,v 1.42 2004/08/29 05:06:40 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -250,9 +250,10 @@ gistindex_keytest(IndexTuple tuple,
|
||||
FALSE, isNull);
|
||||
|
||||
/*
|
||||
* Call the Consistent function to evaluate the test. The arguments
|
||||
* are the index datum (as a GISTENTRY*), the comparison datum, and
|
||||
* the comparison operator's strategy number and subtype from pg_amop.
|
||||
* Call the Consistent function to evaluate the test. The
|
||||
* arguments are the index datum (as a GISTENTRY*), the comparison
|
||||
* datum, and the comparison operator's strategy number and
|
||||
* subtype from pg_amop.
|
||||
*
|
||||
* (Presently there's no need to pass the subtype since it'll always
|
||||
* be zero, but might as well pass it for possible future use.)
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistscan.c,v 1.54 2004/08/29 04:12:17 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistscan.c,v 1.55 2004/08/29 05:06:40 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -115,10 +115,8 @@ gistrescan(PG_FUNCTION_ARGS)
|
||||
* the sk_subtype field.
|
||||
*/
|
||||
for (i = 0; i < s->numberOfKeys; i++)
|
||||
{
|
||||
s->keyData[i].sk_func = p->giststate->consistentFn[s->keyData[i].sk_attno - 1];
|
||||
}
|
||||
}
|
||||
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
@ -266,9 +264,9 @@ ReleaseResources_gist(void)
|
||||
GISTScanList next;
|
||||
|
||||
/*
|
||||
* Note: this should be a no-op during normal query shutdown.
|
||||
* However, in an abort situation ExecutorEnd is not called and so
|
||||
* there may be open index scans to clean up.
|
||||
* Note: this should be a no-op during normal query shutdown. However,
|
||||
* in an abort situation ExecutorEnd is not called and so there may be
|
||||
* open index scans to clean up.
|
||||
*/
|
||||
prev = NULL;
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/hash/hash.c,v 1.72 2004/08/29 04:12:17 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/hash/hash.c,v 1.73 2004/08/29 05:06:40 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* This file contains only the public interface routines.
|
||||
@ -210,8 +210,8 @@ hashgettuple(PG_FUNCTION_ARGS)
|
||||
bool res;
|
||||
|
||||
/*
|
||||
* We hold pin but not lock on current buffer while outside the hash AM.
|
||||
* Reacquire the read lock here.
|
||||
* We hold pin but not lock on current buffer while outside the hash
|
||||
* AM. Reacquire the read lock here.
|
||||
*/
|
||||
if (BufferIsValid(so->hashso_curbuf))
|
||||
_hash_chgbufaccess(rel, so->hashso_curbuf, HASH_NOLOCK, HASH_READ);
|
||||
@ -595,8 +595,8 @@ loop_top:
|
||||
orig_ntuples == metap->hashm_ntuples)
|
||||
{
|
||||
/*
|
||||
* No one has split or inserted anything since start of scan,
|
||||
* so believe our count as gospel.
|
||||
* No one has split or inserted anything since start of scan, so
|
||||
* believe our count as gospel.
|
||||
*/
|
||||
metap->hashm_ntuples = num_index_tuples;
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/hash/hashinsert.c,v 1.33 2004/08/29 04:12:18 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/hash/hashinsert.c,v 1.34 2004/08/29 05:06:40 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -105,7 +105,8 @@ _hash_doinsert(Relation rel, HashItem hitem)
|
||||
_hash_chgbufaccess(rel, metabuf, HASH_READ, HASH_NOLOCK);
|
||||
|
||||
/*
|
||||
* Acquire share lock on target bucket; then we can release split lock.
|
||||
* Acquire share lock on target bucket; then we can release split
|
||||
* lock.
|
||||
*/
|
||||
_hash_getlock(rel, blkno, HASH_SHARE);
|
||||
|
||||
@ -169,8 +170,8 @@ _hash_doinsert(Relation rel, HashItem hitem)
|
||||
_hash_droplock(rel, blkno, HASH_SHARE);
|
||||
|
||||
/*
|
||||
* Write-lock the metapage so we can increment the tuple count.
|
||||
* After incrementing it, check to see if it's time for a split.
|
||||
* Write-lock the metapage so we can increment the tuple count. After
|
||||
* incrementing it, check to see if it's time for a split.
|
||||
*/
|
||||
_hash_chgbufaccess(rel, metabuf, HASH_NOLOCK, HASH_WRITE);
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/hash/hashovfl.c,v 1.43 2004/08/29 04:12:18 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/hash/hashovfl.c,v 1.44 2004/08/29 05:06:40 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Overflow pages look like ordinary relation pages.
|
||||
@ -44,8 +44,8 @@ bitno_to_blkno(HashMetaPage metap, uint32 ovflbitnum)
|
||||
/* loop */ ;
|
||||
|
||||
/*
|
||||
* Convert to absolute page number by adding the number of bucket pages
|
||||
* that exist before this split point.
|
||||
* Convert to absolute page number by adding the number of bucket
|
||||
* pages that exist before this split point.
|
||||
*/
|
||||
return (BlockNumber) ((1 << i) + ovflbitnum);
|
||||
}
|
||||
@ -274,9 +274,9 @@ _hash_getovflpage(Relation rel, Buffer metabuf)
|
||||
blkno = bitno_to_blkno(metap, bit);
|
||||
|
||||
/*
|
||||
* Adjust hashm_firstfree to avoid redundant searches. But don't
|
||||
* risk changing it if someone moved it while we were searching
|
||||
* bitmap pages.
|
||||
* Adjust hashm_firstfree to avoid redundant searches. But don't risk
|
||||
* changing it if someone moved it while we were searching bitmap
|
||||
* pages.
|
||||
*/
|
||||
if (metap->hashm_firstfree == orig_firstfree)
|
||||
metap->hashm_firstfree = bit + 1;
|
||||
@ -304,9 +304,9 @@ found:
|
||||
blkno = bitno_to_blkno(metap, bit);
|
||||
|
||||
/*
|
||||
* Adjust hashm_firstfree to avoid redundant searches. But don't
|
||||
* risk changing it if someone moved it while we were searching
|
||||
* bitmap pages.
|
||||
* Adjust hashm_firstfree to avoid redundant searches. But don't risk
|
||||
* changing it if someone moved it while we were searching bitmap
|
||||
* pages.
|
||||
*/
|
||||
if (metap->hashm_firstfree == orig_firstfree)
|
||||
{
|
||||
@ -488,7 +488,8 @@ _hash_initbitmap(Relation rel, HashMetaPage metap, BlockNumber blkno)
|
||||
|
||||
/*
|
||||
* It is okay to write-lock the new bitmap page while holding metapage
|
||||
* write lock, because no one else could be contending for the new page.
|
||||
* write lock, because no one else could be contending for the new
|
||||
* page.
|
||||
*
|
||||
* There is some loss of concurrency in possibly doing I/O for the new
|
||||
* page while holding the metapage lock, but this path is taken so
|
||||
@ -654,8 +655,8 @@ _hash_squeezebucket(Relation rel,
|
||||
|
||||
/*
|
||||
* delete the tuple from the "read" page. PageIndexTupleDelete
|
||||
* repacks the ItemId array, so 'roffnum' will be "advanced" to
|
||||
* the "next" ItemId.
|
||||
* repacks the ItemId array, so 'roffnum' will be "advanced"
|
||||
* to the "next" ItemId.
|
||||
*/
|
||||
PageIndexTupleDelete(rpage, roffnum);
|
||||
}
|
||||
@ -667,8 +668,9 @@ _hash_squeezebucket(Relation rel,
|
||||
* Tricky point here: if our read and write pages are adjacent in the
|
||||
* bucket chain, our write lock on wbuf will conflict with
|
||||
* _hash_freeovflpage's attempt to update the sibling links of the
|
||||
* removed page. However, in that case we are done anyway, so we can
|
||||
* simply drop the write lock before calling _hash_freeovflpage.
|
||||
* removed page. However, in that case we are done anyway, so we
|
||||
* can simply drop the write lock before calling
|
||||
* _hash_freeovflpage.
|
||||
*/
|
||||
if (PageIsEmpty(rpage))
|
||||
{
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/hash/hashpage.c,v 1.45 2004/08/29 04:12:18 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/hash/hashpage.c,v 1.46 2004/08/29 05:06:40 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Postgres hash pages look like ordinary relation pages. The opaque
|
||||
@ -239,10 +239,10 @@ _hash_metapinit(Relation rel)
|
||||
RelationGetRelationName(rel));
|
||||
|
||||
/*
|
||||
* Determine the target fill factor (tuples per bucket) for this index.
|
||||
* The idea is to make the fill factor correspond to pages about 3/4ths
|
||||
* full. We can compute it exactly if the index datatype is fixed-width,
|
||||
* but for var-width there's some guessing involved.
|
||||
* Determine the target fill factor (tuples per bucket) for this
|
||||
* index. The idea is to make the fill factor correspond to pages
|
||||
* about 3/4ths full. We can compute it exactly if the index datatype
|
||||
* is fixed-width, but for var-width there's some guessing involved.
|
||||
*/
|
||||
data_width = get_typavgwidth(RelationGetDescr(rel)->attrs[0]->atttypid,
|
||||
RelationGetDescr(rel)->attrs[0]->atttypmod);
|
||||
@ -288,8 +288,9 @@ _hash_metapinit(Relation rel)
|
||||
metap->hashm_procid = index_getprocid(rel, 1, HASHPROC);
|
||||
|
||||
/*
|
||||
* We initialize the index with two buckets, 0 and 1, occupying physical
|
||||
* blocks 1 and 2. The first freespace bitmap page is in block 3.
|
||||
* We initialize the index with two buckets, 0 and 1, occupying
|
||||
* physical blocks 1 and 2. The first freespace bitmap page is in
|
||||
* block 3.
|
||||
*/
|
||||
metap->hashm_maxbucket = metap->hashm_lowmask = 1; /* nbuckets - 1 */
|
||||
metap->hashm_highmask = 3; /* (nbuckets << 1) - 1 */
|
||||
@ -319,8 +320,8 @@ _hash_metapinit(Relation rel)
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize first bitmap page. Can't do this until we
|
||||
* create the first two buckets, else smgr will complain.
|
||||
* Initialize first bitmap page. Can't do this until we create the
|
||||
* first two buckets, else smgr will complain.
|
||||
*/
|
||||
_hash_initbitmap(rel, metap, 3);
|
||||
|
||||
@ -362,17 +363,18 @@ _hash_expandtable(Relation rel, Buffer metabuf)
|
||||
uint32 lowmask;
|
||||
|
||||
/*
|
||||
* Obtain the page-zero lock to assert the right to begin a split
|
||||
* (see README).
|
||||
* Obtain the page-zero lock to assert the right to begin a split (see
|
||||
* README).
|
||||
*
|
||||
* Note: deadlock should be impossible here. Our own backend could only
|
||||
* be holding bucket sharelocks due to stopped indexscans; those will not
|
||||
* block other holders of the page-zero lock, who are only interested in
|
||||
* acquiring bucket sharelocks themselves. Exclusive bucket locks are
|
||||
* only taken here and in hashbulkdelete, and neither of these operations
|
||||
* needs any additional locks to complete. (If, due to some flaw in this
|
||||
* reasoning, we manage to deadlock anyway, it's okay to error out; the
|
||||
* index will be left in a consistent state.)
|
||||
* be holding bucket sharelocks due to stopped indexscans; those will
|
||||
* not block other holders of the page-zero lock, who are only
|
||||
* interested in acquiring bucket sharelocks themselves. Exclusive
|
||||
* bucket locks are only taken here and in hashbulkdelete, and neither
|
||||
* of these operations needs any additional locks to complete. (If,
|
||||
* due to some flaw in this reasoning, we manage to deadlock anyway,
|
||||
* it's okay to error out; the index will be left in a consistent
|
||||
* state.)
|
||||
*/
|
||||
_hash_getlock(rel, 0, HASH_EXCLUSIVE);
|
||||
|
||||
@ -383,8 +385,8 @@ _hash_expandtable(Relation rel, Buffer metabuf)
|
||||
_hash_checkpage(rel, (Page) metap, LH_META_PAGE);
|
||||
|
||||
/*
|
||||
* Check to see if split is still needed; someone else might have already
|
||||
* done one while we waited for the lock.
|
||||
* Check to see if split is still needed; someone else might have
|
||||
* already done one while we waited for the lock.
|
||||
*
|
||||
* Make sure this stays in sync with_hash_doinsert()
|
||||
*/
|
||||
@ -399,11 +401,11 @@ _hash_expandtable(Relation rel, Buffer metabuf)
|
||||
* The lock protects us against other backends, but not against our own
|
||||
* backend. Must check for active scans separately.
|
||||
*
|
||||
* Ideally we would lock the new bucket too before proceeding, but if
|
||||
* we are about to cross a splitpoint then the BUCKET_TO_BLKNO mapping
|
||||
* Ideally we would lock the new bucket too before proceeding, but if we
|
||||
* are about to cross a splitpoint then the BUCKET_TO_BLKNO mapping
|
||||
* isn't correct yet. For simplicity we update the metapage first and
|
||||
* then lock. This should be okay because no one else should be trying
|
||||
* to lock the new bucket yet...
|
||||
* then lock. This should be okay because no one else should be
|
||||
* trying to lock the new bucket yet...
|
||||
*/
|
||||
new_bucket = metap->hashm_maxbucket + 1;
|
||||
old_bucket = (new_bucket & metap->hashm_lowmask);
|
||||
@ -417,7 +419,8 @@ _hash_expandtable(Relation rel, Buffer metabuf)
|
||||
goto fail;
|
||||
|
||||
/*
|
||||
* Okay to proceed with split. Update the metapage bucket mapping info.
|
||||
* Okay to proceed with split. Update the metapage bucket mapping
|
||||
* info.
|
||||
*/
|
||||
metap->hashm_maxbucket = new_bucket;
|
||||
|
||||
@ -431,11 +434,11 @@ _hash_expandtable(Relation rel, Buffer metabuf)
|
||||
/*
|
||||
* If the split point is increasing (hashm_maxbucket's log base 2
|
||||
* increases), we need to adjust the hashm_spares[] array and
|
||||
* hashm_ovflpoint so that future overflow pages will be created beyond
|
||||
* this new batch of bucket pages.
|
||||
* hashm_ovflpoint so that future overflow pages will be created
|
||||
* beyond this new batch of bucket pages.
|
||||
*
|
||||
* XXX should initialize new bucket pages to prevent out-of-order
|
||||
* page creation? Don't wanna do it right here though.
|
||||
* XXX should initialize new bucket pages to prevent out-of-order page
|
||||
* creation? Don't wanna do it right here though.
|
||||
*/
|
||||
spare_ndx = _hash_log2(metap->hashm_maxbucket + 1);
|
||||
if (spare_ndx > metap->hashm_ovflpoint)
|
||||
@ -456,9 +459,10 @@ _hash_expandtable(Relation rel, Buffer metabuf)
|
||||
/*
|
||||
* Copy bucket mapping info now; this saves re-accessing the meta page
|
||||
* inside _hash_splitbucket's inner loop. Note that once we drop the
|
||||
* split lock, other splits could begin, so these values might be out of
|
||||
* date before _hash_splitbucket finishes. That's okay, since all it
|
||||
* needs is to tell which of these two buckets to map hashkeys into.
|
||||
* split lock, other splits could begin, so these values might be out
|
||||
* of date before _hash_splitbucket finishes. That's okay, since all
|
||||
* it needs is to tell which of these two buckets to map hashkeys
|
||||
* into.
|
||||
*/
|
||||
maxbucket = metap->hashm_maxbucket;
|
||||
highmask = metap->hashm_highmask;
|
||||
@ -539,8 +543,8 @@ _hash_splitbucket(Relation rel,
|
||||
|
||||
/*
|
||||
* It should be okay to simultaneously write-lock pages from each
|
||||
* bucket, since no one else can be trying to acquire buffer lock
|
||||
* on pages of either bucket.
|
||||
* bucket, since no one else can be trying to acquire buffer lock on
|
||||
* pages of either bucket.
|
||||
*/
|
||||
oblkno = start_oblkno;
|
||||
nblkno = start_nblkno;
|
||||
@ -562,9 +566,9 @@ _hash_splitbucket(Relation rel,
|
||||
nopaque->hasho_filler = HASHO_FILL;
|
||||
|
||||
/*
|
||||
* Partition the tuples in the old bucket between the old bucket and the
|
||||
* new bucket, advancing along the old bucket's overflow bucket chain
|
||||
* and adding overflow pages to the new bucket as needed.
|
||||
* Partition the tuples in the old bucket between the old bucket and
|
||||
* the new bucket, advancing along the old bucket's overflow bucket
|
||||
* chain and adding overflow pages to the new bucket as needed.
|
||||
*/
|
||||
ooffnum = FirstOffsetNumber;
|
||||
omaxoffnum = PageGetMaxOffsetNumber(opage);
|
||||
@ -582,9 +586,10 @@ _hash_splitbucket(Relation rel,
|
||||
oblkno = oopaque->hasho_nextblkno;
|
||||
if (!BlockNumberIsValid(oblkno))
|
||||
break;
|
||||
|
||||
/*
|
||||
* we ran out of tuples on this particular page, but we
|
||||
* have more overflow pages; advance to next page.
|
||||
* we ran out of tuples on this particular page, but we have
|
||||
* more overflow pages; advance to next page.
|
||||
*/
|
||||
_hash_wrtbuf(rel, obuf);
|
||||
|
||||
@ -600,8 +605,8 @@ _hash_splitbucket(Relation rel,
|
||||
/*
|
||||
* Re-hash the tuple to determine which bucket it now belongs in.
|
||||
*
|
||||
* It is annoying to call the hash function while holding locks,
|
||||
* but releasing and relocking the page for each tuple is unappealing
|
||||
* It is annoying to call the hash function while holding locks, but
|
||||
* releasing and relocking the page for each tuple is unappealing
|
||||
* too.
|
||||
*/
|
||||
hitem = (HashItem) PageGetItem(opage, PageGetItemId(opage, ooffnum));
|
||||
@ -666,10 +671,11 @@ _hash_splitbucket(Relation rel,
|
||||
}
|
||||
|
||||
/*
|
||||
* We're at the end of the old bucket chain, so we're done partitioning
|
||||
* the tuples. Before quitting, call _hash_squeezebucket to ensure the
|
||||
* tuples remaining in the old bucket (including the overflow pages) are
|
||||
* packed as tightly as possible. The new bucket is already tight.
|
||||
* We're at the end of the old bucket chain, so we're done
|
||||
* partitioning the tuples. Before quitting, call _hash_squeezebucket
|
||||
* to ensure the tuples remaining in the old bucket (including the
|
||||
* overflow pages) are packed as tightly as possible. The new bucket
|
||||
* is already tight.
|
||||
*/
|
||||
_hash_wrtbuf(rel, obuf);
|
||||
_hash_wrtbuf(rel, nbuf);
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/hash/hashscan.c,v 1.36 2004/08/29 04:12:18 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/hash/hashscan.c,v 1.37 2004/08/29 05:06:40 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -44,9 +44,9 @@ ReleaseResources_hash(void)
|
||||
HashScanList next;
|
||||
|
||||
/*
|
||||
* Note: this should be a no-op during normal query shutdown.
|
||||
* However, in an abort situation ExecutorEnd is not called and so
|
||||
* there may be open index scans to clean up.
|
||||
* Note: this should be a no-op during normal query shutdown. However,
|
||||
* in an abort situation ExecutorEnd is not called and so there may be
|
||||
* open index scans to clean up.
|
||||
*/
|
||||
prev = NULL;
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/hash/hashsearch.c,v 1.36 2004/08/29 04:12:18 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/hash/hashsearch.c,v 1.37 2004/08/29 05:06:40 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -137,7 +137,8 @@ _hash_first(IndexScanDesc scan, ScanDirection dir)
|
||||
* We do not support hash scans with no index qualification, because
|
||||
* we would have to read the whole index rather than just one bucket.
|
||||
* That creates a whole raft of problems, since we haven't got a
|
||||
* practical way to lock all the buckets against splits or compactions.
|
||||
* practical way to lock all the buckets against splits or
|
||||
* compactions.
|
||||
*/
|
||||
if (scan->numberOfKeys < 1)
|
||||
ereport(ERROR,
|
||||
@ -182,7 +183,8 @@ _hash_first(IndexScanDesc scan, ScanDirection dir)
|
||||
_hash_relbuf(rel, metabuf);
|
||||
|
||||
/*
|
||||
* Acquire share lock on target bucket; then we can release split lock.
|
||||
* Acquire share lock on target bucket; then we can release split
|
||||
* lock.
|
||||
*/
|
||||
_hash_getlock(rel, blkno, HASH_SHARE);
|
||||
|
||||
@ -287,9 +289,8 @@ _hash_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
|
||||
while (offnum > maxoff)
|
||||
{
|
||||
/*
|
||||
* either this page is empty
|
||||
* (maxoff == InvalidOffsetNumber)
|
||||
* or we ran off the end.
|
||||
* either this page is empty (maxoff ==
|
||||
* InvalidOffsetNumber) or we ran off the end.
|
||||
*/
|
||||
_hash_readnext(rel, &buf, &page, &opaque);
|
||||
if (BufferIsValid(buf))
|
||||
@ -315,15 +316,12 @@ _hash_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
|
||||
while (offnum < FirstOffsetNumber)
|
||||
{
|
||||
/*
|
||||
* either this page is empty
|
||||
* (offnum == InvalidOffsetNumber)
|
||||
* or we ran off the end.
|
||||
* either this page is empty (offnum ==
|
||||
* InvalidOffsetNumber) or we ran off the end.
|
||||
*/
|
||||
_hash_readprev(rel, &buf, &page, &opaque);
|
||||
if (BufferIsValid(buf))
|
||||
{
|
||||
maxoff = offnum = PageGetMaxOffsetNumber(page);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* end of bucket */
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/hash/hashutil.c,v 1.39 2004/08/29 04:12:18 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/hash/hashutil.c,v 1.40 2004/08/29 05:06:40 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -113,6 +113,7 @@ void
|
||||
_hash_checkpage(Relation rel, Page page, int flags)
|
||||
{
|
||||
Assert(page);
|
||||
|
||||
/*
|
||||
* When checking the metapage, always verify magic number and version.
|
||||
*/
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.172 2004/08/29 04:12:20 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.173 2004/08/29 05:06:40 momjian Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
@ -75,9 +75,9 @@ initscan(HeapScanDesc scan, ScanKey key)
|
||||
/*
|
||||
* Determine the number of blocks we have to scan.
|
||||
*
|
||||
* It is sufficient to do this once at scan start, since any tuples
|
||||
* added while the scan is in progress will be invisible to my
|
||||
* transaction anyway...
|
||||
* It is sufficient to do this once at scan start, since any tuples added
|
||||
* while the scan is in progress will be invisible to my transaction
|
||||
* anyway...
|
||||
*/
|
||||
scan->rs_nblocks = RelationGetNumberOfBlocks(scan->rs_rd);
|
||||
|
||||
@ -1146,7 +1146,8 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid)
|
||||
|
||||
/*
|
||||
* If the new tuple is too big for storage or contains already toasted
|
||||
* out-of-line attributes from some other relation, invoke the toaster.
|
||||
* out-of-line attributes from some other relation, invoke the
|
||||
* toaster.
|
||||
*/
|
||||
if (HeapTupleHasExternal(tup) ||
|
||||
(MAXALIGN(tup->t_len) > TOAST_TUPLE_THRESHOLD))
|
||||
@ -1404,9 +1405,9 @@ l1:
|
||||
|
||||
/*
|
||||
* If the tuple has toasted out-of-line attributes, we need to delete
|
||||
* those items too. We have to do this before WriteBuffer because we need
|
||||
* to look at the contents of the tuple, but it's OK to release the
|
||||
* context lock on the buffer first.
|
||||
* those items too. We have to do this before WriteBuffer because we
|
||||
* need to look at the contents of the tuple, but it's OK to release
|
||||
* the context lock on the buffer first.
|
||||
*/
|
||||
if (HeapTupleHasExternal(&tp))
|
||||
heap_tuple_toast_attrs(relation, NULL, &tp);
|
||||
@ -2198,8 +2199,8 @@ heap_xlog_newpage(bool redo, XLogRecPtr lsn, XLogRecord *record)
|
||||
Page page;
|
||||
|
||||
/*
|
||||
* Note: the NEWPAGE log record is used for both heaps and indexes,
|
||||
* so do not do anything that assumes we are touching a heap.
|
||||
* Note: the NEWPAGE log record is used for both heaps and indexes, so
|
||||
* do not do anything that assumes we are touching a heap.
|
||||
*/
|
||||
|
||||
if (!redo || (record->xl_info & XLR_BKP_BLOCK_1))
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.44 2004/08/29 04:12:20 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.45 2004/08/29 05:06:40 momjian Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
@ -288,13 +288,13 @@ toast_delete(Relation rel, HeapTuple oldtup)
|
||||
/*
|
||||
* Get the tuple descriptor and break down the tuple into fields.
|
||||
*
|
||||
* NOTE: it's debatable whether to use heap_deformtuple() here or
|
||||
* just heap_getattr() only the varlena columns. The latter could
|
||||
* win if there are few varlena columns and many non-varlena ones.
|
||||
* However, heap_deformtuple costs only O(N) while the heap_getattr
|
||||
* way would cost O(N^2) if there are many varlena columns, so it
|
||||
* seems better to err on the side of linear cost. (We won't even
|
||||
* be here unless there's at least one varlena column, by the way.)
|
||||
* NOTE: it's debatable whether to use heap_deformtuple() here or just
|
||||
* heap_getattr() only the varlena columns. The latter could win if
|
||||
* there are few varlena columns and many non-varlena ones. However,
|
||||
* heap_deformtuple costs only O(N) while the heap_getattr way would
|
||||
* cost O(N^2) if there are many varlena columns, so it seems better
|
||||
* to err on the side of linear cost. (We won't even be here unless
|
||||
* there's at least one varlena column, by the way.)
|
||||
*/
|
||||
tupleDesc = rel->rd_att;
|
||||
att = tupleDesc->attrs;
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.115 2004/08/29 04:12:21 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.116 2004/08/29 05:06:40 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -200,23 +200,23 @@ _bt_check_unique(Relation rel, BTItem btitem, Relation heapRel,
|
||||
* We can skip items that are marked killed.
|
||||
*
|
||||
* Formerly, we applied _bt_isequal() before checking the kill
|
||||
* flag, so as to fall out of the item loop as soon as possible.
|
||||
* However, in the presence of heavy update activity an index
|
||||
* may contain many killed items with the same key; running
|
||||
* _bt_isequal() on each killed item gets expensive. Furthermore
|
||||
* it is likely that the non-killed version of each key appears
|
||||
* first, so that we didn't actually get to exit any sooner anyway.
|
||||
* So now we just advance over killed items as quickly as we can.
|
||||
* We only apply _bt_isequal() when we get to a non-killed item or
|
||||
* the end of the page.
|
||||
* flag, so as to fall out of the item loop as soon as
|
||||
* possible. However, in the presence of heavy update activity
|
||||
* an index may contain many killed items with the same key;
|
||||
* running _bt_isequal() on each killed item gets expensive.
|
||||
* Furthermore it is likely that the non-killed version of
|
||||
* each key appears first, so that we didn't actually get to
|
||||
* exit any sooner anyway. So now we just advance over killed
|
||||
* items as quickly as we can. We only apply _bt_isequal()
|
||||
* when we get to a non-killed item or the end of the page.
|
||||
*/
|
||||
if (!ItemIdDeleted(curitemid))
|
||||
{
|
||||
/*
|
||||
* _bt_compare returns 0 for (1,NULL) and (1,NULL) - this's
|
||||
* how we handling NULLs - and so we must not use _bt_compare
|
||||
* in real comparison, but only for ordering/finding items on
|
||||
* pages. - vadim 03/24/97
|
||||
* _bt_compare returns 0 for (1,NULL) and (1,NULL) -
|
||||
* this's how we handling NULLs - and so we must not use
|
||||
* _bt_compare in real comparison, but only for
|
||||
* ordering/finding items on pages. - vadim 03/24/97
|
||||
*/
|
||||
if (!_bt_isequal(itupdesc, page, offset, natts, itup_scankey))
|
||||
break; /* we're past all the equal tuples */
|
||||
|
@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtpage.c,v 1.79 2004/08/29 04:12:21 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtpage.c,v 1.80 2004/08/29 05:06:40 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Postgres btree pages look like ordinary relation pages. The opaque
|
||||
@ -276,8 +276,8 @@ _bt_getroot(Relation rel, int access)
|
||||
rootlevel = metad->btm_fastlevel;
|
||||
|
||||
/*
|
||||
* We are done with the metapage; arrange to release it via
|
||||
* first _bt_relandgetbuf call
|
||||
* We are done with the metapage; arrange to release it via first
|
||||
* _bt_relandgetbuf call
|
||||
*/
|
||||
rootbuf = metabuf;
|
||||
|
||||
@ -368,8 +368,8 @@ _bt_gettrueroot(Relation rel)
|
||||
rootlevel = metad->btm_level;
|
||||
|
||||
/*
|
||||
* We are done with the metapage; arrange to release it via
|
||||
* first _bt_relandgetbuf call
|
||||
* We are done with the metapage; arrange to release it via first
|
||||
* _bt_relandgetbuf call
|
||||
*/
|
||||
rootbuf = metabuf;
|
||||
|
||||
@ -433,21 +433,22 @@ _bt_getbuf(Relation rel, BlockNumber blkno, int access)
|
||||
* page could have been re-used between the time the last VACUUM
|
||||
* scanned it and the time the VACUUM made its FSM updates.)
|
||||
*
|
||||
* In fact, it's worse than that: we can't even assume that it's
|
||||
* safe to take a lock on the reported page. If somebody else
|
||||
* has a lock on it, or even worse our own caller does, we could
|
||||
* In fact, it's worse than that: we can't even assume that it's safe
|
||||
* to take a lock on the reported page. If somebody else has a
|
||||
* lock on it, or even worse our own caller does, we could
|
||||
* deadlock. (The own-caller scenario is actually not improbable.
|
||||
* Consider an index on a serial or timestamp column. Nearly all
|
||||
* splits will be at the rightmost page, so it's entirely likely
|
||||
* that _bt_split will call us while holding a lock on the page most
|
||||
* recently acquired from FSM. A VACUUM running concurrently with
|
||||
* the previous split could well have placed that page back in FSM.)
|
||||
* that _bt_split will call us while holding a lock on the page
|
||||
* most recently acquired from FSM. A VACUUM running concurrently
|
||||
* with the previous split could well have placed that page back
|
||||
* in FSM.)
|
||||
*
|
||||
* To get around that, we ask for only a conditional lock on the
|
||||
* reported page. If we fail, then someone else is using the page,
|
||||
* and we may reasonably assume it's not free. (If we happen to be
|
||||
* wrong, the worst consequence is the page will be lost to use till
|
||||
* the next VACUUM, which is no big problem.)
|
||||
* reported page. If we fail, then someone else is using the
|
||||
* page, and we may reasonably assume it's not free. (If we
|
||||
* happen to be wrong, the worst consequence is the page will be
|
||||
* lost to use till the next VACUUM, which is no big problem.)
|
||||
*/
|
||||
for (;;)
|
||||
{
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.88 2004/08/29 04:12:21 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.89 2004/08/29 05:06:40 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -155,15 +155,16 @@ _bt_moveright(Relation rel,
|
||||
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||
|
||||
/*
|
||||
* When nextkey = false (normal case): if the scan key that brought us to
|
||||
* this page is > the high key stored on the page, then the page has split
|
||||
* and we need to move right. (If the scan key is equal to the high key,
|
||||
* we might or might not need to move right; have to scan the page first
|
||||
* anyway.)
|
||||
* When nextkey = false (normal case): if the scan key that brought us
|
||||
* to this page is > the high key stored on the page, then the page
|
||||
* has split and we need to move right. (If the scan key is equal to
|
||||
* the high key, we might or might not need to move right; have to
|
||||
* scan the page first anyway.)
|
||||
*
|
||||
* When nextkey = true: move right if the scan key is >= page's high key.
|
||||
*
|
||||
* The page could even have split more than once, so scan as far as needed.
|
||||
* The page could even have split more than once, so scan as far as
|
||||
* needed.
|
||||
*
|
||||
* We also have to move right if we followed a link that brought us to a
|
||||
* dead page.
|
||||
@ -253,13 +254,11 @@ _bt_binsrch(Relation rel,
|
||||
* Binary search to find the first key on the page >= scan key, or
|
||||
* first key > scankey when nextkey is true.
|
||||
*
|
||||
* For nextkey=false (cmpval=1), the loop invariant is: all slots
|
||||
* before 'low' are < scan key, all slots at or after 'high'
|
||||
* are >= scan key.
|
||||
* For nextkey=false (cmpval=1), the loop invariant is: all slots before
|
||||
* 'low' are < scan key, all slots at or after 'high' are >= scan key.
|
||||
*
|
||||
* For nextkey=true (cmpval=0), the loop invariant is: all slots
|
||||
* before 'low' are <= scan key, all slots at or after 'high'
|
||||
* are > scan key.
|
||||
* For nextkey=true (cmpval=0), the loop invariant is: all slots before
|
||||
* 'low' are <= scan key, all slots at or after 'high' are > scan key.
|
||||
*
|
||||
* We can fall out when high == low.
|
||||
*/
|
||||
@ -285,15 +284,15 @@ _bt_binsrch(Relation rel,
|
||||
* At this point we have high == low, but be careful: they could point
|
||||
* past the last slot on the page.
|
||||
*
|
||||
* On a leaf page, we always return the first key >= scan key (resp.
|
||||
* > scan key), which could be the last slot + 1.
|
||||
* On a leaf page, we always return the first key >= scan key (resp. >
|
||||
* scan key), which could be the last slot + 1.
|
||||
*/
|
||||
if (P_ISLEAF(opaque))
|
||||
return low;
|
||||
|
||||
/*
|
||||
* On a non-leaf page, return the last key < scan key (resp. <= scan key).
|
||||
* There must be one if _bt_compare() is playing by the rules.
|
||||
* On a non-leaf page, return the last key < scan key (resp. <= scan
|
||||
* key). There must be one if _bt_compare() is playing by the rules.
|
||||
*/
|
||||
Assert(low > P_FIRSTDATAKEY(opaque));
|
||||
|
||||
@ -382,10 +381,10 @@ _bt_compare(Relation rel,
|
||||
{
|
||||
/*
|
||||
* The sk_func needs to be passed the index value as left arg
|
||||
* and the sk_argument as right arg (they might be of different
|
||||
* types). Since it is convenient for callers to think of
|
||||
* _bt_compare as comparing the scankey to the index item,
|
||||
* we have to flip the sign of the comparison result.
|
||||
* and the sk_argument as right arg (they might be of
|
||||
* different types). Since it is convenient for callers to
|
||||
* think of _bt_compare as comparing the scankey to the index
|
||||
* item, we have to flip the sign of the comparison result.
|
||||
*
|
||||
* Note: curious-looking coding is to avoid overflow if
|
||||
* comparison function returns INT_MIN. There is no risk of
|
||||
@ -554,13 +553,15 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||
ScanKey cur;
|
||||
|
||||
startKeys = (ScanKey *) palloc(so->numberOfKeys * sizeof(ScanKey));
|
||||
|
||||
/*
|
||||
* chosen is the so-far-chosen key for the current attribute, if any.
|
||||
* We don't cast the decision in stone until we reach keys for the
|
||||
* next attribute.
|
||||
* chosen is the so-far-chosen key for the current attribute, if
|
||||
* any. We don't cast the decision in stone until we reach keys
|
||||
* for the next attribute.
|
||||
*/
|
||||
curattr = 1;
|
||||
chosen = NULL;
|
||||
|
||||
/*
|
||||
* Loop iterates from 0 to numberOfKeys inclusive; we use the last
|
||||
* pass to handle after-last-key processing. Actual exit from the
|
||||
@ -578,8 +579,10 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||
if (chosen == NULL)
|
||||
break;
|
||||
startKeys[keysCount++] = chosen;
|
||||
|
||||
/*
|
||||
* Adjust strat_total, and quit if we have stored a > or < key.
|
||||
* Adjust strat_total, and quit if we have stored a > or <
|
||||
* key.
|
||||
*/
|
||||
strat = chosen->sk_strategy;
|
||||
if (strat != BTEqualStrategyNumber)
|
||||
@ -589,11 +592,13 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||
strat == BTLessStrategyNumber)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Done if that was the last attribute.
|
||||
*/
|
||||
if (i >= so->numberOfKeys)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Reset for next attr, which should be in sequence.
|
||||
*/
|
||||
@ -646,8 +651,8 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||
ScanKey cur = startKeys[i];
|
||||
|
||||
/*
|
||||
* _bt_preprocess_keys disallows it, but it's place to add some code
|
||||
* later
|
||||
* _bt_preprocess_keys disallows it, but it's place to add some
|
||||
* code later
|
||||
*/
|
||||
if (cur->sk_flags & SK_ISNULL)
|
||||
{
|
||||
@ -656,10 +661,11 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||
elog(ERROR, "btree doesn't support is(not)null, yet");
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* If scankey operator is of default subtype, we can use the
|
||||
* cached comparison procedure; otherwise gotta look it up in
|
||||
* the catalogs.
|
||||
* cached comparison procedure; otherwise gotta look it up in the
|
||||
* catalogs.
|
||||
*/
|
||||
if (cur->sk_subtype == InvalidOid)
|
||||
{
|
||||
@ -695,43 +701,46 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||
|
||||
/*
|
||||
* Examine the selected initial-positioning strategy to determine
|
||||
* exactly where we need to start the scan, and set flag variables
|
||||
* to control the code below.
|
||||
* exactly where we need to start the scan, and set flag variables to
|
||||
* control the code below.
|
||||
*
|
||||
* If nextkey = false, _bt_search and _bt_binsrch will locate the
|
||||
* first item >= scan key. If nextkey = true, they will locate the
|
||||
* first item > scan key.
|
||||
* If nextkey = false, _bt_search and _bt_binsrch will locate the first
|
||||
* item >= scan key. If nextkey = true, they will locate the first
|
||||
* item > scan key.
|
||||
*
|
||||
* If goback = true, we will then step back one item, while if
|
||||
* goback = false, we will start the scan on the located item.
|
||||
* If goback = true, we will then step back one item, while if goback =
|
||||
* false, we will start the scan on the located item.
|
||||
*
|
||||
* it's yet other place to add some code later for is(not)null ...
|
||||
*/
|
||||
switch (strat_total)
|
||||
{
|
||||
case BTLessStrategyNumber:
|
||||
|
||||
/*
|
||||
* Find first item >= scankey, then back up one to arrive at last
|
||||
* item < scankey. (Note: this positioning strategy is only used
|
||||
* for a backward scan, so that is always the correct starting
|
||||
* position.)
|
||||
* Find first item >= scankey, then back up one to arrive at
|
||||
* last item < scankey. (Note: this positioning strategy is
|
||||
* only used for a backward scan, so that is always the
|
||||
* correct starting position.)
|
||||
*/
|
||||
nextkey = false;
|
||||
goback = true;
|
||||
break;
|
||||
|
||||
case BTLessEqualStrategyNumber:
|
||||
|
||||
/*
|
||||
* Find first item > scankey, then back up one to arrive at last
|
||||
* item <= scankey. (Note: this positioning strategy is only used
|
||||
* for a backward scan, so that is always the correct starting
|
||||
* position.)
|
||||
* Find first item > scankey, then back up one to arrive at
|
||||
* last item <= scankey. (Note: this positioning strategy is
|
||||
* only used for a backward scan, so that is always the
|
||||
* correct starting position.)
|
||||
*/
|
||||
nextkey = true;
|
||||
goback = true;
|
||||
break;
|
||||
|
||||
case BTEqualStrategyNumber:
|
||||
|
||||
/*
|
||||
* If a backward scan was specified, need to start with last
|
||||
* equal item not first one.
|
||||
@ -739,8 +748,8 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||
if (ScanDirectionIsBackward(dir))
|
||||
{
|
||||
/*
|
||||
* This is the same as the <= strategy. We will check
|
||||
* at the end whether the found item is actually =.
|
||||
* This is the same as the <= strategy. We will check at
|
||||
* the end whether the found item is actually =.
|
||||
*/
|
||||
nextkey = true;
|
||||
goback = true;
|
||||
@ -748,8 +757,8 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||
else
|
||||
{
|
||||
/*
|
||||
* This is the same as the >= strategy. We will check
|
||||
* at the end whether the found item is actually =.
|
||||
* This is the same as the >= strategy. We will check at
|
||||
* the end whether the found item is actually =.
|
||||
*/
|
||||
nextkey = false;
|
||||
goback = false;
|
||||
@ -757,18 +766,20 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||
break;
|
||||
|
||||
case BTGreaterEqualStrategyNumber:
|
||||
|
||||
/*
|
||||
* Find first item >= scankey. (This is only used for
|
||||
* forward scans.)
|
||||
* Find first item >= scankey. (This is only used for forward
|
||||
* scans.)
|
||||
*/
|
||||
nextkey = false;
|
||||
goback = false;
|
||||
break;
|
||||
|
||||
case BTGreaterStrategyNumber:
|
||||
|
||||
/*
|
||||
* Find first item > scankey. (This is only used for
|
||||
* forward scans.)
|
||||
* Find first item > scankey. (This is only used for forward
|
||||
* scans.)
|
||||
*/
|
||||
nextkey = true;
|
||||
goback = false;
|
||||
@ -814,23 +825,23 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||
pfree(scankeys);
|
||||
|
||||
/*
|
||||
* If nextkey = false, we are positioned at the first item >= scan key,
|
||||
* or possibly at the end of a page on which all the existing items are
|
||||
* less than the scan key and we know that everything on later pages
|
||||
* is greater than or equal to scan key.
|
||||
* If nextkey = false, we are positioned at the first item >= scan
|
||||
* key, or possibly at the end of a page on which all the existing
|
||||
* items are less than the scan key and we know that everything on
|
||||
* later pages is greater than or equal to scan key.
|
||||
*
|
||||
* If nextkey = true, we are positioned at the first item > scan key,
|
||||
* or possibly at the end of a page on which all the existing items are
|
||||
* If nextkey = true, we are positioned at the first item > scan key, or
|
||||
* possibly at the end of a page on which all the existing items are
|
||||
* less than or equal to the scan key and we know that everything on
|
||||
* later pages is greater than scan key.
|
||||
*
|
||||
* The actually desired starting point is either this item or the prior
|
||||
* one, or in the end-of-page case it's the first item on the next page
|
||||
* or the last item on this page. We apply _bt_step if needed to get to
|
||||
* the right place.
|
||||
* one, or in the end-of-page case it's the first item on the next
|
||||
* page or the last item on this page. We apply _bt_step if needed to
|
||||
* get to the right place.
|
||||
*
|
||||
* If _bt_step fails (meaning we fell off the end of the index in
|
||||
* one direction or the other), then there are no matches so we just
|
||||
* If _bt_step fails (meaning we fell off the end of the index in one
|
||||
* direction or the other), then there are no matches so we just
|
||||
* return false.
|
||||
*/
|
||||
if (goback)
|
||||
@ -1292,7 +1303,8 @@ _bt_endpoint(IndexScanDesc scan, ScanDirection dir)
|
||||
itup = &(btitem->bti_itup);
|
||||
|
||||
/*
|
||||
* Okay, we are on the first or last tuple. Does it pass all the quals?
|
||||
* Okay, we are on the first or last tuple. Does it pass all the
|
||||
* quals?
|
||||
*/
|
||||
if (_bt_checkkeys(scan, itup, dir, &continuescan))
|
||||
{
|
||||
|
@ -56,7 +56,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsort.c,v 1.87 2004/08/29 04:12:21 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsort.c,v 1.88 2004/08/29 05:06:40 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -157,12 +157,12 @@ _bt_spoolinit(Relation index, bool isunique, bool isdead)
|
||||
btspool->isunique = isunique;
|
||||
|
||||
/*
|
||||
* We size the sort area as maintenance_work_mem rather than work_mem to
|
||||
* speed index creation. This should be OK since a single backend can't
|
||||
* run multiple index creations in parallel. Note that creation of a
|
||||
* unique index actually requires two BTSpool objects. We expect that the
|
||||
* second one (for dead tuples) won't get very full, so we give it only
|
||||
* work_mem.
|
||||
* We size the sort area as maintenance_work_mem rather than work_mem
|
||||
* to speed index creation. This should be OK since a single backend
|
||||
* can't run multiple index creations in parallel. Note that creation
|
||||
* of a unique index actually requires two BTSpool objects. We expect
|
||||
* that the second one (for dead tuples) won't get very full, so we
|
||||
* give it only work_mem.
|
||||
*/
|
||||
btKbytes = isdead ? work_mem : maintenance_work_mem;
|
||||
btspool->sortstate = tuplesort_begin_index(index, isunique,
|
||||
@ -220,6 +220,7 @@ _bt_leafbuild(BTSpool *btspool, BTSpool *btspool2)
|
||||
tuplesort_performsort(btspool2->sortstate);
|
||||
|
||||
wstate.index = btspool->index;
|
||||
|
||||
/*
|
||||
* We need to log index creation in WAL iff WAL archiving is enabled
|
||||
* AND it's not a temp index.
|
||||
@ -313,8 +314,8 @@ _bt_blwritepage(BTWriteState *wstate, Page page, BlockNumber blkno)
|
||||
* If we have to write pages nonsequentially, fill in the space with
|
||||
* zeroes until we come back and overwrite. This is not logically
|
||||
* necessary on standard Unix filesystems (unwritten space will read
|
||||
* as zeroes anyway), but it should help to avoid fragmentation.
|
||||
* The dummy pages aren't WAL-logged though.
|
||||
* as zeroes anyway), but it should help to avoid fragmentation. The
|
||||
* dummy pages aren't WAL-logged though.
|
||||
*/
|
||||
while (blkno > wstate->btws_pages_written)
|
||||
{
|
||||
@ -326,9 +327,9 @@ _bt_blwritepage(BTWriteState *wstate, Page page, BlockNumber blkno)
|
||||
}
|
||||
|
||||
/*
|
||||
* Now write the page. We say isTemp = true even if it's not a
|
||||
* temp index, because there's no need for smgr to schedule an fsync
|
||||
* for this write; we'll do it ourselves before ending the build.
|
||||
* Now write the page. We say isTemp = true even if it's not a temp
|
||||
* index, because there's no need for smgr to schedule an fsync for
|
||||
* this write; we'll do it ourselves before ending the build.
|
||||
*/
|
||||
smgrwrite(wstate->index->rd_smgr, blkno, (char *) page, true);
|
||||
|
||||
@ -539,8 +540,8 @@ _bt_buildadd(BTWriteState *wstate, BTPageState *state, BTItem bti)
|
||||
((PageHeader) opage)->pd_lower -= sizeof(ItemIdData);
|
||||
|
||||
/*
|
||||
* Link the old page into its parent, using its minimum key. If
|
||||
* we don't have a parent, we have to create one; this adds a new
|
||||
* Link the old page into its parent, using its minimum key. If we
|
||||
* don't have a parent, we have to create one; this adds a new
|
||||
* btree level.
|
||||
*/
|
||||
if (state->btps_next == NULL)
|
||||
@ -572,8 +573,8 @@ _bt_buildadd(BTWriteState *wstate, BTPageState *state, BTItem bti)
|
||||
}
|
||||
|
||||
/*
|
||||
* Write out the old page. We never need to touch it again,
|
||||
* so we can free the opage workspace too.
|
||||
* Write out the old page. We never need to touch it again, so we
|
||||
* can free the opage workspace too.
|
||||
*/
|
||||
_bt_blwritepage(wstate, opage, oblkno);
|
||||
|
||||
@ -663,9 +664,9 @@ _bt_uppershutdown(BTWriteState *wstate, BTPageState *state)
|
||||
|
||||
/*
|
||||
* As the last step in the process, construct the metapage and make it
|
||||
* point to the new root (unless we had no data at all, in which case it's
|
||||
* set to point to "P_NONE"). This changes the index to the "valid"
|
||||
* state by filling in a valid magic number in the metapage.
|
||||
* point to the new root (unless we had no data at all, in which case
|
||||
* it's set to point to "P_NONE"). This changes the index to the
|
||||
* "valid" state by filling in a valid magic number in the metapage.
|
||||
*/
|
||||
metapage = (Page) palloc(BLCKSZ);
|
||||
_bt_initmetapage(metapage, rootblkno, rootlevel);
|
||||
@ -805,15 +806,15 @@ _bt_load(BTWriteState *wstate, BTSpool *btspool, BTSpool *btspool2)
|
||||
* safe to commit the transaction. (For a temp 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 less obvious that we have to do it even if we did WAL-log the
|
||||
* index pages. The reason is that since we're building outside
|
||||
* shared buffers, a CHECKPOINT occurring during the build has no way
|
||||
* to flush the previously written data to disk (indeed it won't know
|
||||
* the index even exists). A crash later on would replay WAL from the
|
||||
* It's obvious that we must do this when not WAL-logging the build. It's
|
||||
* less obvious that we have to do it even if we did WAL-log the index
|
||||
* pages. The reason is that since we're building outside shared
|
||||
* buffers, a CHECKPOINT occurring during the build has no way to
|
||||
* flush the previously written data to disk (indeed it won't know the
|
||||
* index even exists). A crash later on would replay WAL from the
|
||||
* checkpoint, therefore it wouldn't replay our earlier WAL entries.
|
||||
* If we do not fsync those pages here, they might still not be on disk
|
||||
* when the crash occurs.
|
||||
* If we do not fsync those pages here, they might still not be on
|
||||
* disk when the crash occurs.
|
||||
*/
|
||||
if (!wstate->index->rd_istemp)
|
||||
smgrimmedsync(wstate->index->rd_smgr);
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.59 2004/08/29 04:12:21 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.60 2004/08/29 05:06:40 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -48,8 +48,8 @@ _bt_mkscankey(Relation rel, IndexTuple itup)
|
||||
bool null;
|
||||
|
||||
/*
|
||||
* We can use the cached (default) support procs since no cross-type
|
||||
* comparison can be needed.
|
||||
* We can use the cached (default) support procs since no
|
||||
* cross-type comparison can be needed.
|
||||
*/
|
||||
procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);
|
||||
arg = index_getattr(itup, i + 1, itupdesc, &null);
|
||||
@ -93,8 +93,8 @@ _bt_mkscankey_nodata(Relation rel)
|
||||
FmgrInfo *procinfo;
|
||||
|
||||
/*
|
||||
* We can use the cached (default) support procs since no cross-type
|
||||
* comparison can be needed.
|
||||
* We can use the cached (default) support procs since no
|
||||
* cross-type comparison can be needed.
|
||||
*/
|
||||
procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);
|
||||
ScanKeyEntryInitializeWithInfo(&skey[i],
|
||||
@ -285,9 +285,9 @@ _bt_preprocess_keys(IndexScanDesc scan)
|
||||
*
|
||||
* xform[i] points to the currently best scan key of strategy type i+1,
|
||||
* if any is found with a default operator subtype; it is NULL if we
|
||||
* haven't yet found such a key for this attr. Scan keys of nondefault
|
||||
* subtypes are transferred to the output with no processing except for
|
||||
* noting if they are of "=" type.
|
||||
* haven't yet found such a key for this attr. Scan keys of
|
||||
* nondefault subtypes are transferred to the output with no
|
||||
* processing except for noting if they are of "=" type.
|
||||
*/
|
||||
attno = 1;
|
||||
memset(xform, 0, sizeof(xform));
|
||||
@ -545,21 +545,23 @@ _bt_checkkeys(IndexScanDesc scan, IndexTuple tuple,
|
||||
{
|
||||
/*
|
||||
* Tuple fails this qual. If it's a required qual, then we
|
||||
* may be able to conclude no further tuples will pass, either.
|
||||
* We have to look at the scan direction and the qual type.
|
||||
* may be able to conclude no further tuples will pass,
|
||||
* either. We have to look at the scan direction and the qual
|
||||
* type.
|
||||
*
|
||||
* Note: the only case in which we would keep going after failing
|
||||
* a required qual is if there are partially-redundant quals that
|
||||
* _bt_preprocess_keys() was unable to eliminate. For example,
|
||||
* given "x > 4 AND x > 10" where both are cross-type comparisons
|
||||
* and so not removable, we might start the scan at the x = 4
|
||||
* boundary point. The "x > 10" condition will fail until we
|
||||
* pass x = 10, but we must not stop the scan on its account.
|
||||
* a required qual is if there are partially-redundant quals
|
||||
* that _bt_preprocess_keys() was unable to eliminate. For
|
||||
* example, given "x > 4 AND x > 10" where both are cross-type
|
||||
* comparisons and so not removable, we might start the scan
|
||||
* at the x = 4 boundary point. The "x > 10" condition will
|
||||
* fail until we pass x = 10, but we must not stop the scan on
|
||||
* its account.
|
||||
*
|
||||
* Note: because we stop the scan as soon as any required equality
|
||||
* qual fails, it is critical that equality quals be used for the
|
||||
* initial positioning in _bt_first() when they are available.
|
||||
* See comments in _bt_first().
|
||||
* Note: because we stop the scan as soon as any required
|
||||
* equality qual fails, it is critical that equality quals be
|
||||
* used for the initial positioning in _bt_first() when they
|
||||
* are available. See comments in _bt_first().
|
||||
*/
|
||||
if (ikey < so->numberOfRequiredKeys)
|
||||
{
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtxlog.c,v 1.17 2004/08/29 04:12:21 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtxlog.c,v 1.18 2004/08/29 05:06:40 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/rtree/rtscan.c,v 1.54 2004/08/29 04:12:22 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/rtree/rtscan.c,v 1.55 2004/08/29 05:06:40 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -285,9 +285,9 @@ ReleaseResources_rtree(void)
|
||||
RTScanList next;
|
||||
|
||||
/*
|
||||
* Note: this should be a no-op during normal query shutdown.
|
||||
* However, in an abort situation ExecutorEnd is not called and so
|
||||
* there may be open index scans to clean up.
|
||||
* Note: this should be a no-op during normal query shutdown. However,
|
||||
* in an abort situation ExecutorEnd is not called and so there may be
|
||||
* open index scans to clean up.
|
||||
*/
|
||||
prev = NULL;
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/clog.c,v 1.24 2004/08/29 04:12:23 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/clog.c,v 1.25 2004/08/29 05:06:40 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -62,6 +62,7 @@
|
||||
* Link to shared-memory data structures for CLOG control
|
||||
*/
|
||||
static SlruCtlData ClogCtlData;
|
||||
|
||||
#define ClogCtl (&ClogCtlData)
|
||||
|
||||
|
||||
|
@ -48,7 +48,7 @@
|
||||
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/slru.c,v 1.20 2004/08/29 04:12:23 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/slru.c,v 1.21 2004/08/29 05:06:40 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -527,16 +527,17 @@ SlruPhysicalWritePage(SlruCtl ctl, int pageno, int slotno, SlruFlush fdata)
|
||||
{
|
||||
/*
|
||||
* If the file doesn't already exist, we should create it. It is
|
||||
* possible for this to need to happen when writing a page that's not
|
||||
* first in its segment; we assume the OS can cope with that.
|
||||
* (Note: it might seem that it'd be okay to create files only when
|
||||
* SimpleLruZeroPage is called for the first page of a segment.
|
||||
* However, if after a crash and restart the REDO logic elects to
|
||||
* replay the log from a checkpoint before the latest one, then it's
|
||||
* possible that we will get commands to set transaction status of
|
||||
* transactions that have already been truncated from the commit log.
|
||||
* Easiest way to deal with that is to accept references to
|
||||
* nonexistent files here and in SlruPhysicalReadPage.)
|
||||
* possible for this to need to happen when writing a page that's
|
||||
* not first in its segment; we assume the OS can cope with that.
|
||||
* (Note: it might seem that it'd be okay to create files only
|
||||
* when SimpleLruZeroPage is called for the first page of a
|
||||
* segment. However, if after a crash and restart the REDO logic
|
||||
* elects to replay the log from a checkpoint before the latest
|
||||
* one, then it's possible that we will get commands to set
|
||||
* transaction status of transactions that have already been
|
||||
* truncated from the commit log. Easiest way to deal with that is
|
||||
* to accept references to nonexistent files here and in
|
||||
* SlruPhysicalReadPage.)
|
||||
*/
|
||||
SlruFileName(ctl, path, segno);
|
||||
fd = BasicOpenFile(path, O_RDWR | PG_BINARY, S_IRUSR | S_IWUSR);
|
||||
@ -841,8 +842,8 @@ SimpleLruTruncate(SlruCtl ctl, int cutoffPage)
|
||||
/*
|
||||
* Scan shared memory and remove any pages preceding the cutoff page,
|
||||
* to ensure we won't rewrite them later. (Since this is normally
|
||||
* called in or just after a checkpoint, any dirty pages should
|
||||
* have been flushed already ... we're just being extra careful here.)
|
||||
* called in or just after a checkpoint, any dirty pages should have
|
||||
* been flushed already ... we're just being extra careful here.)
|
||||
*/
|
||||
LWLockAcquire(shared->ControlLock, LW_EXCLUSIVE);
|
||||
|
||||
@ -952,8 +953,11 @@ SlruScanDirectory(SlruCtl ctl, int cutoffPage, bool doDeletions)
|
||||
errno = 0;
|
||||
}
|
||||
#ifdef WIN32
|
||||
/* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but
|
||||
not in released version */
|
||||
|
||||
/*
|
||||
* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but
|
||||
* not in released version
|
||||
*/
|
||||
if (GetLastError() == ERROR_NO_MORE_FILES)
|
||||
errno = 0;
|
||||
#endif
|
||||
|
@ -22,7 +22,7 @@
|
||||
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/subtrans.c,v 1.4 2004/08/29 04:12:23 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/subtrans.c,v 1.5 2004/08/29 05:06:40 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -57,6 +57,7 @@
|
||||
* Link to shared-memory data structures for SUBTRANS control
|
||||
*/
|
||||
static SlruCtlData SubTransCtlData;
|
||||
|
||||
#define SubTransCtl (&SubTransCtlData)
|
||||
|
||||
|
||||
@ -229,10 +230,11 @@ StartupSUBTRANS(void)
|
||||
int startPage;
|
||||
|
||||
/*
|
||||
* Since we don't expect pg_subtrans to be valid across crashes,
|
||||
* we initialize the currently-active page to zeroes during startup.
|
||||
* Since we don't expect pg_subtrans to be valid across crashes, we
|
||||
* initialize the currently-active page to zeroes during startup.
|
||||
* Whenever we advance into a new page, ExtendSUBTRANS will likewise
|
||||
* zero the new page without regard to whatever was previously on disk.
|
||||
* zero the new page without regard to whatever was previously on
|
||||
* disk.
|
||||
*/
|
||||
LWLockAcquire(SubtransControlLock, LW_EXCLUSIVE);
|
||||
|
||||
@ -251,8 +253,8 @@ ShutdownSUBTRANS(void)
|
||||
/*
|
||||
* Flush dirty SUBTRANS pages to disk
|
||||
*
|
||||
* This is not actually necessary from a correctness point of view.
|
||||
* We do it merely as a debugging aid.
|
||||
* This is not actually necessary from a correctness point of view. We do
|
||||
* it merely as a debugging aid.
|
||||
*/
|
||||
SimpleLruFlush(SubTransCtl, false);
|
||||
}
|
||||
@ -266,8 +268,8 @@ CheckPointSUBTRANS(void)
|
||||
/*
|
||||
* Flush dirty SUBTRANS pages to disk
|
||||
*
|
||||
* This is not actually necessary from a correctness point of view.
|
||||
* We do it merely to improve the odds that writing of dirty pages is done
|
||||
* This is not actually necessary from a correctness point of view. We do
|
||||
* it merely to improve the odds that writing of dirty pages is done
|
||||
* by the checkpoint process and not by backends.
|
||||
*/
|
||||
SimpleLruFlush(SubTransCtl, true);
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/transam.c,v 1.60 2004/08/29 04:12:23 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/transam.c,v 1.61 2004/08/29 05:06:40 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* This file contains the high level access-method interface to the
|
||||
@ -199,9 +199,10 @@ TransactionIdDidCommit(TransactionId transactionId)
|
||||
return true;
|
||||
|
||||
/*
|
||||
* If it's marked subcommitted, we have to check the parent recursively.
|
||||
* However, if it's older than RecentXmin, we can't look at pg_subtrans;
|
||||
* instead assume that the parent crashed without cleaning up its children.
|
||||
* If it's marked subcommitted, we have to check the parent
|
||||
* recursively. However, if it's older than RecentXmin, we can't look
|
||||
* at pg_subtrans; instead assume that the parent crashed without
|
||||
* cleaning up its children.
|
||||
*/
|
||||
if (xidstatus == TRANSACTION_STATUS_SUB_COMMITTED)
|
||||
{
|
||||
@ -247,9 +248,10 @@ TransactionIdDidAbort(TransactionId transactionId)
|
||||
return true;
|
||||
|
||||
/*
|
||||
* If it's marked subcommitted, we have to check the parent recursively.
|
||||
* However, if it's older than RecentXmin, we can't look at pg_subtrans;
|
||||
* instead assume that the parent crashed without cleaning up its children.
|
||||
* If it's marked subcommitted, we have to check the parent
|
||||
* recursively. However, if it's older than RecentXmin, we can't look
|
||||
* at pg_subtrans; instead assume that the parent crashed without
|
||||
* cleaning up its children.
|
||||
*/
|
||||
if (xidstatus == TRANSACTION_STATUS_SUB_COMMITTED)
|
||||
{
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Copyright (c) 2000-2004, PostgreSQL Global Development Group
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/varsup.c,v 1.58 2004/08/29 04:12:23 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/varsup.c,v 1.59 2004/08/29 05:06:40 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -47,9 +47,9 @@ GetNewTransactionId(bool isSubXact)
|
||||
xid = ShmemVariableCache->nextXid;
|
||||
|
||||
/*
|
||||
* If we are allocating the first XID of a new page of the commit
|
||||
* log, zero out that commit-log page before returning. We must do
|
||||
* this while holding XidGenLock, else another xact could acquire and
|
||||
* If we are allocating the first XID of a new page of the commit log,
|
||||
* zero out that commit-log page before returning. We must do this
|
||||
* while holding XidGenLock, else another xact could acquire and
|
||||
* commit a later XID before we zero the page. Fortunately, a page of
|
||||
* the commit log holds 32K or more transactions, so we don't have to
|
||||
* do this very often.
|
||||
@ -61,17 +61,18 @@ GetNewTransactionId(bool isSubXact)
|
||||
|
||||
/*
|
||||
* Now advance the nextXid counter. This must not happen until after
|
||||
* we have successfully completed ExtendCLOG() --- if that routine fails,
|
||||
* we want the next incoming transaction to try it again. We cannot
|
||||
* assign more XIDs until there is CLOG space for them.
|
||||
* we have successfully completed ExtendCLOG() --- if that routine
|
||||
* fails, we want the next incoming transaction to try it again. We
|
||||
* cannot assign more XIDs until there is CLOG space for them.
|
||||
*/
|
||||
TransactionIdAdvance(ShmemVariableCache->nextXid);
|
||||
|
||||
/*
|
||||
* We must store the new XID into the shared PGPROC array before releasing
|
||||
* XidGenLock. This ensures that when GetSnapshotData calls
|
||||
* We must store the new XID into the shared PGPROC array before
|
||||
* releasing XidGenLock. This ensures that when GetSnapshotData calls
|
||||
* ReadNewTransactionId, all active XIDs before the returned value of
|
||||
* nextXid are already present in PGPROC. Else we have a race condition.
|
||||
* nextXid are already present in PGPROC. Else we have a race
|
||||
* condition.
|
||||
*
|
||||
* XXX by storing xid into MyProc without acquiring SInvalLock, we are
|
||||
* relying on fetch/store of an xid to be atomic, else other backends
|
||||
@ -91,14 +92,14 @@ GetNewTransactionId(bool isSubXact)
|
||||
*
|
||||
* If there's no room to fit a subtransaction XID into PGPROC, set the
|
||||
* cache-overflowed flag instead. This forces readers to look in
|
||||
* pg_subtrans to map subtransaction XIDs up to top-level XIDs.
|
||||
* There is a race-condition window, in that the new XID will not
|
||||
* appear as running until its parent link has been placed into
|
||||
* pg_subtrans. However, that will happen before anyone could possibly
|
||||
* have a reason to inquire about the status of the XID, so it seems
|
||||
* OK. (Snapshots taken during this window *will* include the parent
|
||||
* XID, so they will deliver the correct answer later on when someone
|
||||
* does have a reason to inquire.)
|
||||
* pg_subtrans to map subtransaction XIDs up to top-level XIDs. There
|
||||
* is a race-condition window, in that the new XID will not appear as
|
||||
* running until its parent link has been placed into pg_subtrans.
|
||||
* However, that will happen before anyone could possibly have a
|
||||
* reason to inquire about the status of the XID, so it seems OK.
|
||||
* (Snapshots taken during this window *will* include the parent XID,
|
||||
* so they will deliver the correct answer later on when someone does
|
||||
* have a reason to inquire.)
|
||||
*/
|
||||
if (MyProc != NULL)
|
||||
{
|
||||
@ -112,11 +113,9 @@ GetNewTransactionId(bool isSubXact)
|
||||
MyProc->subxids.nxids++;
|
||||
}
|
||||
else
|
||||
{
|
||||
MyProc->subxids.overflowed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LWLockRelease(XidGenLock);
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.182 2004/08/29 04:12:23 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.183 2004/08/29 05:06:40 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -96,7 +96,8 @@ typedef struct TransactionStateData
|
||||
TransState state; /* low-level state */
|
||||
TBlockState blockState; /* high-level state */
|
||||
int nestingLevel; /* nest depth */
|
||||
MemoryContext curTransactionContext; /* my xact-lifetime context */
|
||||
MemoryContext curTransactionContext; /* my xact-lifetime
|
||||
* context */
|
||||
ResourceOwner curTransactionOwner; /* my query resources */
|
||||
List *childXids; /* subcommitted child XIDs */
|
||||
AclId currentUser; /* subxact start current_user */
|
||||
@ -362,11 +363,11 @@ TransactionIdIsCurrentTransactionId(TransactionId xid)
|
||||
}
|
||||
|
||||
/*
|
||||
* We will return true for the Xid of the current subtransaction,
|
||||
* any of its subcommitted children, any of its parents, or any of
|
||||
* their previously subcommitted children. However, a transaction
|
||||
* being aborted is no longer "current", even though it may still
|
||||
* have an entry on the state stack.
|
||||
* We will return true for the Xid of the current subtransaction, any
|
||||
* of its subcommitted children, any of its parents, or any of their
|
||||
* previously subcommitted children. However, a transaction being
|
||||
* aborted is no longer "current", even though it may still have an
|
||||
* entry on the state stack.
|
||||
*/
|
||||
for (s = CurrentTransactionState; s != NULL; s = s->parent)
|
||||
{
|
||||
@ -502,9 +503,10 @@ AtSubStart_Memory(void)
|
||||
Assert(CurTransactionContext != NULL);
|
||||
|
||||
/*
|
||||
* Create a CurTransactionContext, which will be used to hold data that
|
||||
* survives subtransaction commit but disappears on subtransaction abort.
|
||||
* We make it a child of the immediate parent's CurTransactionContext.
|
||||
* Create a CurTransactionContext, which will be used to hold data
|
||||
* that survives subtransaction commit but disappears on
|
||||
* subtransaction abort. We make it a child of the immediate parent's
|
||||
* CurTransactionContext.
|
||||
*/
|
||||
CurTransactionContext = AllocSetContextCreate(CurTransactionContext,
|
||||
"CurTransactionContext",
|
||||
@ -528,8 +530,8 @@ AtSubStart_ResourceOwner(void)
|
||||
Assert(s->parent != NULL);
|
||||
|
||||
/*
|
||||
* Create a resource owner for the subtransaction. We make it a
|
||||
* child of the immediate parent's resource owner.
|
||||
* Create a resource owner for the subtransaction. We make it a child
|
||||
* of the immediate parent's resource owner.
|
||||
*/
|
||||
s->curTransactionOwner =
|
||||
ResourceOwnerCreate(s->parent->curTransactionOwner,
|
||||
@ -560,10 +562,11 @@ RecordTransactionCommit(void)
|
||||
nchildren = xactGetCommittedChildren(&children);
|
||||
|
||||
/*
|
||||
* If we made neither any XLOG entries nor any temp-rel updates,
|
||||
* and have no files to be deleted, we can omit recording the transaction
|
||||
* If we made neither any XLOG entries nor any temp-rel updates, and
|
||||
* have no files to be deleted, we can omit recording the transaction
|
||||
* commit at all. (This test includes the effects of subtransactions,
|
||||
* so the presence of committed subxacts need not alone force a write.)
|
||||
* so the presence of committed subxacts need not alone force a
|
||||
* write.)
|
||||
*/
|
||||
if (MyXactMadeXLogEntry || MyXactMadeTempRelUpdate || nrels > 0)
|
||||
{
|
||||
@ -577,17 +580,18 @@ RecordTransactionCommit(void)
|
||||
START_CRIT_SECTION();
|
||||
|
||||
/*
|
||||
* If our transaction made any transaction-controlled XLOG entries,
|
||||
* we need to lock out checkpoint start between writing our XLOG
|
||||
* record and updating pg_clog. Otherwise it is possible for the
|
||||
* checkpoint to set REDO after the XLOG record but fail to flush the
|
||||
* pg_clog update to disk, leading to loss of the transaction commit
|
||||
* if we crash a little later. Slightly klugy fix for problem
|
||||
* discovered 2004-08-10.
|
||||
* If our transaction made any transaction-controlled XLOG
|
||||
* entries, we need to lock out checkpoint start between writing
|
||||
* our XLOG record and updating pg_clog. Otherwise it is possible
|
||||
* for the checkpoint to set REDO after the XLOG record but fail
|
||||
* to flush the pg_clog update to disk, leading to loss of the
|
||||
* transaction commit if we crash a little later. Slightly klugy
|
||||
* fix for problem discovered 2004-08-10.
|
||||
*
|
||||
* (If it made no transaction-controlled XLOG entries, its XID
|
||||
* appears nowhere in permanent storage, so no one else will ever care
|
||||
* if it committed; so it doesn't matter if we lose the commit flag.)
|
||||
* appears nowhere in permanent storage, so no one else will ever
|
||||
* care if it committed; so it doesn't matter if we lose the
|
||||
* commit flag.)
|
||||
*
|
||||
* Note we only need a shared lock.
|
||||
*/
|
||||
@ -798,16 +802,16 @@ static void
|
||||
RecordSubTransactionCommit(void)
|
||||
{
|
||||
/*
|
||||
* We do not log the subcommit in XLOG; it doesn't matter until
|
||||
* the top-level transaction commits.
|
||||
* We do not log the subcommit in XLOG; it doesn't matter until the
|
||||
* top-level transaction commits.
|
||||
*
|
||||
* We must mark the subtransaction subcommitted in clog if its XID
|
||||
* appears either in permanent rels or in local temporary rels. We
|
||||
* test this by seeing if we made transaction-controlled entries
|
||||
* *OR* local-rel tuple updates. (The test here actually covers the
|
||||
* entire transaction tree so far, so it may mark subtransactions that
|
||||
* don't really need it, but it's probably not worth being tenser.
|
||||
* Note that if a prior subtransaction dirtied these variables, then
|
||||
* test this by seeing if we made transaction-controlled entries *OR*
|
||||
* local-rel tuple updates. (The test here actually covers the entire
|
||||
* transaction tree so far, so it may mark subtransactions that don't
|
||||
* really need it, but it's probably not worth being tenser. Note that
|
||||
* if a prior subtransaction dirtied these variables, then
|
||||
* RecordTransactionCommit will have to do the full pushup anyway...)
|
||||
*/
|
||||
if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate)
|
||||
@ -846,9 +850,9 @@ RecordTransactionAbort(void)
|
||||
|
||||
/*
|
||||
* If we made neither any transaction-controlled XLOG entries nor any
|
||||
* temp-rel updates, and are not going to delete any files, we can omit
|
||||
* recording the transaction abort at all. No one will ever care that
|
||||
* it aborted. (These tests cover our whole transaction tree.)
|
||||
* temp-rel updates, and are not going to delete any files, we can
|
||||
* omit recording the transaction abort at all. No one will ever care
|
||||
* that it aborted. (These tests cover our whole transaction tree.)
|
||||
*/
|
||||
if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate || nrels > 0)
|
||||
{
|
||||
@ -867,13 +871,13 @@ RecordTransactionAbort(void)
|
||||
* We only need to log the abort in XLOG if the transaction made
|
||||
* any transaction-controlled XLOG entries or will delete files.
|
||||
* (If it made no transaction-controlled XLOG entries, its XID
|
||||
* appears nowhere in permanent storage, so no one else will ever care
|
||||
* if it committed.)
|
||||
* appears nowhere in permanent storage, so no one else will ever
|
||||
* care if it committed.)
|
||||
*
|
||||
* We do not flush XLOG to disk unless deleting files, since the
|
||||
* default assumption after a crash would be that we aborted, anyway.
|
||||
* For the same reason, we don't need to worry about interlocking
|
||||
* against checkpoint start.
|
||||
* default assumption after a crash would be that we aborted,
|
||||
* anyway. For the same reason, we don't need to worry about
|
||||
* interlocking against checkpoint start.
|
||||
*/
|
||||
if (MyLastRecPtr.xrecoff != 0 || nrels > 0)
|
||||
{
|
||||
@ -1000,10 +1004,10 @@ RecordSubTransactionAbort(void)
|
||||
|
||||
/*
|
||||
* If we made neither any transaction-controlled XLOG entries nor any
|
||||
* temp-rel updates, and are not going to delete any files, we can omit
|
||||
* recording the transaction abort at all. No one will ever care that
|
||||
* it aborted. (These tests cover our whole transaction tree, and
|
||||
* therefore may mark subxacts that don't really need it, but it's
|
||||
* temp-rel updates, and are not going to delete any files, we can
|
||||
* omit recording the transaction abort at all. No one will ever care
|
||||
* that it aborted. (These tests cover our whole transaction tree,
|
||||
* and therefore may mark subxacts that don't really need it, but it's
|
||||
* probably not worth being tenser.)
|
||||
*
|
||||
* In this case we needn't worry about marking subcommitted children as
|
||||
@ -1071,8 +1075,8 @@ RecordSubTransactionAbort(void)
|
||||
/*
|
||||
* We can immediately remove failed XIDs from PGPROC's cache of
|
||||
* running child XIDs. It's easiest to do it here while we have the
|
||||
* child XID array at hand, even though in the main-transaction
|
||||
* case the equivalent work happens just after return from
|
||||
* child XID array at hand, even though in the main-transaction case
|
||||
* the equivalent work happens just after return from
|
||||
* RecordTransactionAbort.
|
||||
*/
|
||||
XidCacheRemoveRunningXids(xid, nchildren, children);
|
||||
@ -1169,7 +1173,8 @@ StartTransaction(void)
|
||||
s->state = TRANS_START;
|
||||
|
||||
/*
|
||||
* Make sure we've freed any old snapshot, and reset xact state variables
|
||||
* Make sure we've freed any old snapshot, and reset xact state
|
||||
* variables
|
||||
*/
|
||||
FreeXactSnapshot();
|
||||
XactIsoLevel = DefaultXactIsoLevel;
|
||||
@ -1323,9 +1328,9 @@ CommitTransaction(void)
|
||||
* want to release locks at the point where any backend waiting for us
|
||||
* will see our transaction as being fully cleaned up.
|
||||
*
|
||||
* Resources that can be associated with individual queries are
|
||||
* handled by the ResourceOwner mechanism. The other calls here
|
||||
* are for backend-wide state.
|
||||
* Resources that can be associated with individual queries are handled
|
||||
* by the ResourceOwner mechanism. The other calls here are for
|
||||
* backend-wide state.
|
||||
*/
|
||||
|
||||
smgrDoPendingDeletes(true);
|
||||
@ -1342,7 +1347,8 @@ CommitTransaction(void)
|
||||
* after relcache references are dropped (see comments for
|
||||
* AtEOXact_RelationCache), but before locks are released (if anyone
|
||||
* is waiting for lock on a relation we've modified, we want them to
|
||||
* know about the catalog change before they start using the relation).
|
||||
* know about the catalog change before they start using the
|
||||
* relation).
|
||||
*/
|
||||
AtEOXact_Inval(true);
|
||||
|
||||
@ -1428,7 +1434,8 @@ AbortTransaction(void)
|
||||
|
||||
/*
|
||||
* Reset user id which might have been changed transiently. We cannot
|
||||
* use s->currentUser, but must get the session userid from miscinit.c.
|
||||
* use s->currentUser, but must get the session userid from
|
||||
* miscinit.c.
|
||||
*
|
||||
* (Note: it is not necessary to restore session authorization here
|
||||
* because that can only be changed via GUC, and GUC will take care of
|
||||
@ -1561,9 +1568,10 @@ StartTransactionCommand(void)
|
||||
break;
|
||||
|
||||
/*
|
||||
* This is the case when we are somewhere in a transaction block
|
||||
* and about to start a new command. For now we do nothing
|
||||
* but someday we may do command-local resource initialization.
|
||||
* This is the case when we are somewhere in a transaction
|
||||
* block and about to start a new command. For now we do
|
||||
* nothing but someday we may do command-local resource
|
||||
* initialization.
|
||||
*/
|
||||
case TBLOCK_INPROGRESS:
|
||||
case TBLOCK_SUBINPROGRESS:
|
||||
@ -1616,8 +1624,8 @@ CommitTransactionCommand(void)
|
||||
/*
|
||||
* This shouldn't happen, because it means the previous
|
||||
* StartTransactionCommand didn't set the STARTED state
|
||||
* appropriately, or we didn't manage previous pending
|
||||
* abort states.
|
||||
* appropriately, or we didn't manage previous pending abort
|
||||
* states.
|
||||
*/
|
||||
case TBLOCK_DEFAULT:
|
||||
case TBLOCK_SUBABORT_PENDING:
|
||||
@ -1694,14 +1702,16 @@ CommitTransactionCommand(void)
|
||||
*/
|
||||
case TBLOCK_SUBENDABORT_ALL:
|
||||
AbortOutOfAnyTransaction();
|
||||
s = CurrentTransactionState; /* changed by AbortOutOfAnyTransaction */
|
||||
s = CurrentTransactionState; /* changed by
|
||||
* AbortOutOfAnyTransaction
|
||||
* */
|
||||
/* AbortOutOfAnyTransaction sets the blockState */
|
||||
break;
|
||||
|
||||
/*
|
||||
* We were just issued a SAVEPOINT inside a transaction block.
|
||||
* Start a subtransaction. (DefineSavepoint already
|
||||
* did PushTransaction, so as to have someplace to put the
|
||||
* Start a subtransaction. (DefineSavepoint already did
|
||||
* PushTransaction, so as to have someplace to put the
|
||||
* SUBBEGIN state.)
|
||||
*/
|
||||
case TBLOCK_SUBBEGIN:
|
||||
@ -1720,11 +1730,12 @@ CommitTransactionCommand(void)
|
||||
* We were issued a RELEASE command, so we end the current
|
||||
* subtransaction and return to the parent transaction.
|
||||
*
|
||||
* Since RELEASE can exit multiple levels of subtransaction,
|
||||
* we must loop here until we get out of all SUBEND'ed levels.
|
||||
* Since RELEASE can exit multiple levels of subtransaction, we
|
||||
* must loop here until we get out of all SUBEND'ed levels.
|
||||
*/
|
||||
case TBLOCK_SUBEND:
|
||||
do {
|
||||
do
|
||||
{
|
||||
CommitSubTransaction();
|
||||
PopTransaction();
|
||||
s = CurrentTransactionState; /* changed by pop */
|
||||
@ -1738,17 +1749,17 @@ CommitTransactionCommand(void)
|
||||
break;
|
||||
|
||||
/*
|
||||
* The current subtransaction is ending. Do the equivalent
|
||||
* of a ROLLBACK TO followed by a RELEASE command.
|
||||
* The current subtransaction is ending. Do the equivalent of
|
||||
* a ROLLBACK TO followed by a RELEASE command.
|
||||
*/
|
||||
case TBLOCK_SUBENDABORT_RELEASE:
|
||||
CleanupAbortedSubTransactions(false);
|
||||
break;
|
||||
|
||||
/*
|
||||
* The current subtransaction is ending due to a ROLLBACK
|
||||
* TO command, so close all savepoints up to the target
|
||||
* level. When finished, recreate the savepoint.
|
||||
* The current subtransaction is ending due to a ROLLBACK TO
|
||||
* command, so close all savepoints up to the target level.
|
||||
* When finished, recreate the savepoint.
|
||||
*/
|
||||
case TBLOCK_SUBENDABORT:
|
||||
{
|
||||
@ -1756,7 +1767,8 @@ CommitTransactionCommand(void)
|
||||
|
||||
Assert(PointerIsValid(name));
|
||||
DefineSavepoint(name);
|
||||
s = CurrentTransactionState; /* changed by DefineSavepoint */
|
||||
s = CurrentTransactionState; /* changed by
|
||||
* DefineSavepoint */
|
||||
pfree(name);
|
||||
|
||||
/* This is the same as TBLOCK_SUBBEGIN case */
|
||||
@ -1856,10 +1868,10 @@ AbortCurrentTransaction(void)
|
||||
break;
|
||||
|
||||
/*
|
||||
* This is the case when we are somewhere in a transaction block
|
||||
* and we've gotten a failure, so we abort the transaction and
|
||||
* set up the persistent ABORT state. We will stay in ABORT
|
||||
* until we get an "END TRANSACTION".
|
||||
* This is the case when we are somewhere in a transaction
|
||||
* block and we've gotten a failure, so we abort the
|
||||
* transaction and set up the persistent ABORT state. We will
|
||||
* stay in ABORT until we get an "END TRANSACTION".
|
||||
*/
|
||||
case TBLOCK_INPROGRESS:
|
||||
AbortTransaction();
|
||||
@ -1900,8 +1912,8 @@ AbortCurrentTransaction(void)
|
||||
break;
|
||||
|
||||
/*
|
||||
* If we are just starting a subtransaction, put it
|
||||
* in aborted state.
|
||||
* If we are just starting a subtransaction, put it in aborted
|
||||
* state.
|
||||
*/
|
||||
case TBLOCK_SUBBEGIN:
|
||||
StartAbortedSubTransaction();
|
||||
@ -1914,8 +1926,8 @@ AbortCurrentTransaction(void)
|
||||
break;
|
||||
|
||||
/*
|
||||
* If we are aborting an ending transaction,
|
||||
* we have to abort the parent transaction too.
|
||||
* If we are aborting an ending transaction, we have to abort
|
||||
* the parent transaction too.
|
||||
*/
|
||||
case TBLOCK_SUBEND:
|
||||
case TBLOCK_SUBABORT_PENDING:
|
||||
@ -1942,8 +1954,8 @@ AbortCurrentTransaction(void)
|
||||
break;
|
||||
|
||||
/*
|
||||
* We are already aborting the whole transaction tree.
|
||||
* Do nothing, CommitTransactionCommand will call
|
||||
* We are already aborting the whole transaction tree. Do
|
||||
* nothing, CommitTransactionCommand will call
|
||||
* AbortOutOfAnyTransaction and set things straight.
|
||||
*/
|
||||
case TBLOCK_SUBENDABORT_ALL:
|
||||
@ -2068,8 +2080,8 @@ bool
|
||||
IsInTransactionChain(void *stmtNode)
|
||||
{
|
||||
/*
|
||||
* Return true on same conditions that would make PreventTransactionChain
|
||||
* error out
|
||||
* Return true on same conditions that would make
|
||||
* PreventTransactionChain error out
|
||||
*/
|
||||
if (IsTransactionBlock())
|
||||
return true;
|
||||
@ -2141,10 +2153,8 @@ CallXactCallbacks(XactEvent event, TransactionId parentXid)
|
||||
XactCallbackItem *item;
|
||||
|
||||
for (item = Xact_callbacks; item; item = item->next)
|
||||
{
|
||||
(*item->callback) (event, parentXid, item->arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
@ -2164,8 +2174,8 @@ BeginTransactionBlock(void)
|
||||
switch (s->blockState)
|
||||
{
|
||||
/*
|
||||
* We are not inside a transaction block, so allow one
|
||||
* to begin.
|
||||
* We are not inside a transaction block, so allow one to
|
||||
* begin.
|
||||
*/
|
||||
case TBLOCK_STARTED:
|
||||
s->blockState = TBLOCK_BEGIN;
|
||||
@ -2217,9 +2227,10 @@ EndTransactionBlock(void)
|
||||
{
|
||||
/*
|
||||
* We are in a transaction block which should commit when we
|
||||
* get to the upcoming CommitTransactionCommand() so we set the
|
||||
* state to "END". CommitTransactionCommand() will recognize this
|
||||
* and commit the transaction and return us to the default state.
|
||||
* get to the upcoming CommitTransactionCommand() so we set
|
||||
* the state to "END". CommitTransactionCommand() will
|
||||
* recognize this and commit the transaction and return us to
|
||||
* the default state.
|
||||
*/
|
||||
case TBLOCK_INPROGRESS:
|
||||
case TBLOCK_SUBINPROGRESS:
|
||||
@ -2229,30 +2240,31 @@ EndTransactionBlock(void)
|
||||
|
||||
/*
|
||||
* We are in a transaction block which aborted. Since the
|
||||
* AbortTransaction() was already done, we need only
|
||||
* change to the special "END ABORT" state. The upcoming
|
||||
* CommitTransactionCommand() will recognise this and then put us
|
||||
* back in the default state.
|
||||
* AbortTransaction() was already done, we need only change to
|
||||
* the special "END ABORT" state. The upcoming
|
||||
* CommitTransactionCommand() will recognise this and then put
|
||||
* us back in the default state.
|
||||
*/
|
||||
case TBLOCK_ABORT:
|
||||
s->blockState = TBLOCK_ENDABORT;
|
||||
break;
|
||||
|
||||
/*
|
||||
* Here we are inside an aborted subtransaction. Go to the "abort
|
||||
* the whole tree" state so that CommitTransactionCommand() calls
|
||||
* AbortOutOfAnyTransaction.
|
||||
* Here we are inside an aborted subtransaction. Go to the
|
||||
* "abort the whole tree" state so that
|
||||
* CommitTransactionCommand() calls AbortOutOfAnyTransaction.
|
||||
*/
|
||||
case TBLOCK_SUBABORT:
|
||||
s->blockState = TBLOCK_SUBENDABORT_ALL;
|
||||
break;
|
||||
|
||||
case TBLOCK_STARTED:
|
||||
|
||||
/*
|
||||
* here, the user issued COMMIT when not inside a
|
||||
* transaction. Issue a WARNING and go to abort state. The
|
||||
* upcoming call to CommitTransactionCommand() will then put us
|
||||
* back into the default state.
|
||||
* here, the user issued COMMIT when not inside a transaction.
|
||||
* Issue a WARNING and go to abort state. The upcoming call
|
||||
* to CommitTransactionCommand() will then put us back into
|
||||
* the default state.
|
||||
*/
|
||||
ereport(WARNING,
|
||||
(errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
|
||||
@ -2303,11 +2315,10 @@ UserAbortTransactionBlock(void)
|
||||
break;
|
||||
|
||||
/*
|
||||
* We are inside a failed subtransaction and we got an
|
||||
* abort command from the user. Abort processing is already
|
||||
* done, so go to the "abort all" state and
|
||||
* CommitTransactionCommand will call AbortOutOfAnyTransaction
|
||||
* to set things straight.
|
||||
* We are inside a failed subtransaction and we got an abort
|
||||
* command from the user. Abort processing is already done,
|
||||
* so go to the "abort all" state and CommitTransactionCommand
|
||||
* will call AbortOutOfAnyTransaction to set things straight.
|
||||
*/
|
||||
case TBLOCK_SUBABORT:
|
||||
s->blockState = TBLOCK_SUBENDABORT_ALL;
|
||||
@ -2382,10 +2393,11 @@ DefineSavepoint(char *name)
|
||||
/* Normal subtransaction start */
|
||||
PushTransaction();
|
||||
s = CurrentTransactionState; /* changed by push */
|
||||
|
||||
/*
|
||||
* Note that we are allocating the savepoint name in the
|
||||
* parent transaction's CurTransactionContext, since we
|
||||
* don't yet have a transaction context for the new guy.
|
||||
* parent transaction's CurTransactionContext, since we don't
|
||||
* yet have a transaction context for the new guy.
|
||||
*/
|
||||
s->name = MemoryContextStrdup(CurTransactionContext, name);
|
||||
s->blockState = TBLOCK_SUBBEGIN;
|
||||
@ -2437,8 +2449,8 @@ ReleaseSavepoint(List *options)
|
||||
break;
|
||||
|
||||
/*
|
||||
* We are in a non-aborted subtransaction. This is
|
||||
* the only valid case.
|
||||
* We are in a non-aborted subtransaction. This is the only
|
||||
* valid case.
|
||||
*/
|
||||
case TBLOCK_SUBINPROGRESS:
|
||||
break;
|
||||
@ -2490,8 +2502,8 @@ ReleaseSavepoint(List *options)
|
||||
|
||||
/*
|
||||
* Mark "commit pending" all subtransactions up to the target
|
||||
* subtransaction. The actual commits will happen when control
|
||||
* gets to CommitTransactionCommand.
|
||||
* subtransaction. The actual commits will happen when control gets
|
||||
* to CommitTransactionCommand.
|
||||
*/
|
||||
xact = CurrentTransactionState;
|
||||
for (;;)
|
||||
@ -2536,9 +2548,10 @@ RollbackToSavepoint(List *options)
|
||||
*/
|
||||
case TBLOCK_SUBABORT:
|
||||
case TBLOCK_SUBINPROGRESS:
|
||||
|
||||
/*
|
||||
* Have to do AbortSubTransaction, but first check
|
||||
* if this is the right subtransaction
|
||||
* Have to do AbortSubTransaction, but first check if this is
|
||||
* the right subtransaction
|
||||
*/
|
||||
break;
|
||||
|
||||
@ -2633,10 +2646,11 @@ BeginInternalSubTransaction(char *name)
|
||||
/* Normal subtransaction start */
|
||||
PushTransaction();
|
||||
s = CurrentTransactionState; /* changed by push */
|
||||
|
||||
/*
|
||||
* Note that we are allocating the savepoint name in the
|
||||
* parent transaction's CurTransactionContext, since we
|
||||
* don't yet have a transaction context for the new guy.
|
||||
* parent transaction's CurTransactionContext, since we don't
|
||||
* yet have a transaction context for the new guy.
|
||||
*/
|
||||
if (name)
|
||||
s->name = MemoryContextStrdup(CurTransactionContext, name);
|
||||
@ -2748,7 +2762,8 @@ AbortOutOfAnyTransaction(void)
|
||||
/*
|
||||
* Get out of any transaction or nested transaction
|
||||
*/
|
||||
do {
|
||||
do
|
||||
{
|
||||
switch (s->blockState)
|
||||
{
|
||||
case TBLOCK_DEFAULT:
|
||||
@ -2770,9 +2785,10 @@ AbortOutOfAnyTransaction(void)
|
||||
s->blockState = TBLOCK_DEFAULT;
|
||||
break;
|
||||
case TBLOCK_SUBBEGIN:
|
||||
|
||||
/*
|
||||
* We didn't get as far as starting the subxact, so there's
|
||||
* nothing to abort. Just pop back to parent.
|
||||
* We didn't get as far as starting the subxact, so
|
||||
* there's nothing to abort. Just pop back to parent.
|
||||
*/
|
||||
PopTransaction();
|
||||
s = CurrentTransactionState; /* changed by pop */
|
||||
@ -2780,7 +2796,11 @@ AbortOutOfAnyTransaction(void)
|
||||
case TBLOCK_SUBINPROGRESS:
|
||||
case TBLOCK_SUBEND:
|
||||
case TBLOCK_SUBABORT_PENDING:
|
||||
/* In a subtransaction, so clean it up and abort parent too */
|
||||
|
||||
/*
|
||||
* In a subtransaction, so clean it up and abort parent
|
||||
* too
|
||||
*/
|
||||
AbortSubTransaction();
|
||||
CleanupSubTransaction();
|
||||
PopTransaction();
|
||||
@ -2928,9 +2948,10 @@ StartSubTransaction(void)
|
||||
|
||||
/*
|
||||
* Generate a new Xid and record it in pg_subtrans. NB: we must make
|
||||
* the subtrans entry BEFORE the Xid appears anywhere in shared storage,
|
||||
* such as in the lock table; because until it's made the Xid may not
|
||||
* appear to be "running" to other backends. See GetNewTransactionId.
|
||||
* the subtrans entry BEFORE the Xid appears anywhere in shared
|
||||
* storage, such as in the lock table; because until it's made the Xid
|
||||
* may not appear to be "running" to other backends. See
|
||||
* GetNewTransactionId.
|
||||
*/
|
||||
s->transactionIdData = GetNewTransactionId(true);
|
||||
|
||||
@ -3020,9 +3041,9 @@ CommitSubTransaction(void)
|
||||
s->parent->transactionIdData);
|
||||
|
||||
/*
|
||||
* We need to restore the upper transaction's read-only state,
|
||||
* in case the upper is read-write while the child is read-only;
|
||||
* GUC will incorrectly think it should leave the child state in place.
|
||||
* We need to restore the upper transaction's read-only state, in case
|
||||
* the upper is read-write while the child is read-only; GUC will
|
||||
* incorrectly think it should leave the child state in place.
|
||||
*/
|
||||
XactReadOnly = s->prevXactReadOnly;
|
||||
|
||||
@ -3117,14 +3138,16 @@ AbortSubTransaction(void)
|
||||
/*
|
||||
* Reset user id which might have been changed transiently. Here we
|
||||
* want to restore to the userid that was current at subxact entry.
|
||||
* (As in AbortTransaction, we need not worry about the session userid.)
|
||||
* (As in AbortTransaction, we need not worry about the session
|
||||
* userid.)
|
||||
*
|
||||
* Must do this after AtEOXact_GUC to handle the case where we entered
|
||||
* the subxact inside a SECURITY DEFINER function (hence current and
|
||||
* session userids were different) and then session auth was changed
|
||||
* inside the subxact. GUC will reset both current and session userids
|
||||
* to the entry-time session userid. This is right in every other
|
||||
* scenario so it seems simplest to let GUC do that and fix it here.
|
||||
* inside the subxact. GUC will reset both current and session
|
||||
* userids to the entry-time session userid. This is right in every
|
||||
* other scenario so it seems simplest to let GUC do that and fix it
|
||||
* here.
|
||||
*/
|
||||
SetUserId(s->currentUser);
|
||||
|
||||
@ -3197,7 +3220,8 @@ StartAbortedSubTransaction(void)
|
||||
s->currentUser = s->parent->currentUser;
|
||||
|
||||
/*
|
||||
* Initialize only what has to be there for CleanupSubTransaction to work.
|
||||
* Initialize only what has to be there for CleanupSubTransaction to
|
||||
* work.
|
||||
*/
|
||||
AtSubStart_Memory();
|
||||
AtSubStart_ResourceOwner();
|
||||
@ -3502,6 +3526,7 @@ xact_desc(char *buf, uint8 xl_info, char *rec)
|
||||
for (i = 0; i < xlrec->nrels; i++)
|
||||
{
|
||||
RelFileNode rnode = xlrec->xnodes[i];
|
||||
|
||||
sprintf(buf + strlen(buf), " %u/%u/%u",
|
||||
rnode.spcNode, rnode.dbNode, rnode.relNode);
|
||||
}
|
||||
@ -3530,6 +3555,7 @@ xact_desc(char *buf, uint8 xl_info, char *rec)
|
||||
for (i = 0; i < xlrec->nrels; i++)
|
||||
{
|
||||
RelFileNode rnode = xlrec->xnodes[i];
|
||||
|
||||
sprintf(buf + strlen(buf), " %u/%u/%u",
|
||||
rnode.spcNode, rnode.dbNode, rnode.relNode);
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.165 2004/08/29 04:12:23 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.166 2004/08/29 05:06:40 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -128,8 +128,10 @@ TimeLineID ThisTimeLineID = 0;
|
||||
|
||||
/* Are we doing recovery from XLOG? */
|
||||
bool InRecovery = false;
|
||||
|
||||
/* Are we recovering using offline XLOG archives? */
|
||||
static bool InArchiveRecovery = false;
|
||||
|
||||
/* Was the last xlog file restored from archive, or local? */
|
||||
static bool restoredFromArchive = false;
|
||||
|
||||
@ -453,6 +455,7 @@ static void WriteControlFile(void);
|
||||
static void ReadControlFile(void);
|
||||
static char *str_time(time_t tnow);
|
||||
static void issue_xlog_fsync(void);
|
||||
|
||||
#ifdef WAL_DEBUG
|
||||
static void xlog_outrec(char *buf, XLogRecord *record);
|
||||
#endif
|
||||
@ -514,7 +517,8 @@ XLogInsert(RmgrId rmid, uint8 info, XLogRecData *rdata)
|
||||
if (IsBootstrapProcessingMode() && rmid != RM_XLOG_ID)
|
||||
{
|
||||
RecPtr.xlogid = 0;
|
||||
RecPtr.xrecoff = SizeOfXLogLongPHD; /* start of 1st chkpt record */
|
||||
RecPtr.xrecoff = SizeOfXLogLongPHD; /* start of 1st chkpt
|
||||
* record */
|
||||
return (RecPtr);
|
||||
}
|
||||
|
||||
@ -724,7 +728,8 @@ begin:;
|
||||
|
||||
/*
|
||||
* If there isn't enough space on the current XLOG page for a record
|
||||
* header, advance to the next page (leaving the unused space as zeroes).
|
||||
* header, advance to the next page (leaving the unused space as
|
||||
* zeroes).
|
||||
*/
|
||||
updrqst = false;
|
||||
freespace = INSERT_FREESPACE(Insert);
|
||||
@ -900,14 +905,16 @@ XLogArchiveNotify(const char *xlog)
|
||||
/* insert an otherwise empty file called <XLOG>.ready */
|
||||
StatusFilePath(archiveStatusPath, xlog, ".ready");
|
||||
fd = AllocateFile(archiveStatusPath, "w");
|
||||
if (fd == NULL) {
|
||||
if (fd == NULL)
|
||||
{
|
||||
ereport(LOG,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not create archive status file \"%s\": %m",
|
||||
archiveStatusPath)));
|
||||
return;
|
||||
}
|
||||
if (FreeFile(fd)) {
|
||||
if (FreeFile(fd))
|
||||
{
|
||||
ereport(LOG,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not write archive status file \"%s\": %m",
|
||||
@ -1823,11 +1830,11 @@ XLogFileRead(uint32 log, uint32 seg, int emode)
|
||||
int fd;
|
||||
|
||||
/*
|
||||
* Loop looking for a suitable timeline ID: we might need to
|
||||
* read any of the timelines listed in expectedTLIs.
|
||||
* Loop looking for a suitable timeline ID: we might need to read any
|
||||
* of the timelines listed in expectedTLIs.
|
||||
*
|
||||
* We expect curFileTLI on entry to be the TLI of the preceding file
|
||||
* in sequence, or 0 if there was no predecessor. We do not allow
|
||||
* We expect curFileTLI on entry to be the TLI of the preceding file in
|
||||
* sequence, or 0 if there was no predecessor. We do not allow
|
||||
* curFileTLI to go backwards; this prevents us from picking up the
|
||||
* wrong file when a parent timeline extends to higher segment numbers
|
||||
* than the child we want to read.
|
||||
@ -1902,25 +1909,26 @@ RestoreArchivedFile(char *path, const char *xlogfname,
|
||||
/*
|
||||
* When doing archive recovery, we always prefer an archived log file
|
||||
* even if a file of the same name exists in XLogDir. The reason is
|
||||
* that the file in XLogDir could be an old, un-filled or partly-filled
|
||||
* version that was copied and restored as part of backing up $PGDATA.
|
||||
* that the file in XLogDir could be an old, un-filled or
|
||||
* partly-filled version that was copied and restored as part of
|
||||
* backing up $PGDATA.
|
||||
*
|
||||
* We could try to optimize this slightly by checking the local
|
||||
* copy lastchange timestamp against the archived copy,
|
||||
* but we have no API to do this, nor can we guarantee that the
|
||||
* lastchange timestamp was preserved correctly when we copied
|
||||
* to archive. Our aim is robustness, so we elect not to do this.
|
||||
* We could try to optimize this slightly by checking the local copy
|
||||
* lastchange timestamp against the archived copy, but we have no API
|
||||
* to do this, nor can we guarantee that the lastchange timestamp was
|
||||
* preserved correctly when we copied to archive. Our aim is
|
||||
* robustness, so we elect not to do this.
|
||||
*
|
||||
* If we cannot obtain the log file from the archive, however, we
|
||||
* will try to use the XLogDir file if it exists. This is so that
|
||||
* we can make use of log segments that weren't yet transferred to
|
||||
* the archive.
|
||||
* If we cannot obtain the log file from the archive, however, we will
|
||||
* try to use the XLogDir file if it exists. This is so that we can
|
||||
* make use of log segments that weren't yet transferred to the
|
||||
* archive.
|
||||
*
|
||||
* Notice that we don't actually overwrite any files when we copy back
|
||||
* from archive because the recoveryRestoreCommand may inadvertently
|
||||
* restore inappropriate xlogs, or they may be corrupt, so we may
|
||||
* wish to fallback to the segments remaining in current XLogDir later.
|
||||
* The copy-from-archive filename is always the same, ensuring that we
|
||||
* restore inappropriate xlogs, or they may be corrupt, so we may wish
|
||||
* to fallback to the segments remaining in current XLogDir later. The
|
||||
* copy-from-archive filename is always the same, ensuring that we
|
||||
* don't run out of disk space on long recoveries.
|
||||
*/
|
||||
snprintf(xlogpath, MAXPGPATH, "%s/%s", XLogDir, recovername);
|
||||
@ -2006,9 +2014,9 @@ RestoreArchivedFile(char *path, const char *xlogfname,
|
||||
* command apparently succeeded, but let's make sure the file is
|
||||
* really there now and has the correct size.
|
||||
*
|
||||
* XXX I made wrong-size a fatal error to ensure the DBA would
|
||||
* notice it, but is that too strong? We could try to plow ahead
|
||||
* with a local copy of the file ... but the problem is that there
|
||||
* XXX I made wrong-size a fatal error to ensure the DBA would notice
|
||||
* it, but is that too strong? We could try to plow ahead with a
|
||||
* local copy of the file ... but the problem is that there
|
||||
* probably isn't one, and we'd incorrectly conclude we've reached
|
||||
* the end of WAL and we're done recovering ...
|
||||
*/
|
||||
@ -2041,11 +2049,10 @@ RestoreArchivedFile(char *path, const char *xlogfname,
|
||||
}
|
||||
|
||||
/*
|
||||
* remember, we rollforward UNTIL the restore fails
|
||||
* so failure here is just part of the process...
|
||||
* that makes it difficult to determine whether the restore
|
||||
* failed because there isn't an archive to restore, or
|
||||
* because the administrator has specified the restore
|
||||
* remember, we rollforward UNTIL the restore fails so failure here is
|
||||
* just part of the process... that makes it difficult to determine
|
||||
* whether the restore failed because there isn't an archive to
|
||||
* restore, or because the administrator has specified the restore
|
||||
* program incorrectly. We have to assume the former.
|
||||
*/
|
||||
ereport(DEBUG1,
|
||||
@ -2053,11 +2060,12 @@ RestoreArchivedFile(char *path, const char *xlogfname,
|
||||
xlogfname, rc)));
|
||||
|
||||
/*
|
||||
* if an archived file is not available, there might still be a version
|
||||
* of this file in XLogDir, so return that as the filename to open.
|
||||
* if an archived file is not available, there might still be a
|
||||
* version of this file in XLogDir, so return that as the filename to
|
||||
* open.
|
||||
*
|
||||
* In many recovery scenarios we expect this to fail also, but
|
||||
* if so that just means we've reached the end of WAL.
|
||||
* In many recovery scenarios we expect this to fail also, but if so that
|
||||
* just means we've reached the end of WAL.
|
||||
*/
|
||||
snprintf(path, MAXPGPATH, "%s/%s", XLogDir, xlogfname);
|
||||
return false;
|
||||
@ -2124,8 +2132,8 @@ MoveOfflineLogs(uint32 log, uint32 seg, XLogRecPtr endptr)
|
||||
* segments of non-parent timelines, but that would be a whole lot
|
||||
* more complicated.
|
||||
*
|
||||
* We use the alphanumeric sorting property of the filenames to decide
|
||||
* which ones are earlier than the lastoff segment.
|
||||
* We use the alphanumeric sorting property of the filenames to
|
||||
* decide which ones are earlier than the lastoff segment.
|
||||
*/
|
||||
if (strlen(xlde->d_name) == 24 &&
|
||||
strspn(xlde->d_name, "0123456789ABCDEF") == 24 &&
|
||||
@ -2171,8 +2179,11 @@ MoveOfflineLogs(uint32 log, uint32 seg, XLogRecPtr endptr)
|
||||
errno = 0;
|
||||
}
|
||||
#ifdef WIN32
|
||||
/* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but
|
||||
not in released version */
|
||||
|
||||
/*
|
||||
* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but
|
||||
* not in released version
|
||||
*/
|
||||
if (GetLastError() == ERROR_NO_MORE_FILES)
|
||||
errno = 0;
|
||||
#endif
|
||||
@ -2361,12 +2372,13 @@ ReadRecord(XLogRecPtr *RecPtr, int emode, char *buffer)
|
||||
ereport(PANIC,
|
||||
(errmsg("invalid record offset at %X/%X",
|
||||
RecPtr->xlogid, RecPtr->xrecoff)));
|
||||
|
||||
/*
|
||||
* Since we are going to a random position in WAL, forget any
|
||||
* prior state about what timeline we were in, and allow it
|
||||
* to be any timeline in expectedTLIs. We also set a flag to
|
||||
* allow curFileTLI to go backwards (but we can't reset that
|
||||
* variable right here, since we might not change files at all).
|
||||
* prior state about what timeline we were in, and allow it to be
|
||||
* any timeline in expectedTLIs. We also set a flag to allow
|
||||
* curFileTLI to go backwards (but we can't reset that variable
|
||||
* right here, since we might not change files at all).
|
||||
*/
|
||||
lastPageTLI = 0; /* see comment in ValidXLOGHeader */
|
||||
randAccess = true; /* allow curFileTLI to go backwards too */
|
||||
@ -2418,9 +2430,9 @@ ReadRecord(XLogRecPtr *RecPtr, int emode, char *buffer)
|
||||
if (targetRecOff == 0)
|
||||
{
|
||||
/*
|
||||
* Can only get here in the continuing-from-prev-page case, because
|
||||
* XRecOffIsValid eliminated the zero-page-offset case otherwise.
|
||||
* Need to skip over the new page's header.
|
||||
* Can only get here in the continuing-from-prev-page case,
|
||||
* because XRecOffIsValid eliminated the zero-page-offset case
|
||||
* otherwise. Need to skip over the new page's header.
|
||||
*/
|
||||
tmpRecPtr.xrecoff += pageHeaderSize;
|
||||
targetRecOff = pageHeaderSize;
|
||||
@ -2671,9 +2683,9 @@ ValidXLOGHeader(XLogPageHeader hdr, int emode)
|
||||
* immediate parent's TLI, we should never see TLI go backwards across
|
||||
* successive pages of a consistent WAL sequence.
|
||||
*
|
||||
* Of course this check should only be applied when advancing sequentially
|
||||
* across pages; therefore ReadRecord resets lastPageTLI to zero when
|
||||
* going to a random page.
|
||||
* Of course this check should only be applied when advancing
|
||||
* sequentially across pages; therefore ReadRecord resets lastPageTLI
|
||||
* to zero when going to a random page.
|
||||
*/
|
||||
if (hdr->xlp_tli < lastPageTLI)
|
||||
{
|
||||
@ -2827,8 +2839,8 @@ findNewestTimeLine(TimeLineID startTLI)
|
||||
TimeLineID probeTLI;
|
||||
|
||||
/*
|
||||
* The algorithm is just to probe for the existence of timeline history
|
||||
* files. XXX is it useful to allow gaps in the sequence?
|
||||
* The algorithm is just to probe for the existence of timeline
|
||||
* history files. XXX is it useful to allow gaps in the sequence?
|
||||
*/
|
||||
newestTLI = startTLI;
|
||||
|
||||
@ -2932,7 +2944,11 @@ writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI,
|
||||
* space
|
||||
*/
|
||||
unlink(tmppath);
|
||||
/* if write didn't set errno, assume problem is no disk space */
|
||||
|
||||
/*
|
||||
* if write didn't set errno, assume problem is no disk
|
||||
* space
|
||||
*/
|
||||
errno = save_errno ? save_errno : ENOSPC;
|
||||
|
||||
ereport(PANIC,
|
||||
@ -2946,8 +2962,8 @@ writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI,
|
||||
/*
|
||||
* Append one line with the details of this timeline split.
|
||||
*
|
||||
* If we did have a parent file, insert an extra newline just in case
|
||||
* the parent file failed to end with one.
|
||||
* If we did have a parent file, insert an extra newline just in case the
|
||||
* parent file failed to end with one.
|
||||
*/
|
||||
XLogFileName(xlogfname, endTLI, endLogId, endLogSeg);
|
||||
|
||||
@ -2967,8 +2983,7 @@ writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI,
|
||||
int save_errno = errno;
|
||||
|
||||
/*
|
||||
* If we fail to make the file, delete it to release disk
|
||||
* space
|
||||
* If we fail to make the file, delete it to release disk space
|
||||
*/
|
||||
unlink(tmppath);
|
||||
/* if write didn't set errno, assume problem is no disk space */
|
||||
@ -3336,7 +3351,8 @@ XLOGShmemSize(void)
|
||||
void
|
||||
XLOGShmemInit(void)
|
||||
{
|
||||
bool foundXLog, foundCFile;
|
||||
bool foundXLog,
|
||||
foundCFile;
|
||||
|
||||
/* this must agree with space requested by XLOGShmemSize() */
|
||||
if (XLOGbuffers < MinXLOGbuffers)
|
||||
@ -3414,16 +3430,17 @@ BootStrapXLOG(void)
|
||||
crc64 crc;
|
||||
|
||||
/*
|
||||
* Select a hopefully-unique system identifier code for this installation.
|
||||
* We use the result of gettimeofday(), including the fractional seconds
|
||||
* field, as being about as unique as we can easily get. (Think not to
|
||||
* use random(), since it hasn't been seeded and there's no portable way
|
||||
* to seed it other than the system clock value...) The upper half of the
|
||||
* uint64 value is just the tv_sec part, while the lower half is the XOR
|
||||
* of tv_sec and tv_usec. This is to ensure that we don't lose uniqueness
|
||||
* unnecessarily if "uint64" is really only 32 bits wide. A person
|
||||
* knowing this encoding can determine the initialization time of the
|
||||
* installation, which could perhaps be useful sometimes.
|
||||
* Select a hopefully-unique system identifier code for this
|
||||
* installation. We use the result of gettimeofday(), including the
|
||||
* fractional seconds field, as being about as unique as we can easily
|
||||
* get. (Think not to use random(), since it hasn't been seeded and
|
||||
* there's no portable way to seed it other than the system clock
|
||||
* value...) The upper half of the uint64 value is just the tv_sec
|
||||
* part, while the lower half is the XOR of tv_sec and tv_usec. This
|
||||
* is to ensure that we don't lose uniqueness unnecessarily if
|
||||
* "uint64" is really only 32 bits wide. A person knowing this
|
||||
* encoding can determine the initialization time of the installation,
|
||||
* which could perhaps be useful sometimes.
|
||||
*/
|
||||
gettimeofday(&tv, NULL);
|
||||
sysidentifier = ((uint64) tv.tv_sec) << 32;
|
||||
@ -3611,13 +3628,15 @@ readRecoveryCommandFile(void)
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcmp(tok1,"restore_command") == 0) {
|
||||
if (strcmp(tok1, "restore_command") == 0)
|
||||
{
|
||||
recoveryRestoreCommand = pstrdup(tok2);
|
||||
ereport(LOG,
|
||||
(errmsg("restore_command = \"%s\"",
|
||||
recoveryRestoreCommand)));
|
||||
}
|
||||
else if (strcmp(tok1,"recovery_target_timeline") == 0) {
|
||||
else if (strcmp(tok1, "recovery_target_timeline") == 0)
|
||||
{
|
||||
rtliGiven = true;
|
||||
if (strcmp(tok2, "latest") == 0)
|
||||
rtli = 0;
|
||||
@ -3637,7 +3656,8 @@ readRecoveryCommandFile(void)
|
||||
ereport(LOG,
|
||||
(errmsg("recovery_target_timeline = latest")));
|
||||
}
|
||||
else if (strcmp(tok1,"recovery_target_xid") == 0) {
|
||||
else if (strcmp(tok1, "recovery_target_xid") == 0)
|
||||
{
|
||||
errno = 0;
|
||||
recoveryTargetXid = (TransactionId) strtoul(tok2, NULL, 0);
|
||||
if (errno == EINVAL || errno == ERANGE)
|
||||
@ -3650,7 +3670,8 @@ readRecoveryCommandFile(void)
|
||||
recoveryTarget = true;
|
||||
recoveryTargetExact = true;
|
||||
}
|
||||
else if (strcmp(tok1,"recovery_target_time") == 0) {
|
||||
else if (strcmp(tok1, "recovery_target_time") == 0)
|
||||
{
|
||||
/*
|
||||
* if recovery_target_xid specified, then this overrides
|
||||
* recovery_target_time
|
||||
@ -3659,10 +3680,11 @@ readRecoveryCommandFile(void)
|
||||
continue;
|
||||
recoveryTarget = true;
|
||||
recoveryTargetExact = false;
|
||||
|
||||
/*
|
||||
* Convert the time string given by the user to the time_t format.
|
||||
* We use type abstime's input converter because we know abstime
|
||||
* has the same representation as time_t.
|
||||
* Convert the time string given by the user to the time_t
|
||||
* format. We use type abstime's input converter because we
|
||||
* know abstime has the same representation as time_t.
|
||||
*/
|
||||
recoveryTargetTime = (time_t)
|
||||
DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
|
||||
@ -3672,7 +3694,8 @@ readRecoveryCommandFile(void)
|
||||
DatumGetCString(DirectFunctionCall1(abstimeout,
|
||||
AbsoluteTimeGetDatum((AbsoluteTime) recoveryTargetTime))))));
|
||||
}
|
||||
else if (strcmp(tok1,"recovery_target_inclusive") == 0) {
|
||||
else if (strcmp(tok1, "recovery_target_inclusive") == 0)
|
||||
{
|
||||
/*
|
||||
* does nothing if a recovery_target is not also set
|
||||
*/
|
||||
@ -3710,10 +3733,10 @@ readRecoveryCommandFile(void)
|
||||
InArchiveRecovery = true;
|
||||
|
||||
/*
|
||||
* If user specified recovery_target_timeline, validate it or compute the
|
||||
* "latest" value. We can't do this until after we've gotten the restore
|
||||
* command and set InArchiveRecovery, because we need to fetch timeline
|
||||
* history files from the archive.
|
||||
* If user specified recovery_target_timeline, validate it or compute
|
||||
* the "latest" value. We can't do this until after we've gotten the
|
||||
* restore command and set InArchiveRecovery, because we need to fetch
|
||||
* timeline history files from the archive.
|
||||
*/
|
||||
if (rtliGiven)
|
||||
{
|
||||
@ -3751,9 +3774,9 @@ exitArchiveRecovery(TimeLineID endTLI, uint32 endLogId, uint32 endLogSeg)
|
||||
InArchiveRecovery = false;
|
||||
|
||||
/*
|
||||
* We should have the ending log segment currently open. Verify,
|
||||
* and then close it (to avoid problems on Windows with trying to
|
||||
* rename or delete an open file).
|
||||
* We should have the ending log segment currently open. Verify, and
|
||||
* then close it (to avoid problems on Windows with trying to rename
|
||||
* or delete an open file).
|
||||
*/
|
||||
Assert(readFile >= 0);
|
||||
Assert(readId == endLogId);
|
||||
@ -3763,17 +3786,17 @@ exitArchiveRecovery(TimeLineID endTLI, uint32 endLogId, uint32 endLogSeg)
|
||||
readFile = -1;
|
||||
|
||||
/*
|
||||
* If the segment was fetched from archival storage, we want to replace
|
||||
* the existing xlog segment (if any) with the archival version. This
|
||||
* is because whatever is in XLogDir is very possibly older than what
|
||||
* we have from the archives, since it could have come from restoring
|
||||
* a PGDATA backup. In any case, the archival version certainly is
|
||||
* more descriptive of what our current database state is, because that
|
||||
* is what we replayed from.
|
||||
* If the segment was fetched from archival storage, we want to
|
||||
* replace the existing xlog segment (if any) with the archival
|
||||
* version. This is because whatever is in XLogDir is very possibly
|
||||
* older than what we have from the archives, since it could have come
|
||||
* from restoring a PGDATA backup. In any case, the archival version
|
||||
* certainly is more descriptive of what our current database state
|
||||
* is, because that is what we replayed from.
|
||||
*
|
||||
* Note that if we are establishing a new timeline, ThisTimeLineID is
|
||||
* already set to the new value, and so we will create a new file instead
|
||||
* of overwriting any existing file.
|
||||
* already set to the new value, and so we will create a new file
|
||||
* instead of overwriting any existing file.
|
||||
*/
|
||||
snprintf(recoveryPath, MAXPGPATH, "%s/RECOVERYXLOG", XLogDir);
|
||||
XLogFilePath(xlogpath, ThisTimeLineID, endLogId, endLogSeg);
|
||||
@ -3798,6 +3821,7 @@ exitArchiveRecovery(TimeLineID endTLI, uint32 endLogId, uint32 endLogSeg)
|
||||
* RECOVERYXLOG laying about, get rid of it.
|
||||
*/
|
||||
unlink(recoveryPath); /* ignore any error */
|
||||
|
||||
/*
|
||||
* If we are establishing a new timeline, we have to copy data
|
||||
* from the last WAL segment of the old timeline to create a
|
||||
@ -3809,8 +3833,8 @@ exitArchiveRecovery(TimeLineID endTLI, uint32 endLogId, uint32 endLogSeg)
|
||||
}
|
||||
|
||||
/*
|
||||
* Let's just make real sure there are not .ready or .done flags posted
|
||||
* for the new segment.
|
||||
* Let's just make real sure there are not .ready or .done flags
|
||||
* posted for the new segment.
|
||||
*/
|
||||
XLogFileName(xlogpath, ThisTimeLineID, endLogId, endLogSeg);
|
||||
XLogArchiveCleanup(xlogpath);
|
||||
@ -3820,8 +3844,8 @@ exitArchiveRecovery(TimeLineID endTLI, uint32 endLogId, uint32 endLogSeg)
|
||||
unlink(recoveryPath); /* ignore any error */
|
||||
|
||||
/*
|
||||
* Rename the config file out of the way, so that we don't accidentally
|
||||
* re-enter archive recovery mode in a subsequent crash.
|
||||
* Rename the config file out of the way, so that we don't
|
||||
* accidentally re-enter archive recovery mode in a subsequent crash.
|
||||
*/
|
||||
snprintf(recoveryCommandFile, MAXPGPATH, "%s/recovery.conf", DataDir);
|
||||
snprintf(recoveryCommandDone, MAXPGPATH, "%s/recovery.done", DataDir);
|
||||
@ -3880,14 +3904,13 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
|
||||
if (recoveryTargetExact)
|
||||
{
|
||||
/*
|
||||
* there can be only one transaction end record
|
||||
* with this exact transactionid
|
||||
* there can be only one transaction end record with this exact
|
||||
* transactionid
|
||||
*
|
||||
* when testing for an xid, we MUST test for
|
||||
* equality only, since transactions are numbered
|
||||
* in the order they start, not the order they
|
||||
* complete. A higher numbered xid will complete
|
||||
* before you about 50% of the time...
|
||||
* when testing for an xid, we MUST test for equality only, since
|
||||
* transactions are numbered in the order they start, not the
|
||||
* order they complete. A higher numbered xid will complete before
|
||||
* you about 50% of the time...
|
||||
*/
|
||||
stopsHere = (record->xl_xid == recoveryTargetXid);
|
||||
if (stopsHere)
|
||||
@ -3896,11 +3919,9 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
|
||||
else
|
||||
{
|
||||
/*
|
||||
* there can be many transactions that
|
||||
* share the same commit time, so
|
||||
* we stop after the last one, if we are
|
||||
* inclusive, or stop at the first one
|
||||
* if we are exclusive
|
||||
* there can be many transactions that share the same commit time,
|
||||
* so we stop after the last one, if we are inclusive, or stop at
|
||||
* the first one if we are exclusive
|
||||
*/
|
||||
if (recoveryTargetInclusive)
|
||||
stopsHere = (recordXtime > recoveryTargetTime);
|
||||
@ -4009,14 +4030,14 @@ StartupXLOG(void)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Initialize on the assumption we want to recover to the same timeline
|
||||
* that's active according to pg_control.
|
||||
* Initialize on the assumption we want to recover to the same
|
||||
* timeline that's active according to pg_control.
|
||||
*/
|
||||
recoveryTargetTLI = ControlFile->checkPointCopy.ThisTimeLineID;
|
||||
|
||||
/*
|
||||
* Check for recovery control file, and if so set up state for
|
||||
* offline recovery
|
||||
* Check for recovery control file, and if so set up state for offline
|
||||
* recovery
|
||||
*/
|
||||
readRecoveryCommandFile();
|
||||
|
||||
@ -4038,8 +4059,9 @@ StartupXLOG(void)
|
||||
if (read_backup_label(&checkPointLoc))
|
||||
{
|
||||
/*
|
||||
* When a backup_label file is present, we want to roll forward from
|
||||
* the checkpoint it identifies, rather than using pg_control.
|
||||
* When a backup_label file is present, we want to roll forward
|
||||
* from the checkpoint it identifies, rather than using
|
||||
* pg_control.
|
||||
*/
|
||||
record = ReadCheckpointRecord(checkPointLoc, 0, buffer);
|
||||
if (record != NULL)
|
||||
@ -4059,8 +4081,8 @@ StartupXLOG(void)
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Get the last valid checkpoint record. If the latest one according
|
||||
* to pg_control is broken, try the next-to-last one.
|
||||
* Get the last valid checkpoint record. If the latest one
|
||||
* according to pg_control is broken, try the next-to-last one.
|
||||
*/
|
||||
checkPointLoc = ControlFile->checkPoint;
|
||||
record = ReadCheckpointRecord(checkPointLoc, 1, buffer);
|
||||
@ -4079,7 +4101,8 @@ StartupXLOG(void)
|
||||
ereport(LOG,
|
||||
(errmsg("using previous checkpoint record at %X/%X",
|
||||
checkPointLoc.xlogid, checkPointLoc.xrecoff)));
|
||||
InRecovery = true; /* force recovery even if SHUTDOWNED */
|
||||
InRecovery = true; /* force recovery even if
|
||||
* SHUTDOWNED */
|
||||
}
|
||||
else
|
||||
ereport(PANIC,
|
||||
@ -4108,9 +4131,9 @@ StartupXLOG(void)
|
||||
ShmemVariableCache->oidCount = 0;
|
||||
|
||||
/*
|
||||
* We must replay WAL entries using the same TimeLineID they were created
|
||||
* under, so temporarily adopt the TLI indicated by the checkpoint (see
|
||||
* also xlog_redo()).
|
||||
* We must replay WAL entries using the same TimeLineID they were
|
||||
* created under, so temporarily adopt the TLI indicated by the
|
||||
* checkpoint (see also xlog_redo()).
|
||||
*/
|
||||
ThisTimeLineID = checkPoint.ThisTimeLineID;
|
||||
|
||||
@ -4123,8 +4146,8 @@ StartupXLOG(void)
|
||||
checkPoint.undo = RecPtr;
|
||||
|
||||
/*
|
||||
* Check whether we need to force recovery from WAL. If it appears
|
||||
* to have been a clean shutdown and we did not have a recovery.conf
|
||||
* Check whether we need to force recovery from WAL. If it appears to
|
||||
* have been a clean shutdown and we did not have a recovery.conf
|
||||
* file, then assume no recovery needed.
|
||||
*/
|
||||
if (XLByteLT(checkPoint.undo, RecPtr) ||
|
||||
@ -4242,6 +4265,7 @@ StartupXLOG(void)
|
||||
|
||||
record = ReadRecord(NULL, LOG, buffer);
|
||||
} while (record != NULL && recoveryContinue);
|
||||
|
||||
/*
|
||||
* end of main redo apply loop
|
||||
*/
|
||||
@ -4276,7 +4300,8 @@ StartupXLOG(void)
|
||||
if (needNewTimeLine) /* stopped because of stop request */
|
||||
ereport(FATAL,
|
||||
(errmsg("requested recovery stop point is before end time of backup dump")));
|
||||
else /* ran off end of WAL */
|
||||
else
|
||||
/* ran off end of WAL */
|
||||
ereport(FATAL,
|
||||
(errmsg("WAL ends before end time of backup dump")));
|
||||
}
|
||||
@ -4284,10 +4309,10 @@ StartupXLOG(void)
|
||||
/*
|
||||
* Consider whether we need to assign a new timeline ID.
|
||||
*
|
||||
* If we stopped short of the end of WAL during recovery, then we
|
||||
* are generating a new timeline and must assign it a unique new ID.
|
||||
* Otherwise, we can just extend the timeline we were in when we
|
||||
* ran out of WAL.
|
||||
* If we stopped short of the end of WAL during recovery, then we are
|
||||
* generating a new timeline and must assign it a unique new ID.
|
||||
* Otherwise, we can just extend the timeline we were in when we ran
|
||||
* out of WAL.
|
||||
*/
|
||||
if (needNewTimeLine)
|
||||
{
|
||||
@ -4302,8 +4327,8 @@ StartupXLOG(void)
|
||||
XLogCtl->ThisTimeLineID = ThisTimeLineID;
|
||||
|
||||
/*
|
||||
* We are now done reading the old WAL. Turn off archive fetching
|
||||
* if it was active, and make a writable copy of the last WAL segment.
|
||||
* We are now done reading the old WAL. Turn off archive fetching if
|
||||
* it was active, and make a writable copy of the last WAL segment.
|
||||
* (Note that we also have a copy of the last block of the old WAL in
|
||||
* readBuf; we will use that below.)
|
||||
*/
|
||||
@ -4434,8 +4459,8 @@ StartupXLOG(void)
|
||||
XLogCloseRelationCache();
|
||||
|
||||
/*
|
||||
* Now that we've checkpointed the recovery, it's safe to
|
||||
* flush old backup_label, if present.
|
||||
* Now that we've checkpointed the recovery, it's safe to flush
|
||||
* old backup_label, if present.
|
||||
*/
|
||||
remove_backup_label();
|
||||
}
|
||||
@ -4791,8 +4816,8 @@ CreateCheckPoint(bool shutdown, bool force)
|
||||
* so there's a risk of deadlock. Need to find a better solution. See
|
||||
* pgsql-hackers discussion of 17-Dec-01.
|
||||
*
|
||||
* XXX actually, the whole UNDO code is dead code and unlikely to ever
|
||||
* be revived, so the lack of a good solution here is not troubling.
|
||||
* XXX actually, the whole UNDO code is dead code and unlikely to ever be
|
||||
* revived, so the lack of a good solution here is not troubling.
|
||||
*/
|
||||
#ifdef NOT_USED
|
||||
checkPoint.undo = GetUndoRecPtr();
|
||||
@ -4919,11 +4944,11 @@ CreateCheckPoint(bool shutdown, bool force)
|
||||
PreallocXlogFiles(recptr);
|
||||
|
||||
/*
|
||||
* Truncate pg_subtrans if possible. We can throw away all data before
|
||||
* the oldest XMIN of any running transaction. No future transaction will
|
||||
* attempt to reference any pg_subtrans entry older than that (see Asserts
|
||||
* in subtrans.c). During recovery, though, we mustn't do this because
|
||||
* StartupSUBTRANS hasn't been called yet.
|
||||
* Truncate pg_subtrans if possible. We can throw away all data
|
||||
* before the oldest XMIN of any running transaction. No future
|
||||
* transaction will attempt to reference any pg_subtrans entry older
|
||||
* than that (see Asserts in subtrans.c). During recovery, though, we
|
||||
* mustn't do this because StartupSUBTRANS hasn't been called yet.
|
||||
*/
|
||||
if (!InRecovery)
|
||||
TruncateSUBTRANS(GetOldestXmin(true));
|
||||
@ -4974,8 +4999,10 @@ xlog_redo(XLogRecPtr lsn, XLogRecord *record)
|
||||
ShmemVariableCache->nextXid = checkPoint.nextXid;
|
||||
ShmemVariableCache->nextOid = checkPoint.nextOid;
|
||||
ShmemVariableCache->oidCount = 0;
|
||||
|
||||
/*
|
||||
* TLI may change in a shutdown checkpoint, but it shouldn't decrease
|
||||
* TLI may change in a shutdown checkpoint, but it shouldn't
|
||||
* decrease
|
||||
*/
|
||||
if (checkPoint.ThisTimeLineID != ThisTimeLineID)
|
||||
{
|
||||
@ -5071,7 +5098,6 @@ xlog_outrec(char *buf, XLogRecord *record)
|
||||
sprintf(buf + strlen(buf), ": %s",
|
||||
RmgrTable[record->xl_rmid].rm_name);
|
||||
}
|
||||
|
||||
#endif /* WAL_DEBUG */
|
||||
|
||||
|
||||
@ -5215,18 +5241,20 @@ pg_start_backup(PG_FUNCTION_ARGS)
|
||||
(errmsg("must be superuser to run a backup"))));
|
||||
backupidstr = DatumGetCString(DirectFunctionCall1(textout,
|
||||
PointerGetDatum(backupid)));
|
||||
|
||||
/*
|
||||
* Force a CHECKPOINT. This is not strictly necessary, but it seems
|
||||
* like a good idea to minimize the amount of past WAL needed to use the
|
||||
* backup. Also, this guarantees that two successive backup runs
|
||||
* will have different checkpoint positions and hence different history
|
||||
* file names, even if nothing happened in between.
|
||||
* like a good idea to minimize the amount of past WAL needed to use
|
||||
* the backup. Also, this guarantees that two successive backup runs
|
||||
* will have different checkpoint positions and hence different
|
||||
* history file names, even if nothing happened in between.
|
||||
*/
|
||||
RequestCheckpoint(true);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* 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_EXCLUSIVE);
|
||||
checkpointloc = ControlFile->checkPoint;
|
||||
@ -5235,18 +5263,21 @@ pg_start_backup(PG_FUNCTION_ARGS)
|
||||
|
||||
XLByteToSeg(startpoint, _logId, _logSeg);
|
||||
XLogFileName(xlogfilename, ThisTimeLineID, _logId, _logSeg);
|
||||
|
||||
/*
|
||||
* We deliberately use strftime/localtime not the src/timezone functions,
|
||||
* so that backup labels will consistently be recorded in the same
|
||||
* timezone regardless of TimeZone setting. This matches elog.c's
|
||||
* practice.
|
||||
* We deliberately use strftime/localtime not the src/timezone
|
||||
* functions, so that backup labels will consistently be recorded in
|
||||
* the same timezone regardless of TimeZone setting. This matches
|
||||
* elog.c's practice.
|
||||
*/
|
||||
stamp_time = time(NULL);
|
||||
strftime(strfbuf, sizeof(strfbuf),
|
||||
"%Y-%m-%d %H:%M:%S %Z",
|
||||
localtime(&stamp_time));
|
||||
|
||||
/*
|
||||
* Check for existing backup label --- implies a backup is already running
|
||||
* Check for existing backup label --- implies a backup is already
|
||||
* running
|
||||
*/
|
||||
snprintf(labelfilepath, MAXPGPATH, "%s/backup_label", DataDir);
|
||||
if (stat(labelfilepath, &stat_buf) != 0)
|
||||
@ -5263,6 +5294,7 @@ pg_start_backup(PG_FUNCTION_ARGS)
|
||||
errmsg("a backup is already in progress"),
|
||||
errhint("If you're sure there is no backup in progress, remove file \"%s\" and try again.",
|
||||
labelfilepath)));
|
||||
|
||||
/*
|
||||
* Okay, write the file
|
||||
*/
|
||||
@ -5283,6 +5315,7 @@ pg_start_backup(PG_FUNCTION_ARGS)
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not write file \"%s\": %m",
|
||||
labelfilepath)));
|
||||
|
||||
/*
|
||||
* We're done. As a convenience, return the starting WAL offset.
|
||||
*/
|
||||
@ -5325,6 +5358,7 @@ pg_stop_backup(PG_FUNCTION_ARGS)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
(errmsg("must be superuser to run a backup"))));
|
||||
|
||||
/*
|
||||
* Get the current end-of-WAL position; it will be unsafe to use this
|
||||
* dump to restore to a point in advance of this time.
|
||||
@ -5335,16 +5369,18 @@ pg_stop_backup(PG_FUNCTION_ARGS)
|
||||
|
||||
XLByteToSeg(stoppoint, _logId, _logSeg);
|
||||
XLogFileName(stopxlogfilename, ThisTimeLineID, _logId, _logSeg);
|
||||
|
||||
/*
|
||||
* We deliberately use strftime/localtime not the src/timezone functions,
|
||||
* so that backup labels will consistently be recorded in the same
|
||||
* timezone regardless of TimeZone setting. This matches elog.c's
|
||||
* practice.
|
||||
* We deliberately use strftime/localtime not the src/timezone
|
||||
* functions, so that backup labels will consistently be recorded in
|
||||
* the same timezone regardless of TimeZone setting. This matches
|
||||
* elog.c's practice.
|
||||
*/
|
||||
stamp_time = time(NULL);
|
||||
strftime(strfbuf, sizeof(strfbuf),
|
||||
"%Y-%m-%d %H:%M:%S %Z",
|
||||
localtime(&stamp_time));
|
||||
|
||||
/*
|
||||
* Open the existing label file
|
||||
*/
|
||||
@ -5361,9 +5397,11 @@ pg_stop_backup(PG_FUNCTION_ARGS)
|
||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
errmsg("a backup is not in progress")));
|
||||
}
|
||||
|
||||
/*
|
||||
* Read and parse the START WAL LOCATION line (this code is pretty
|
||||
* crude, but we are not expecting any variability in the file format).
|
||||
* crude, but we are not expecting any variability in the file
|
||||
* format).
|
||||
*/
|
||||
if (fscanf(lfp, "START WAL LOCATION: %X/%X (file %24s)%c",
|
||||
&startpoint.xlogid, &startpoint.xrecoff, startxlogfilename,
|
||||
@ -5371,6 +5409,7 @@ pg_stop_backup(PG_FUNCTION_ARGS)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
errmsg("invalid data in file \"%s\"", labelfilepath)));
|
||||
|
||||
/*
|
||||
* Write the backup history file
|
||||
*/
|
||||
@ -5396,6 +5435,7 @@ pg_stop_backup(PG_FUNCTION_ARGS)
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not write file \"%s\": %m",
|
||||
histfilepath)));
|
||||
|
||||
/*
|
||||
* Close and remove the backup label file
|
||||
*/
|
||||
@ -5409,6 +5449,7 @@ pg_stop_backup(PG_FUNCTION_ARGS)
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not remove file \"%s\": %m",
|
||||
labelfilepath)));
|
||||
|
||||
/*
|
||||
* Notify archiver that history file may be archived immediately
|
||||
*/
|
||||
@ -5418,6 +5459,7 @@ pg_stop_backup(PG_FUNCTION_ARGS)
|
||||
startpoint.xrecoff % XLogSegSize);
|
||||
XLogArchiveNotify(histfilepath);
|
||||
}
|
||||
|
||||
/*
|
||||
* We're done. As a convenience, return the ending WAL offset.
|
||||
*/
|
||||
@ -5476,10 +5518,11 @@ read_backup_label(XLogRecPtr *checkPointLoc)
|
||||
labelfilepath)));
|
||||
return false; /* it's not there, all is fine */
|
||||
}
|
||||
|
||||
/*
|
||||
* Read and parse the START WAL LOCATION and CHECKPOINT lines (this code
|
||||
* is pretty crude, but we are not expecting any variability in the file
|
||||
* format).
|
||||
* Read and parse the START WAL LOCATION and CHECKPOINT lines (this
|
||||
* code is pretty crude, but we are not expecting any variability in
|
||||
* the file format).
|
||||
*/
|
||||
if (fscanf(lfp, "START WAL LOCATION: %X/%X (file %08X%16s)%c",
|
||||
&startpoint.xlogid, &startpoint.xrecoff, &tli,
|
||||
@ -5498,6 +5541,7 @@ read_backup_label(XLogRecPtr *checkPointLoc)
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not read file \"%s\": %m",
|
||||
labelfilepath)));
|
||||
|
||||
/*
|
||||
* Try to retrieve the backup history file (no error if we can't)
|
||||
*/
|
||||
|
@ -11,7 +11,7 @@
|
||||
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/xlogutils.c,v 1.33 2004/08/29 04:12:23 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/xlogutils.c,v 1.34 2004/08/29 05:06:41 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -212,11 +212,11 @@ XLogOpenRelation(bool redo, RmgrId rmid, RelFileNode rnode)
|
||||
res->reldata.rd_node = rnode;
|
||||
|
||||
/*
|
||||
* We set up the lockRelId in case anything tries to lock the dummy
|
||||
* relation. Note that this is fairly bogus since relNode may be
|
||||
* different from the relation's OID. It shouldn't really matter
|
||||
* though, since we are presumably running by ourselves and can't
|
||||
* have any lock conflicts ...
|
||||
* We set up the lockRelId in case anything tries to lock the
|
||||
* dummy relation. Note that this is fairly bogus since relNode
|
||||
* may be different from the relation's OID. It shouldn't really
|
||||
* matter though, since we are presumably running by ourselves and
|
||||
* can't have any lock conflicts ...
|
||||
*/
|
||||
res->reldata.rd_lockInfo.lockRelId.dbId = rnode.dbNode;
|
||||
res->reldata.rd_lockInfo.lockRelId.relId = rnode.relNode;
|
||||
@ -234,14 +234,15 @@ XLogOpenRelation(bool redo, RmgrId rmid, RelFileNode rnode)
|
||||
|
||||
res->reldata.rd_targblock = InvalidBlockNumber;
|
||||
res->reldata.rd_smgr = smgropen(res->reldata.rd_node);
|
||||
|
||||
/*
|
||||
* Create the target file if it doesn't already exist. This lets
|
||||
* us cope if the replay sequence contains writes to a relation
|
||||
* that is later deleted. (The original coding of this routine
|
||||
* would instead return NULL, causing the writes to be suppressed.
|
||||
* But that seems like it risks losing valuable data if the filesystem
|
||||
* loses an inode during a crash. Better to write the data until we
|
||||
* are actually told to delete the file.)
|
||||
* But that seems like it risks losing valuable data if the
|
||||
* filesystem loses an inode during a crash. Better to write the
|
||||
* data until we are actually told to delete the file.)
|
||||
*/
|
||||
smgrcreate(res->reldata.rd_smgr, res->reldata.rd_istemp, true);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.192 2004/08/29 04:12:25 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.193 2004/08/29 05:06:41 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.106 2004/08/29 04:12:26 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.107 2004/08/29 05:06:41 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* See acl.h.
|
||||
@ -161,10 +161,11 @@ merge_acl_with_grant(Acl *old_acl, bool is_grant,
|
||||
|
||||
/*
|
||||
* The asymmetry in the conditions here comes from the spec. In
|
||||
* GRANT, the grant_option flag signals WITH GRANT OPTION, which means
|
||||
* to grant both the basic privilege and its grant option. But in
|
||||
* REVOKE, plain revoke revokes both the basic privilege and its
|
||||
* grant option, while REVOKE GRANT OPTION revokes only the option.
|
||||
* GRANT, the grant_option flag signals WITH GRANT OPTION, which
|
||||
* means to grant both the basic privilege and its grant option.
|
||||
* But in REVOKE, plain revoke revokes both the basic privilege
|
||||
* and its grant option, while REVOKE GRANT OPTION revokes only
|
||||
* the option.
|
||||
*/
|
||||
ACLITEM_SET_PRIVS_IDTYPE(aclitem,
|
||||
(is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS,
|
||||
@ -318,11 +319,11 @@ ExecuteGrantStmt_Relation(GrantStmt *stmt)
|
||||
|
||||
/*
|
||||
* Restrict the operation to what we can actually grant or revoke,
|
||||
* and issue a warning if appropriate. (For REVOKE this isn't quite
|
||||
* what the spec says to do: the spec seems to want a warning only
|
||||
* if no privilege bits actually change in the ACL. In practice
|
||||
* that behavior seems much too noisy, as well as inconsistent with
|
||||
* the GRANT case.)
|
||||
* and issue a warning if appropriate. (For REVOKE this isn't
|
||||
* quite what the spec says to do: the spec seems to want a
|
||||
* warning only if no privilege bits actually change in the ACL.
|
||||
* In practice that behavior seems much too noisy, as well as
|
||||
* inconsistent with the GRANT case.)
|
||||
*/
|
||||
this_privileges = privileges & my_goptions;
|
||||
if (stmt->is_grant)
|
||||
@ -476,11 +477,11 @@ ExecuteGrantStmt_Database(GrantStmt *stmt)
|
||||
|
||||
/*
|
||||
* Restrict the operation to what we can actually grant or revoke,
|
||||
* and issue a warning if appropriate. (For REVOKE this isn't quite
|
||||
* what the spec says to do: the spec seems to want a warning only
|
||||
* if no privilege bits actually change in the ACL. In practice
|
||||
* that behavior seems much too noisy, as well as inconsistent with
|
||||
* the GRANT case.)
|
||||
* and issue a warning if appropriate. (For REVOKE this isn't
|
||||
* quite what the spec says to do: the spec seems to want a
|
||||
* warning only if no privilege bits actually change in the ACL.
|
||||
* In practice that behavior seems much too noisy, as well as
|
||||
* inconsistent with the GRANT case.)
|
||||
*/
|
||||
this_privileges = privileges & my_goptions;
|
||||
if (stmt->is_grant)
|
||||
@ -630,11 +631,11 @@ ExecuteGrantStmt_Function(GrantStmt *stmt)
|
||||
|
||||
/*
|
||||
* Restrict the operation to what we can actually grant or revoke,
|
||||
* and issue a warning if appropriate. (For REVOKE this isn't quite
|
||||
* what the spec says to do: the spec seems to want a warning only
|
||||
* if no privilege bits actually change in the ACL. In practice
|
||||
* that behavior seems much too noisy, as well as inconsistent with
|
||||
* the GRANT case.)
|
||||
* and issue a warning if appropriate. (For REVOKE this isn't
|
||||
* quite what the spec says to do: the spec seems to want a
|
||||
* warning only if no privilege bits actually change in the ACL.
|
||||
* In practice that behavior seems much too noisy, as well as
|
||||
* inconsistent with the GRANT case.)
|
||||
*/
|
||||
this_privileges = privileges & my_goptions;
|
||||
if (stmt->is_grant)
|
||||
@ -793,11 +794,11 @@ ExecuteGrantStmt_Language(GrantStmt *stmt)
|
||||
|
||||
/*
|
||||
* Restrict the operation to what we can actually grant or revoke,
|
||||
* and issue a warning if appropriate. (For REVOKE this isn't quite
|
||||
* what the spec says to do: the spec seems to want a warning only
|
||||
* if no privilege bits actually change in the ACL. In practice
|
||||
* that behavior seems much too noisy, as well as inconsistent with
|
||||
* the GRANT case.)
|
||||
* and issue a warning if appropriate. (For REVOKE this isn't
|
||||
* quite what the spec says to do: the spec seems to want a
|
||||
* warning only if no privilege bits actually change in the ACL.
|
||||
* In practice that behavior seems much too noisy, as well as
|
||||
* inconsistent with the GRANT case.)
|
||||
*/
|
||||
this_privileges = privileges & my_goptions;
|
||||
if (stmt->is_grant)
|
||||
@ -946,11 +947,11 @@ ExecuteGrantStmt_Namespace(GrantStmt *stmt)
|
||||
|
||||
/*
|
||||
* Restrict the operation to what we can actually grant or revoke,
|
||||
* and issue a warning if appropriate. (For REVOKE this isn't quite
|
||||
* what the spec says to do: the spec seems to want a warning only
|
||||
* if no privilege bits actually change in the ACL. In practice
|
||||
* that behavior seems much too noisy, as well as inconsistent with
|
||||
* the GRANT case.)
|
||||
* and issue a warning if appropriate. (For REVOKE this isn't
|
||||
* quite what the spec says to do: the spec seems to want a
|
||||
* warning only if no privilege bits actually change in the ACL.
|
||||
* In practice that behavior seems much too noisy, as well as
|
||||
* inconsistent with the GRANT case.)
|
||||
*/
|
||||
this_privileges = privileges & my_goptions;
|
||||
if (stmt->is_grant)
|
||||
@ -1105,11 +1106,11 @@ ExecuteGrantStmt_Tablespace(GrantStmt *stmt)
|
||||
|
||||
/*
|
||||
* Restrict the operation to what we can actually grant or revoke,
|
||||
* and issue a warning if appropriate. (For REVOKE this isn't quite
|
||||
* what the spec says to do: the spec seems to want a warning only
|
||||
* if no privilege bits actually change in the ACL. In practice
|
||||
* that behavior seems much too noisy, as well as inconsistent with
|
||||
* the GRANT case.)
|
||||
* and issue a warning if appropriate. (For REVOKE this isn't
|
||||
* quite what the spec says to do: the spec seems to want a
|
||||
* warning only if no privilege bits actually change in the ACL.
|
||||
* In practice that behavior seems much too noisy, as well as
|
||||
* inconsistent with the GRANT case.)
|
||||
*/
|
||||
this_privileges = privileges & my_goptions;
|
||||
if (stmt->is_grant)
|
||||
@ -1389,11 +1390,12 @@ pg_class_aclmask(Oid table_oid, AclId userid,
|
||||
/*
|
||||
* Deny anyone permission to update a system catalog unless
|
||||
* pg_shadow.usecatupd is set. (This is to let superusers protect
|
||||
* themselves from themselves.) Also allow it if allowSystemTableMods.
|
||||
* themselves from themselves.) Also allow it if
|
||||
* allowSystemTableMods.
|
||||
*
|
||||
* As of 7.4 we have some updatable system views; those shouldn't
|
||||
* be protected in this way. Assume the view rules can take care
|
||||
* of themselves.
|
||||
* As of 7.4 we have some updatable system views; those shouldn't be
|
||||
* protected in this way. Assume the view rules can take care of
|
||||
* themselves.
|
||||
*/
|
||||
if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE)) &&
|
||||
IsSystemClass(classForm) &&
|
||||
@ -1648,23 +1650,23 @@ pg_namespace_aclmask(Oid nsp_oid, AclId userid,
|
||||
return mask;
|
||||
|
||||
/*
|
||||
* If we have been assigned this namespace as a temp namespace,
|
||||
* check to make sure we have CREATE TEMP permission on the database,
|
||||
* and if so act as though we have all standard (but not GRANT OPTION)
|
||||
* If we have been assigned this namespace as a temp namespace, check
|
||||
* to make sure we have CREATE TEMP permission on the database, and if
|
||||
* so act as though we have all standard (but not GRANT OPTION)
|
||||
* permissions on the namespace. If we don't have CREATE TEMP, act as
|
||||
* though we have only USAGE (and not CREATE) rights.
|
||||
*
|
||||
* This may seem redundant given the check in InitTempTableNamespace,
|
||||
* but it really isn't since current user ID may have changed since then.
|
||||
* This may seem redundant given the check in InitTempTableNamespace, but
|
||||
* it really isn't since current user ID may have changed since then.
|
||||
* The upshot of this behavior is that a SECURITY DEFINER function can
|
||||
* create temp tables that can then be accessed (if permission is granted)
|
||||
* by code in the same session that doesn't have permissions to create
|
||||
* temp tables.
|
||||
* create temp tables that can then be accessed (if permission is
|
||||
* granted) by code in the same session that doesn't have permissions
|
||||
* to create temp tables.
|
||||
*
|
||||
* XXX Would it be safe to ereport a special error message as
|
||||
* InitTempTableNamespace does? Returning zero here means we'll get a
|
||||
* generic "permission denied for schema pg_temp_N" message, which is not
|
||||
* remarkably user-friendly.
|
||||
* generic "permission denied for schema pg_temp_N" message, which is
|
||||
* not remarkably user-friendly.
|
||||
*/
|
||||
if (isTempNamespace(nsp_oid))
|
||||
{
|
||||
@ -1731,8 +1733,8 @@ pg_tablespace_aclmask(Oid spc_oid, AclId userid,
|
||||
AclId ownerId;
|
||||
|
||||
/*
|
||||
* Only shared relations can be stored in global space; don't let
|
||||
* even superusers override this
|
||||
* Only shared relations can be stored in global space; don't let even
|
||||
* superusers override this
|
||||
*/
|
||||
if (spc_oid == GLOBALTABLESPACE_OID && !IsBootstrapProcessingMode())
|
||||
return 0;
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.38 2004/08/29 04:12:27 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.39 2004/08/29 05:06:41 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -970,6 +970,7 @@ find_expr_references_walker(Node *node,
|
||||
if (var->varno <= 0 || var->varno > list_length(rtable))
|
||||
elog(ERROR, "invalid varno %d", var->varno);
|
||||
rte = rt_fetch(var->varno, rtable);
|
||||
|
||||
/*
|
||||
* A whole-row Var references no specific columns, so adds no new
|
||||
* dependency.
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.274 2004/08/29 04:12:27 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.275 2004/08/29 05:06:41 momjian Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
@ -265,10 +265,10 @@ heap_create(const char *relname,
|
||||
|
||||
/*
|
||||
* Never allow a pg_class entry to explicitly specify the database's
|
||||
* default tablespace in reltablespace; force it to zero instead.
|
||||
* This ensures that if the database is cloned with a different
|
||||
* default tablespace, the pg_class entry will still match where
|
||||
* CREATE DATABASE will put the physically copied relation.
|
||||
* default tablespace in reltablespace; force it to zero instead. This
|
||||
* ensures that if the database is cloned with a different default
|
||||
* tablespace, the pg_class entry will still match where CREATE
|
||||
* DATABASE will put the physically copied relation.
|
||||
*
|
||||
* Yes, this is a bit of a hack.
|
||||
*/
|
||||
@ -294,7 +294,8 @@ heap_create(const char *relname,
|
||||
nailme);
|
||||
|
||||
/*
|
||||
* have the storage manager create the relation's disk file, if needed.
|
||||
* have the storage manager create the relation's disk file, if
|
||||
* needed.
|
||||
*/
|
||||
if (create_storage)
|
||||
{
|
||||
@ -980,12 +981,12 @@ RemoveAttributeById(Oid relid, AttrNumber attnum)
|
||||
|
||||
/*
|
||||
* Set the type OID to invalid. A dropped attribute's type link
|
||||
* cannot be relied on (once the attribute is dropped, the type might
|
||||
* be too). Fortunately we do not need the type row --- the only
|
||||
* really essential information is the type's typlen and typalign,
|
||||
* which are preserved in the attribute's attlen and attalign. We set
|
||||
* atttypid to zero here as a means of catching code that incorrectly
|
||||
* expects it to be valid.
|
||||
* cannot be relied on (once the attribute is dropped, the type
|
||||
* might be too). Fortunately we do not need the type row --- the
|
||||
* only really essential information is the type's typlen and
|
||||
* typalign, which are preserved in the attribute's attlen and
|
||||
* attalign. We set atttypid to zero here as a means of catching
|
||||
* code that incorrectly expects it to be valid.
|
||||
*/
|
||||
attStruct->atttypid = InvalidOid;
|
||||
|
||||
@ -995,7 +996,10 @@ RemoveAttributeById(Oid relid, AttrNumber attnum)
|
||||
/* We don't want to keep stats for it anymore */
|
||||
attStruct->attstattarget = 0;
|
||||
|
||||
/* Change the column name to something that isn't likely to conflict */
|
||||
/*
|
||||
* Change the column name to something that isn't likely to
|
||||
* conflict
|
||||
*/
|
||||
snprintf(newattname, sizeof(newattname),
|
||||
"........pg.dropped.%d........", attnum);
|
||||
namestrcpy(&(attStruct->attname), newattname);
|
||||
@ -1623,15 +1627,15 @@ AddRelationRawConstraints(Relation rel,
|
||||
/*
|
||||
* When generating a name, we want to create "tab_col_check"
|
||||
* for a column constraint and "tab_check" for a table
|
||||
* constraint. We no longer have any info about the
|
||||
* syntactic positioning of the constraint phrase, so we
|
||||
* approximate this by seeing whether the expression references
|
||||
* more than one column. (If the user played by the rules,
|
||||
* the result is the same...)
|
||||
* constraint. We no longer have any info about the syntactic
|
||||
* positioning of the constraint phrase, so we approximate
|
||||
* this by seeing whether the expression references more than
|
||||
* one column. (If the user played by the rules, the result
|
||||
* is the same...)
|
||||
*
|
||||
* Note: pull_var_clause() doesn't descend into sublinks,
|
||||
* but we eliminated those above; and anyway this only needs
|
||||
* to be an approximate answer.
|
||||
* Note: pull_var_clause() doesn't descend into sublinks, but we
|
||||
* eliminated those above; and anyway this only needs to be an
|
||||
* approximate answer.
|
||||
*/
|
||||
List *vars;
|
||||
char *colname;
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.237 2004/08/29 04:12:27 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.238 2004/08/29 05:06:41 momjian Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
@ -511,9 +511,10 @@ index_create(Oid heapRelationId,
|
||||
* We cannot allow indexing a shared relation after initdb (because
|
||||
* there's no way to make the entry in other databases' pg_class).
|
||||
* Unfortunately we can't distinguish initdb from a manually started
|
||||
* standalone backend (toasting of shared rels happens after the bootstrap
|
||||
* phase, so checking IsBootstrapProcessingMode() won't work). However,
|
||||
* we can at least prevent this mistake under normal multi-user operation.
|
||||
* standalone backend (toasting of shared rels happens after the
|
||||
* bootstrap phase, so checking IsBootstrapProcessingMode() won't
|
||||
* work). However, we can at least prevent this mistake under normal
|
||||
* multi-user operation.
|
||||
*/
|
||||
if (shared_relation && IsUnderPostmaster)
|
||||
ereport(ERROR,
|
||||
@ -800,8 +801,8 @@ index_drop(Oid indexId)
|
||||
|
||||
/*
|
||||
* Close and flush the index's relcache entry, to ensure relcache
|
||||
* doesn't try to rebuild it while we're deleting catalog entries.
|
||||
* We keep the lock though.
|
||||
* doesn't try to rebuild it while we're deleting catalog entries. We
|
||||
* keep the lock though.
|
||||
*/
|
||||
index_close(userIndexRelation);
|
||||
|
||||
@ -826,8 +827,8 @@ index_drop(Oid indexId)
|
||||
heap_close(indexRelation, RowExclusiveLock);
|
||||
|
||||
/*
|
||||
* if it has any expression columns, we might have stored
|
||||
* statistics about them.
|
||||
* if it has any expression columns, we might have stored statistics
|
||||
* about them.
|
||||
*/
|
||||
if (hasexprs)
|
||||
RemoveStatistics(indexId, 0);
|
||||
@ -1206,12 +1207,12 @@ UpdateStats(Oid relid, double reltuples)
|
||||
|
||||
/*
|
||||
* Find the tuple to update in pg_class. Normally we make a copy of
|
||||
* the tuple using the syscache, modify it, and apply heap_update.
|
||||
* But in bootstrap mode we can't use heap_update, so we cheat and
|
||||
* the tuple using the syscache, modify it, and apply heap_update. But
|
||||
* in bootstrap mode we can't use heap_update, so we cheat and
|
||||
* overwrite the tuple in-place.
|
||||
*
|
||||
* We also must cheat if reindexing pg_class itself, because the
|
||||
* target index may presently not be part of the set of indexes that
|
||||
* We also must cheat if reindexing pg_class itself, because the target
|
||||
* index may presently not be part of the set of indexes that
|
||||
* CatalogUpdateIndexes would update (see reindex_relation). In this
|
||||
* case the stats updates will not be WAL-logged and so could be lost
|
||||
* in a crash. This seems OK considering VACUUM does the same thing.
|
||||
@ -1659,11 +1660,11 @@ reindex_index(Oid indexId)
|
||||
* Note: for REINDEX INDEX, doing this before opening the parent heap
|
||||
* relation means there's a possibility for deadlock failure against
|
||||
* another xact that is doing normal accesses to the heap and index.
|
||||
* However, it's not real clear why you'd be wanting to do REINDEX INDEX
|
||||
* on a table that's in active use, so I'd rather have the protection of
|
||||
* making sure the index is locked down. In the REINDEX TABLE and
|
||||
* REINDEX DATABASE cases, there is no problem because caller already
|
||||
* holds exclusive lock on the parent table.
|
||||
* However, it's not real clear why you'd be wanting to do REINDEX
|
||||
* INDEX on a table that's in active use, so I'd rather have the
|
||||
* protection of making sure the index is locked down. In the REINDEX
|
||||
* TABLE and REINDEX DATABASE cases, there is no problem because
|
||||
* caller already holds exclusive lock on the parent table.
|
||||
*/
|
||||
iRel = index_open(indexId);
|
||||
LockRelation(iRel, AccessExclusiveLock);
|
||||
@ -1680,8 +1681,8 @@ reindex_index(Oid indexId)
|
||||
* we can do it the normal transaction-safe way.
|
||||
*
|
||||
* Since inplace processing isn't crash-safe, we only allow it in a
|
||||
* standalone backend. (In the REINDEX TABLE and REINDEX DATABASE cases,
|
||||
* the caller should have detected this.)
|
||||
* standalone backend. (In the REINDEX TABLE and REINDEX DATABASE
|
||||
* cases, the caller should have detected this.)
|
||||
*/
|
||||
inplace = iRel->rd_rel->relisshared;
|
||||
|
||||
@ -1705,7 +1706,8 @@ reindex_index(Oid indexId)
|
||||
{
|
||||
/*
|
||||
* Release any buffers associated with this index. If they're
|
||||
* dirty, they're just dropped without bothering to flush to disk.
|
||||
* dirty, they're just dropped without bothering to flush to
|
||||
* disk.
|
||||
*/
|
||||
DropRelationBuffers(iRel);
|
||||
|
||||
@ -1724,8 +1726,8 @@ reindex_index(Oid indexId)
|
||||
index_build(heapRelation, iRel, indexInfo);
|
||||
|
||||
/*
|
||||
* index_build will close both the heap and index relations (but not
|
||||
* give up the locks we hold on them). So we're done.
|
||||
* index_build will close both the heap and index relations (but
|
||||
* not give up the locks we hold on them). So we're done.
|
||||
*/
|
||||
}
|
||||
PG_CATCH();
|
||||
@ -1774,13 +1776,13 @@ reindex_relation(Oid relid, bool toast_too)
|
||||
|
||||
/*
|
||||
* reindex_index will attempt to update the pg_class rows for the
|
||||
* relation and index. If we are processing pg_class itself, we
|
||||
* want to make sure that the updates do not try to insert index
|
||||
* entries into indexes we have not processed yet. (When we are
|
||||
* trying to recover from corrupted indexes, that could easily
|
||||
* cause a crash.) We can accomplish this because CatalogUpdateIndexes
|
||||
* will use the relcache's index list to know which indexes to update.
|
||||
* We just force the index list to be only the stuff we've processed.
|
||||
* relation and index. If we are processing pg_class itself, we want
|
||||
* to make sure that the updates do not try to insert index entries
|
||||
* into indexes we have not processed yet. (When we are trying to
|
||||
* recover from corrupted indexes, that could easily cause a crash.)
|
||||
* We can accomplish this because CatalogUpdateIndexes will use the
|
||||
* relcache's index list to know which indexes to update. We just
|
||||
* force the index list to be only the stuff we've processed.
|
||||
*
|
||||
* It is okay to not insert entries into the indexes we have not
|
||||
* processed yet because all of this is transaction-safe. If we fail
|
||||
@ -1819,8 +1821,8 @@ reindex_relation(Oid relid, bool toast_too)
|
||||
result = (indexIds != NIL);
|
||||
|
||||
/*
|
||||
* If the relation has a secondary toast rel, reindex that too while we
|
||||
* still hold the lock on the master table.
|
||||
* If the relation has a secondary toast rel, reindex that too while
|
||||
* we still hold the lock on the master table.
|
||||
*/
|
||||
if (toast_too && OidIsValid(toast_relid))
|
||||
result |= reindex_relation(toast_relid, false);
|
||||
|
@ -13,7 +13,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.69 2004/08/29 04:12:28 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.70 2004/08/29 05:06:41 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -699,12 +699,13 @@ OpernameGetCandidates(List *names, char oprkind)
|
||||
|
||||
/*
|
||||
* In typical scenarios, most if not all of the operators found by the
|
||||
* catcache search will end up getting returned; and there can be quite
|
||||
* a few, for common operator names such as '=' or '+'. To reduce the
|
||||
* time spent in palloc, we allocate the result space as an array large
|
||||
* enough to hold all the operators. The original coding of this routine
|
||||
* did a separate palloc for each operator, but profiling revealed that
|
||||
* the pallocs used an unreasonably large fraction of parsing time.
|
||||
* catcache search will end up getting returned; and there can be
|
||||
* quite a few, for common operator names such as '=' or '+'. To
|
||||
* reduce the time spent in palloc, we allocate the result space as an
|
||||
* array large enough to hold all the operators. The original coding
|
||||
* of this routine did a separate palloc for each operator, but
|
||||
* profiling revealed that the pallocs used an unreasonably large
|
||||
* fraction of parsing time.
|
||||
*/
|
||||
#define SPACE_PER_OP MAXALIGN(sizeof(struct _FuncCandidateList) + sizeof(Oid))
|
||||
|
||||
@ -1645,10 +1646,11 @@ InitTempTableNamespace(void)
|
||||
* tables. We use a nonstandard error message here since
|
||||
* "databasename: permission denied" might be a tad cryptic.
|
||||
*
|
||||
* Note that ACL_CREATE_TEMP rights are rechecked in pg_namespace_aclmask;
|
||||
* that's necessary since current user ID could change during the session.
|
||||
* But there's no need to make the namespace in the first place until a
|
||||
* temp table creation request is made by someone with appropriate rights.
|
||||
* Note that ACL_CREATE_TEMP rights are rechecked in
|
||||
* pg_namespace_aclmask; that's necessary since current user ID could
|
||||
* change during the session. But there's no need to make the
|
||||
* namespace in the first place until a temp table creation request is
|
||||
* made by someone with appropriate rights.
|
||||
*/
|
||||
if (pg_database_aclcheck(MyDatabaseId, GetUserId(),
|
||||
ACL_CREATE_TEMP) != ACLCHECK_OK)
|
||||
@ -1847,7 +1849,8 @@ assign_search_path(const char *newval, bool doit, GucSource source)
|
||||
* ALTER DATABASE SET or ALTER USER SET command. It could be that
|
||||
* the intended use of the search path is for some other database,
|
||||
* so we should not error out if it mentions schemas not present
|
||||
* in the current database. We reduce the message to NOTICE instead.
|
||||
* in the current database. We reduce the message to NOTICE
|
||||
* instead.
|
||||
*/
|
||||
foreach(l, namelist)
|
||||
{
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.67 2004/08/29 04:12:28 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.68 2004/08/29 05:06:41 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.118 2004/08/29 04:12:29 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.119 2004/08/29 05:06:41 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -562,8 +562,9 @@ check_sql_fn_retval(Oid rettype, char fn_typtype, List *queryTreeList)
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise assume we are returning the whole tuple. Crosschecking
|
||||
* against what the caller expects will happen at runtime.
|
||||
* Otherwise assume we are returning the whole tuple.
|
||||
* Crosschecking against what the caller expects will happen at
|
||||
* runtime.
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
@ -652,9 +653,10 @@ fmgr_c_validator(PG_FUNCTION_ARGS)
|
||||
char *probin;
|
||||
|
||||
/*
|
||||
* It'd be most consistent to skip the check if !check_function_bodies,
|
||||
* but the purpose of that switch is to be helpful for pg_dump loading,
|
||||
* and for pg_dump loading it's much better if we *do* check.
|
||||
* It'd be most consistent to skip the check if
|
||||
* !check_function_bodies, but the purpose of that switch is to be
|
||||
* helpful for pg_dump loading, and for pg_dump loading it's much
|
||||
* better if we *do* check.
|
||||
*/
|
||||
|
||||
tuple = SearchSysCache(PROCOID,
|
||||
@ -760,10 +762,10 @@ fmgr_sql_validator(PG_FUNCTION_ARGS)
|
||||
error_context_stack = &sqlerrcontext;
|
||||
|
||||
/*
|
||||
* We can't do full prechecking of the function definition if there
|
||||
* are any polymorphic input types, because actual datatypes of
|
||||
* expression results will be unresolvable. The check will be done
|
||||
* at runtime instead.
|
||||
* We can't do full prechecking of the function definition if
|
||||
* there are any polymorphic input types, because actual datatypes
|
||||
* of expression results will be unresolvable. The check will be
|
||||
* done at runtime instead.
|
||||
*
|
||||
* We can run the text through the raw parser though; this will at
|
||||
* least catch silly syntactic errors.
|
||||
@ -832,11 +834,11 @@ function_parse_error_transpose(const char *prosrc)
|
||||
const char *queryText;
|
||||
|
||||
/*
|
||||
* Nothing to do unless we are dealing with a syntax error that has
|
||||
* a cursor position.
|
||||
* Nothing to do unless we are dealing with a syntax error that has a
|
||||
* cursor position.
|
||||
*
|
||||
* Some PLs may prefer to report the error position as an internal
|
||||
* error to begin with, so check that too.
|
||||
* Some PLs may prefer to report the error position as an internal error
|
||||
* to begin with, so check that too.
|
||||
*/
|
||||
origerrposition = geterrposition();
|
||||
if (origerrposition <= 0)
|
||||
@ -918,8 +920,9 @@ match_prosrc_to_query(const char *prosrc, const char *queryText,
|
||||
cursorpos, &newcursorpos))
|
||||
{
|
||||
/*
|
||||
* Found a 'foo' match. match_prosrc_to_literal() has adjusted
|
||||
* for any quotes or backslashes embedded in the literal.
|
||||
* Found a 'foo' match. match_prosrc_to_literal() has
|
||||
* adjusted for any quotes or backslashes embedded in the
|
||||
* literal.
|
||||
*/
|
||||
if (matchpos)
|
||||
return 0; /* multiple matches, fail */
|
||||
@ -951,12 +954,13 @@ match_prosrc_to_literal(const char *prosrc, const char *literal,
|
||||
* string literal. It does not handle the SQL syntax for literals
|
||||
* continued across line boundaries.
|
||||
*
|
||||
* We do the comparison a character at a time, not a byte at a time,
|
||||
* so that we can do the correct cursorpos math.
|
||||
* We do the comparison a character at a time, not a byte at a time, so
|
||||
* that we can do the correct cursorpos math.
|
||||
*/
|
||||
while (*prosrc)
|
||||
{
|
||||
cursorpos--; /* characters left before cursor */
|
||||
|
||||
/*
|
||||
* Check for backslashes and doubled quotes in the literal; adjust
|
||||
* newcp when one is found before the cursor.
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.95 2004/08/29 04:12:29 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.96 2004/08/29 05:06:41 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.20 2004/08/29 04:12:29 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.21 2004/08/29 05:06:41 momjian Exp $
|
||||
*
|
||||
* DESCRIPTION
|
||||
* The "DefineFoo" routines take the parse tree and pick out the
|
||||
@ -223,9 +223,9 @@ RenameAggregate(List *name, TypeName *basetype, const char *newname)
|
||||
|
||||
/*
|
||||
* if a basetype is passed in, then attempt to find an aggregate for
|
||||
* that specific type; else attempt to find an aggregate with a basetype
|
||||
* of ANYOID. This means that the aggregate applies to all basetypes
|
||||
* (eg, COUNT).
|
||||
* that specific type; else attempt to find an aggregate with a
|
||||
* basetype of ANYOID. This means that the aggregate applies to all
|
||||
* basetypes (eg, COUNT).
|
||||
*/
|
||||
if (basetype)
|
||||
basetypeOid = typenameTypeId(basetype);
|
||||
@ -302,9 +302,9 @@ AlterAggregateOwner(List *name, TypeName *basetype, AclId newOwnerSysId)
|
||||
|
||||
/*
|
||||
* if a basetype is passed in, then attempt to find an aggregate for
|
||||
* that specific type; else attempt to find an aggregate with a basetype
|
||||
* of ANYOID. This means that the aggregate applies to all basetypes
|
||||
* (eg, COUNT).
|
||||
* that specific type; else attempt to find an aggregate with a
|
||||
* basetype of ANYOID. This means that the aggregate applies to all
|
||||
* basetypes (eg, COUNT).
|
||||
*/
|
||||
if (basetype)
|
||||
basetypeOid = typenameTypeId(basetype);
|
||||
@ -334,7 +334,10 @@ AlterAggregateOwner(List *name, TypeName *basetype, AclId newOwnerSysId)
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("must be superuser to change owner")));
|
||||
|
||||
/* Modify the owner --- okay to scribble on tup because it's a copy */
|
||||
/*
|
||||
* Modify the owner --- okay to scribble on tup because it's a
|
||||
* copy
|
||||
*/
|
||||
procForm->proowner = newOwnerSysId;
|
||||
|
||||
simple_heap_update(rel, &tup->t_self, tup);
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/commands/alter.c,v 1.10 2004/08/29 04:12:29 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/commands/alter.c,v 1.11 2004/08/29 05:06:41 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.75 2004/08/29 04:12:29 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.76 2004/08/29 05:06:41 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -157,9 +157,8 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that it's a plain table; we used to do this in
|
||||
* get_rel_oids() but seems safer to check after we've locked the
|
||||
* relation.
|
||||
* Check that it's a plain table; we used to do this in get_rel_oids()
|
||||
* but seems safer to check after we've locked the relation.
|
||||
*/
|
||||
if (onerel->rd_rel->relkind != RELKIND_RELATION)
|
||||
{
|
||||
@ -239,9 +238,10 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
|
||||
}
|
||||
|
||||
/*
|
||||
* Open all indexes of the relation, and see if there are any analyzable
|
||||
* columns in the indexes. We do not analyze index columns if there was
|
||||
* an explicit column list in the ANALYZE command, however.
|
||||
* Open all indexes of the relation, and see if there are any
|
||||
* analyzable columns in the indexes. We do not analyze index columns
|
||||
* if there was an explicit column list in the ANALYZE command,
|
||||
* however.
|
||||
*/
|
||||
vac_open_indexes(onerel, &nindexes, &Irel);
|
||||
hasindex = (nindexes > 0);
|
||||
@ -279,12 +279,13 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
|
||||
indexpr_item = lnext(indexpr_item);
|
||||
|
||||
/*
|
||||
* Can't analyze if the opclass uses a storage type
|
||||
* different from the expression result type. We'd
|
||||
* get confused because the type shown in pg_attribute
|
||||
* for the index column doesn't match what we are
|
||||
* getting from the expression. Perhaps this can be
|
||||
* fixed someday, but for now, punt.
|
||||
* Can't analyze if the opclass uses a storage
|
||||
* type different from the expression result type.
|
||||
* We'd get confused because the type shown in
|
||||
* pg_attribute for the index column doesn't match
|
||||
* what we are getting from the expression.
|
||||
* Perhaps this can be fixed someday, but for now,
|
||||
* punt.
|
||||
*/
|
||||
if (exprType(indexkey) !=
|
||||
Irel[ind]->rd_att->attrs[i]->atttypid)
|
||||
@ -401,9 +402,9 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
|
||||
|
||||
/*
|
||||
* If we are running a standalone ANALYZE, update pages/tuples stats
|
||||
* in pg_class. We know the accurate page count from the smgr,
|
||||
* but only an approximate number of tuples; therefore, if we are part
|
||||
* of VACUUM ANALYZE do *not* overwrite the accurate count already
|
||||
* in pg_class. We know the accurate page count from the smgr, but
|
||||
* only an approximate number of tuples; therefore, if we are part of
|
||||
* VACUUM ANALYZE do *not* overwrite the accurate count already
|
||||
* inserted by VACUUM. The same consideration applies to indexes.
|
||||
*/
|
||||
if (!vacstmt->vacuum)
|
||||
@ -526,8 +527,9 @@ compute_index_stats(Relation onerel, double totalrows,
|
||||
if (attr_cnt > 0)
|
||||
{
|
||||
/*
|
||||
* Evaluate the index row to compute expression values.
|
||||
* We could do this by hand, but FormIndexDatum is convenient.
|
||||
* Evaluate the index row to compute expression values. We
|
||||
* could do this by hand, but FormIndexDatum is
|
||||
* convenient.
|
||||
*/
|
||||
FormIndexDatum(indexInfo,
|
||||
heapTuple,
|
||||
@ -535,6 +537,7 @@ compute_index_stats(Relation onerel, double totalrows,
|
||||
estate,
|
||||
attdata,
|
||||
nulls);
|
||||
|
||||
/*
|
||||
* Save just the columns we care about.
|
||||
*/
|
||||
@ -552,7 +555,8 @@ compute_index_stats(Relation onerel, double totalrows,
|
||||
|
||||
/*
|
||||
* Having counted the number of rows that pass the predicate in
|
||||
* the sample, we can estimate the total number of rows in the index.
|
||||
* the sample, we can estimate the total number of rows in the
|
||||
* index.
|
||||
*/
|
||||
thisdata->tupleFract = (double) numindexrows / (double) numrows;
|
||||
totalindexrows = ceil(thisdata->tupleFract * totalrows);
|
||||
@ -667,10 +671,10 @@ static void
|
||||
BlockSampler_Init(BlockSampler bs, BlockNumber nblocks, int samplesize)
|
||||
{
|
||||
bs->N = nblocks; /* measured table size */
|
||||
|
||||
/*
|
||||
* If we decide to reduce samplesize for tables that have less or
|
||||
* not much more than samplesize blocks, here is the place to do
|
||||
* it.
|
||||
* If we decide to reduce samplesize for tables that have less or not
|
||||
* much more than samplesize blocks, here is the place to do it.
|
||||
*/
|
||||
bs->n = samplesize;
|
||||
bs->t = 0; /* blocks scanned so far */
|
||||
@ -826,14 +830,13 @@ acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
|
||||
{
|
||||
/*
|
||||
* The first targrows live rows are simply copied into the
|
||||
* reservoir.
|
||||
* Then we start replacing tuples in the sample until
|
||||
* we reach the end of the relation. This algorithm is
|
||||
* from Jeff Vitter's paper (see full citation below).
|
||||
* reservoir. Then we start replacing tuples in the sample
|
||||
* until we reach the end of the relation. This algorithm
|
||||
* is from Jeff Vitter's paper (see full citation below).
|
||||
* It works by repeatedly computing the number of tuples
|
||||
* to skip before selecting a tuple, which replaces a
|
||||
* randomly chosen element of the reservoir (current
|
||||
* set of tuples). At all times the reservoir is a true
|
||||
* randomly chosen element of the reservoir (current set
|
||||
* of tuples). At all times the reservoir is a true
|
||||
* random sample of the tuples we've passed over so far,
|
||||
* so when we fall off the end of the relation we're done.
|
||||
*/
|
||||
@ -842,10 +845,10 @@ acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
|
||||
else
|
||||
{
|
||||
/*
|
||||
* t in Vitter's paper is the number of records already
|
||||
* processed. If we need to compute a new S value, we
|
||||
* must use the not-yet-incremented value of liverows
|
||||
* as t.
|
||||
* t in Vitter's paper is the number of records
|
||||
* already processed. If we need to compute a new S
|
||||
* value, we must use the not-yet-incremented value of
|
||||
* liverows as t.
|
||||
*/
|
||||
if (rowstoskip < 0)
|
||||
rowstoskip = get_next_S(liverows, targrows, &rstate);
|
||||
@ -853,8 +856,8 @@ acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
|
||||
if (rowstoskip <= 0)
|
||||
{
|
||||
/*
|
||||
* Found a suitable tuple, so save it,
|
||||
* replacing one old tuple at random
|
||||
* Found a suitable tuple, so save it, replacing
|
||||
* one old tuple at random
|
||||
*/
|
||||
int k = (int) (targrows * random_fract());
|
||||
|
||||
@ -874,9 +877,9 @@ acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Count dead rows, but not empty slots. This information is
|
||||
* currently not used, but it seems likely we'll want it
|
||||
* someday.
|
||||
* Count dead rows, but not empty slots. This information
|
||||
* is currently not used, but it seems likely we'll want
|
||||
* it someday.
|
||||
*/
|
||||
if (targtuple.t_data != NULL)
|
||||
deadrows += 1;
|
||||
@ -888,12 +891,12 @@ acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
|
||||
}
|
||||
|
||||
/*
|
||||
* If we didn't find as many tuples as we wanted then we're done.
|
||||
* No sort is needed, since they're already in order.
|
||||
* If we didn't find as many tuples as we wanted then we're done. No
|
||||
* sort is needed, since they're already in order.
|
||||
*
|
||||
* Otherwise we need to sort the collected tuples by position
|
||||
* (itempointer). It's not worth worrying about corner cases
|
||||
* where the tuples are already sorted.
|
||||
* (itempointer). It's not worth worrying about corner cases where
|
||||
* the tuples are already sorted.
|
||||
*/
|
||||
if (numrows == targrows)
|
||||
qsort((void *) rows, numrows, sizeof(HeapTuple), compare_rows);
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/commands/async.c,v 1.114 2004/08/29 04:12:29 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/commands/async.c,v 1.115 2004/08/29 05:06:41 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -106,7 +106,8 @@
|
||||
*/
|
||||
static List *pendingNotifies = NIL;
|
||||
|
||||
static List *upperPendingNotifies = NIL; /* list of upper-xact lists */
|
||||
static List *upperPendingNotifies = NIL; /* list of upper-xact
|
||||
* lists */
|
||||
|
||||
/*
|
||||
* State for inbound notifies consists of two flags: one saying whether
|
||||
@ -524,20 +525,22 @@ AtCommit_Notify(void)
|
||||
|
||||
rTuple = heap_modifytuple(lTuple, lRel,
|
||||
value, nulls, repl);
|
||||
|
||||
/*
|
||||
* We cannot use simple_heap_update here because the tuple
|
||||
* could have been modified by an uncommitted transaction;
|
||||
* specifically, since UNLISTEN releases exclusive lock on
|
||||
* the table before commit, the other guy could already have
|
||||
* tried to unlisten. There are no other cases where we
|
||||
* should be able to see an uncommitted update or delete.
|
||||
* Therefore, our response to a HeapTupleBeingUpdated result
|
||||
* is just to ignore it. We do *not* wait for the other
|
||||
* guy to commit --- that would risk deadlock, and we don't
|
||||
* want to block while holding the table lock anyway for
|
||||
* performance reasons. We also ignore HeapTupleUpdated,
|
||||
* which could occur if the other guy commits between our
|
||||
* heap_getnext and heap_update calls.
|
||||
* the table before commit, the other guy could already
|
||||
* have tried to unlisten. There are no other cases where
|
||||
* we should be able to see an uncommitted update or
|
||||
* delete. Therefore, our response to a
|
||||
* HeapTupleBeingUpdated result is just to ignore it. We
|
||||
* do *not* wait for the other guy to commit --- that
|
||||
* would risk deadlock, and we don't want to block while
|
||||
* holding the table lock anyway for performance reasons.
|
||||
* We also ignore HeapTupleUpdated, which could occur if
|
||||
* the other guy commits between our heap_getnext and
|
||||
* heap_update calls.
|
||||
*/
|
||||
result = heap_update(lRel, &lTuple->t_self, rTuple,
|
||||
&ctid,
|
||||
@ -646,7 +649,8 @@ AtSubCommit_Notify(void)
|
||||
upperPendingNotifies = list_delete_first(upperPendingNotifies);
|
||||
|
||||
/*
|
||||
* We could try to eliminate duplicates here, but it seems not worthwhile.
|
||||
* We could try to eliminate duplicates here, but it seems not
|
||||
* worthwhile.
|
||||
*/
|
||||
pendingNotifies = list_concat(parentPendingNotifies, pendingNotifies);
|
||||
}
|
||||
@ -914,11 +918,12 @@ ProcessIncomingNotify(void)
|
||||
relname, (int) sourcePID);
|
||||
|
||||
NotifyMyFrontEnd(relname, sourcePID);
|
||||
|
||||
/*
|
||||
* Rewrite the tuple with 0 in notification column.
|
||||
*
|
||||
* simple_heap_update is safe here because no one else would
|
||||
* have tried to UNLISTEN us, so there can be no uncommitted
|
||||
* simple_heap_update is safe here because no one else would have
|
||||
* tried to UNLISTEN us, so there can be no uncommitted
|
||||
* changes.
|
||||
*/
|
||||
rTuple = heap_modifytuple(lTuple, lRel, value, nulls, repl);
|
||||
|
@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.128 2004/08/29 04:12:29 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.129 2004/08/29 05:06:41 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -286,8 +286,8 @@ cluster_rel(RelToCluster *rvtc, bool recheck)
|
||||
/*
|
||||
* We grab exclusive access to the target rel and index for the
|
||||
* duration of the transaction. (This is redundant for the single-
|
||||
* transaction case, since cluster() already did it.) The index
|
||||
* lock is taken inside check_index_is_clusterable.
|
||||
* transaction case, since cluster() already did it.) The index lock
|
||||
* is taken inside check_index_is_clusterable.
|
||||
*/
|
||||
OldHeap = heap_open(rvtc->tableOid, AccessExclusiveLock);
|
||||
|
||||
@ -540,8 +540,8 @@ rebuild_relation(Relation OldHeap, Oid indexOid)
|
||||
/* performDeletion does CommandCounterIncrement at end */
|
||||
|
||||
/*
|
||||
* Rebuild each index on the relation (but not the toast table,
|
||||
* which is all-new at this point). We do not need
|
||||
* Rebuild each index on the relation (but not the toast table, which
|
||||
* is all-new at this point). We do not need
|
||||
* CommandCounterIncrement() because reindex_relation does it.
|
||||
*/
|
||||
reindex_relation(tableOid, false);
|
||||
@ -745,8 +745,8 @@ swap_relation_files(Oid r1, Oid r2)
|
||||
* their new owning relations. Otherwise the wrong one will get
|
||||
* dropped ...
|
||||
*
|
||||
* NOTE: it is possible that only one table has a toast table; this
|
||||
* can happen in CLUSTER if there were dropped columns in the old table,
|
||||
* NOTE: it is possible that only one table has a toast table; this can
|
||||
* happen in CLUSTER if there were dropped columns in the old table,
|
||||
* and in ALTER TABLE when adding or changing type of columns.
|
||||
*
|
||||
* NOTE: at present, a TOAST table's only dependency is the one on its
|
||||
@ -802,15 +802,15 @@ swap_relation_files(Oid r1, Oid r2)
|
||||
/*
|
||||
* Blow away the old relcache entries now. We need this kluge because
|
||||
* relcache.c keeps a link to the smgr relation for the physical file,
|
||||
* and that will be out of date as soon as we do CommandCounterIncrement.
|
||||
* Whichever of the rels is the second to be cleared during cache
|
||||
* invalidation will have a dangling reference to an already-deleted smgr
|
||||
* relation. Rather than trying to avoid this by ordering operations
|
||||
* just so, it's easiest to not have the relcache entries there at all.
|
||||
* (Fortunately, since one of the entries is local in our transaction,
|
||||
* it's sufficient to clear out our own relcache this way; the problem
|
||||
* cannot arise for other backends when they see our update on the
|
||||
* non-local relation.)
|
||||
* and that will be out of date as soon as we do
|
||||
* CommandCounterIncrement. Whichever of the rels is the second to be
|
||||
* cleared during cache invalidation will have a dangling reference to
|
||||
* an already-deleted smgr relation. Rather than trying to avoid this
|
||||
* by ordering operations just so, it's easiest to not have the
|
||||
* relcache entries there at all. (Fortunately, since one of the
|
||||
* entries is local in our transaction, it's sufficient to clear out
|
||||
* our own relcache this way; the problem cannot arise for other
|
||||
* backends when they see our update on the non-local relation.)
|
||||
*/
|
||||
RelationForgetRelation(r1);
|
||||
RelationForgetRelation(r2);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user