pgindent run for 8.2.
This commit is contained in:
parent
451e419e98
commit
f99a569a2e
|
@ -8,7 +8,7 @@
|
|||
* Author: Andreas Pflug <pgadmin@pse-consulting.de>
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/contrib/adminpack/adminpack.c,v 1.3 2006/07/11 16:35:30 momjian Exp $
|
||||
* $PostgreSQL: pgsql/contrib/adminpack/adminpack.c,v 1.4 2006/10/04 00:29:44 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -35,7 +35,6 @@
|
|||
#ifdef unlink
|
||||
#undef unlink
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
extern DLLIMPORT char *DataDir;
|
||||
|
@ -68,7 +67,8 @@ typedef struct
|
|||
* Return an absolute path. Argument may be absolute or
|
||||
* relative to the DataDir.
|
||||
*/
|
||||
static char *absClusterPath(text *arg, bool logAllowed)
|
||||
static char *
|
||||
absClusterPath(text *arg, bool logAllowed)
|
||||
{
|
||||
char *filename;
|
||||
int len = VARSIZE(arg) - VARHDRSZ;
|
||||
|
@ -97,6 +97,7 @@ static char *absClusterPath(text *arg, bool logAllowed)
|
|||
else
|
||||
{
|
||||
char *absname = palloc(dlen + len + 2);
|
||||
|
||||
sprintf(absname, "%s/%s", DataDir, filename);
|
||||
pfree(filename);
|
||||
return absname;
|
||||
|
@ -122,7 +123,8 @@ requireSuperuser(void)
|
|||
* generic file handling functions
|
||||
*/
|
||||
|
||||
Datum pg_file_write(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
pg_file_write(PG_FUNCTION_ARGS)
|
||||
{
|
||||
FILE *f;
|
||||
char *filename;
|
||||
|
@ -137,6 +139,7 @@ Datum pg_file_write(PG_FUNCTION_ARGS)
|
|||
if (PG_ARGISNULL(2) || !PG_GETARG_BOOL(2))
|
||||
{
|
||||
struct stat fst;
|
||||
|
||||
if (stat(filename, &fst) >= 0)
|
||||
ereport(ERROR,
|
||||
(ERRCODE_DUPLICATE_FILE,
|
||||
|
@ -169,9 +172,12 @@ Datum pg_file_write(PG_FUNCTION_ARGS)
|
|||
}
|
||||
|
||||
|
||||
Datum pg_file_rename(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
pg_file_rename(PG_FUNCTION_ARGS)
|
||||
{
|
||||
char *fn1, *fn2, *fn3;
|
||||
char *fn1,
|
||||
*fn2,
|
||||
*fn3;
|
||||
int rc;
|
||||
|
||||
requireSuperuser();
|
||||
|
@ -256,7 +262,8 @@ Datum pg_file_rename(PG_FUNCTION_ARGS)
|
|||
}
|
||||
|
||||
|
||||
Datum pg_file_unlink(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
pg_file_unlink(PG_FUNCTION_ARGS)
|
||||
{
|
||||
char *filename;
|
||||
|
||||
|
@ -287,7 +294,8 @@ Datum pg_file_unlink(PG_FUNCTION_ARGS)
|
|||
}
|
||||
|
||||
|
||||
Datum pg_logdir_ls(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
pg_logdir_ls(PG_FUNCTION_ARGS)
|
||||
{
|
||||
FuncCallContext *funcctx;
|
||||
struct dirent *de;
|
||||
|
@ -352,14 +360,14 @@ Datum pg_logdir_ls(PG_FUNCTION_ARGS)
|
|||
char *field[MAXDATEFIELDS];
|
||||
char lowstr[MAXDATELEN + 1];
|
||||
int dtype;
|
||||
int nf, ftype[MAXDATEFIELDS];
|
||||
int nf,
|
||||
ftype[MAXDATEFIELDS];
|
||||
fsec_t fsec;
|
||||
int tz = 0;
|
||||
struct pg_tm date;
|
||||
|
||||
/*
|
||||
* Default format:
|
||||
* postgresql-YYYY-MM-DD_HHMMSS.log
|
||||
* Default format: postgresql-YYYY-MM-DD_HHMMSS.log
|
||||
*/
|
||||
if (strlen(de->d_name) != 32
|
||||
|| memcmp(de->d_name, "postgresql-", 11)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/******************************************************************************
|
||||
$PostgreSQL: pgsql/contrib/cube/cube.c,v 1.29 2006/09/10 17:36:50 tgl Exp $
|
||||
$PostgreSQL: pgsql/contrib/cube/cube.c,v 1.30 2006/10/04 00:29:44 momjian Exp $
|
||||
|
||||
This file contains routines that can be bound to a Postgres backend and
|
||||
called by the backend in the process of processing queries. The calling
|
||||
|
@ -196,8 +196,10 @@ cube_a_f8_f8(PG_FUNCTION_ARGS)
|
|||
int dim;
|
||||
int size;
|
||||
NDBOX *result;
|
||||
ArrayType *ur, *ll;
|
||||
double *dur, *dll;
|
||||
ArrayType *ur,
|
||||
*ll;
|
||||
double *dur,
|
||||
*dll;
|
||||
|
||||
ur = (ArrayType *) PG_GETARG_VARLENA_P(0);
|
||||
ll = (ArrayType *) PG_GETARG_VARLENA_P(1);
|
||||
|
@ -279,9 +281,12 @@ cube_a_f8(PG_FUNCTION_ARGS)
|
|||
Datum
|
||||
cube_subset(PG_FUNCTION_ARGS)
|
||||
{
|
||||
NDBOX *c, *result;
|
||||
NDBOX *c,
|
||||
*result;
|
||||
ArrayType *idx;
|
||||
int size, dim, i;
|
||||
int size,
|
||||
dim,
|
||||
i;
|
||||
int *dx;
|
||||
|
||||
c = (NDBOX *) PG_GETARG_POINTER(0);
|
||||
|
@ -649,7 +654,8 @@ g_cube_picksplit(PG_FUNCTION_ARGS)
|
|||
Datum
|
||||
g_cube_same(PG_FUNCTION_ARGS)
|
||||
{
|
||||
NDBOX *b1, *b2;
|
||||
NDBOX *b1,
|
||||
*b2;
|
||||
bool *result;
|
||||
|
||||
b1 = (NDBOX *) PG_GETARG_POINTER(0);
|
||||
|
@ -805,7 +811,8 @@ cube_union_v0(NDBOX * a, NDBOX * b)
|
|||
Datum
|
||||
cube_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
NDBOX *a, *b;
|
||||
NDBOX *a,
|
||||
*b;
|
||||
|
||||
a = (NDBOX *) PG_GETARG_POINTER(0);
|
||||
b = (NDBOX *) PG_GETARG_POINTER(1);
|
||||
|
@ -818,7 +825,9 @@ Datum
|
|||
cube_inter(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int i;
|
||||
NDBOX *result, *a, *b;
|
||||
NDBOX *result,
|
||||
*a,
|
||||
*b;
|
||||
|
||||
a = (NDBOX *) PG_GETARG_POINTER(0);
|
||||
b = (NDBOX *) PG_GETARG_POINTER(1);
|
||||
|
@ -997,7 +1006,8 @@ cube_cmp_v0(NDBOX * a, NDBOX * b)
|
|||
Datum
|
||||
cube_cmp(PG_FUNCTION_ARGS)
|
||||
{
|
||||
NDBOX *a, *b;
|
||||
NDBOX *a,
|
||||
*b;
|
||||
|
||||
a = (NDBOX *) PG_GETARG_POINTER(0);
|
||||
b = (NDBOX *) PG_GETARG_POINTER(1);
|
||||
|
@ -1009,7 +1019,8 @@ cube_cmp(PG_FUNCTION_ARGS)
|
|||
Datum
|
||||
cube_eq(PG_FUNCTION_ARGS)
|
||||
{
|
||||
NDBOX *a, *b;
|
||||
NDBOX *a,
|
||||
*b;
|
||||
|
||||
a = (NDBOX *) PG_GETARG_POINTER(0);
|
||||
b = (NDBOX *) PG_GETARG_POINTER(1);
|
||||
|
@ -1021,7 +1032,8 @@ cube_eq(PG_FUNCTION_ARGS)
|
|||
Datum
|
||||
cube_ne(PG_FUNCTION_ARGS)
|
||||
{
|
||||
NDBOX *a, *b;
|
||||
NDBOX *a,
|
||||
*b;
|
||||
|
||||
a = (NDBOX *) PG_GETARG_POINTER(0);
|
||||
b = (NDBOX *) PG_GETARG_POINTER(1);
|
||||
|
@ -1033,7 +1045,8 @@ cube_ne(PG_FUNCTION_ARGS)
|
|||
Datum
|
||||
cube_lt(PG_FUNCTION_ARGS)
|
||||
{
|
||||
NDBOX *a, *b;
|
||||
NDBOX *a,
|
||||
*b;
|
||||
|
||||
a = (NDBOX *) PG_GETARG_POINTER(0);
|
||||
b = (NDBOX *) PG_GETARG_POINTER(1);
|
||||
|
@ -1045,7 +1058,8 @@ cube_lt(PG_FUNCTION_ARGS)
|
|||
Datum
|
||||
cube_gt(PG_FUNCTION_ARGS)
|
||||
{
|
||||
NDBOX *a, *b;
|
||||
NDBOX *a,
|
||||
*b;
|
||||
|
||||
a = (NDBOX *) PG_GETARG_POINTER(0);
|
||||
b = (NDBOX *) PG_GETARG_POINTER(1);
|
||||
|
@ -1057,7 +1071,8 @@ cube_gt(PG_FUNCTION_ARGS)
|
|||
Datum
|
||||
cube_le(PG_FUNCTION_ARGS)
|
||||
{
|
||||
NDBOX *a, *b;
|
||||
NDBOX *a,
|
||||
*b;
|
||||
|
||||
a = (NDBOX *) PG_GETARG_POINTER(0);
|
||||
b = (NDBOX *) PG_GETARG_POINTER(1);
|
||||
|
@ -1069,7 +1084,8 @@ cube_le(PG_FUNCTION_ARGS)
|
|||
Datum
|
||||
cube_ge(PG_FUNCTION_ARGS)
|
||||
{
|
||||
NDBOX *a, *b;
|
||||
NDBOX *a,
|
||||
*b;
|
||||
|
||||
a = (NDBOX *) PG_GETARG_POINTER(0);
|
||||
b = (NDBOX *) PG_GETARG_POINTER(1);
|
||||
|
@ -1122,7 +1138,8 @@ cube_contains_v0(NDBOX * a, NDBOX * b)
|
|||
Datum
|
||||
cube_contains(PG_FUNCTION_ARGS)
|
||||
{
|
||||
NDBOX *a, *b;
|
||||
NDBOX *a,
|
||||
*b;
|
||||
|
||||
a = (NDBOX *) PG_GETARG_POINTER(0);
|
||||
b = (NDBOX *) PG_GETARG_POINTER(1);
|
||||
|
@ -1135,7 +1152,8 @@ cube_contains(PG_FUNCTION_ARGS)
|
|||
Datum
|
||||
cube_contained(PG_FUNCTION_ARGS)
|
||||
{
|
||||
NDBOX *a, *b;
|
||||
NDBOX *a,
|
||||
*b;
|
||||
|
||||
a = (NDBOX *) PG_GETARG_POINTER(0);
|
||||
b = (NDBOX *) PG_GETARG_POINTER(1);
|
||||
|
@ -1193,7 +1211,8 @@ cube_overlap_v0(NDBOX * a, NDBOX * b)
|
|||
Datum
|
||||
cube_overlap(PG_FUNCTION_ARGS)
|
||||
{
|
||||
NDBOX *a, *b;
|
||||
NDBOX *a,
|
||||
*b;
|
||||
|
||||
a = (NDBOX *) PG_GETARG_POINTER(0);
|
||||
b = (NDBOX *) PG_GETARG_POINTER(1);
|
||||
|
@ -1213,7 +1232,8 @@ cube_distance(PG_FUNCTION_ARGS)
|
|||
int i;
|
||||
double d,
|
||||
distance;
|
||||
NDBOX *a, *b;
|
||||
NDBOX *a,
|
||||
*b;
|
||||
|
||||
a = (NDBOX *) PG_GETARG_POINTER(0);
|
||||
b = (NDBOX *) PG_GETARG_POINTER(1);
|
||||
|
@ -1455,7 +1475,8 @@ cube_c_f8_f8(PG_FUNCTION_ARGS)
|
|||
{
|
||||
NDBOX *c;
|
||||
NDBOX *result;
|
||||
double x1, x2;
|
||||
double x1,
|
||||
x2;
|
||||
int size;
|
||||
int i;
|
||||
|
||||
|
@ -1478,5 +1499,3 @@ cube_c_f8_f8(PG_FUNCTION_ARGS)
|
|||
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Darko Prenosil <Darko.Prenosil@finteh.hr>
|
||||
* Shridhar Daithankar <shridhar_daithankar@persistent.co.in>
|
||||
*
|
||||
* $PostgreSQL: pgsql/contrib/dblink/dblink.c,v 1.58 2006/09/02 21:11:15 joe Exp $
|
||||
* $PostgreSQL: pgsql/contrib/dblink/dblink.c,v 1.59 2006/10/04 00:29:44 momjian Exp $
|
||||
* Copyright (c) 2001-2006, PostgreSQL Global Development Group
|
||||
* ALL RIGHTS RESERVED;
|
||||
*
|
||||
|
@ -362,11 +362,11 @@ dblink_open(PG_FUNCTION_ARGS)
|
|||
DBLINK_RES_INTERNALERROR("begin error");
|
||||
PQclear(res);
|
||||
rconn->newXactForCursor = TRUE;
|
||||
|
||||
/*
|
||||
* Since transaction state was IDLE, we force cursor count to
|
||||
* initially be 0. This is needed as a previous ABORT might
|
||||
* have wiped out our transaction without maintaining the
|
||||
* cursor count for us.
|
||||
* initially be 0. This is needed as a previous ABORT might have wiped
|
||||
* out our transaction without maintaining the cursor count for us.
|
||||
*/
|
||||
rconn->openCursorCount = 0;
|
||||
}
|
||||
|
@ -850,8 +850,8 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async, bool do_get)
|
|||
TEXTOID, -1, 0);
|
||||
|
||||
/*
|
||||
* and save a copy of the command status string to return as our
|
||||
* result tuple
|
||||
* and save a copy of the command status string to return as
|
||||
* our result tuple
|
||||
*/
|
||||
sql_cmd_status = PQcmdStatus(res);
|
||||
funcctx->max_calls = 1;
|
||||
|
@ -891,7 +891,10 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async, bool do_get)
|
|||
tupdesc = CreateTupleDescCopy(tupdesc);
|
||||
}
|
||||
|
||||
/* check result and tuple descriptor have the same number of columns */
|
||||
/*
|
||||
* check result and tuple descriptor have the same number of
|
||||
* columns
|
||||
*/
|
||||
if (PQnfields(res) != tupdesc->natts)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
#include "storage/bufpage.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
uint16 keylen;
|
||||
uint16 vallen;
|
||||
uint32
|
||||
|
@ -20,7 +21,8 @@ typedef struct {
|
|||
} HEntry;
|
||||
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
int4 len;
|
||||
int4 size;
|
||||
char data[1];
|
||||
|
@ -34,7 +36,8 @@ typedef struct {
|
|||
|
||||
#define PG_GETARG_HS(x) ((HStore*)PG_DETOAST_DATUM(PG_GETARG_DATUM(x)))
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
char *key;
|
||||
char *val;
|
||||
uint16 keylen;
|
||||
|
|
|
@ -36,7 +36,8 @@ typedef char *BITVECP;
|
|||
#define HASHVAL(val) (((unsigned int)(val)) % SIGLENBIT)
|
||||
#define HASH(sign, val) SETBIT((sign), HASHVAL(val))
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
int4 len;
|
||||
int4 flag;
|
||||
char data[1];
|
||||
|
@ -74,13 +75,15 @@ Datum ghstore_out(PG_FUNCTION_ARGS);
|
|||
|
||||
|
||||
Datum
|
||||
ghstore_in(PG_FUNCTION_ARGS) {
|
||||
ghstore_in(PG_FUNCTION_ARGS)
|
||||
{
|
||||
elog(ERROR, "Not implemented");
|
||||
PG_RETURN_DATUM(0);
|
||||
}
|
||||
|
||||
Datum
|
||||
ghstore_out(PG_FUNCTION_ARGS) {
|
||||
ghstore_out(PG_FUNCTION_ARGS)
|
||||
{
|
||||
elog(ERROR, "Not implemented");
|
||||
PG_RETURN_DATUM(0);
|
||||
}
|
||||
|
@ -102,11 +105,13 @@ Datum ghstore_union(PG_FUNCTION_ARGS);
|
|||
Datum ghstore_same(PG_FUNCTION_ARGS);
|
||||
|
||||
Datum
|
||||
ghstore_compress(PG_FUNCTION_ARGS) {
|
||||
ghstore_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
GISTENTRY *retval = entry;
|
||||
|
||||
if (entry->leafkey) {
|
||||
if (entry->leafkey)
|
||||
{
|
||||
GISTTYPE *res = (GISTTYPE *) palloc(CALCGTSIZE(0));
|
||||
HStore *toastedval = (HStore *) DatumGetPointer(entry->key);
|
||||
HStore *val = (HStore *) DatumGetPointer(PG_DETOAST_DATUM(entry->key));
|
||||
|
@ -116,11 +121,14 @@ ghstore_compress(PG_FUNCTION_ARGS) {
|
|||
memset(res, 0, CALCGTSIZE(0));
|
||||
res->len = CALCGTSIZE(0);
|
||||
|
||||
while(ptr-ARRPTR(val) < val->size) {
|
||||
while (ptr - ARRPTR(val) < val->size)
|
||||
{
|
||||
int h;
|
||||
|
||||
h = crc32_sz((char *) (words + ptr->pos), ptr->keylen);
|
||||
HASH(GETSIGN(res), h);
|
||||
if ( !ptr->valisnull ) {
|
||||
if (!ptr->valisnull)
|
||||
{
|
||||
h = crc32_sz((char *) (words + ptr->pos + ptr->keylen), ptr->vallen);
|
||||
HASH(GETSIGN(res), h);
|
||||
}
|
||||
|
@ -135,7 +143,9 @@ ghstore_compress(PG_FUNCTION_ARGS) {
|
|||
entry->rel, entry->page,
|
||||
entry->offset,
|
||||
FALSE);
|
||||
} else if ( !ISALLTRUE(DatumGetPointer(entry->key)) ) {
|
||||
}
|
||||
else if (!ISALLTRUE(DatumGetPointer(entry->key)))
|
||||
{
|
||||
int4 i;
|
||||
GISTTYPE *res;
|
||||
BITVECP sign = GETSIGN(DatumGetPointer(entry->key));
|
||||
|
@ -160,12 +170,14 @@ ghstore_compress(PG_FUNCTION_ARGS) {
|
|||
}
|
||||
|
||||
Datum
|
||||
ghstore_decompress(PG_FUNCTION_ARGS) {
|
||||
ghstore_decompress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_DATUM(PG_GETARG_DATUM(0));
|
||||
}
|
||||
|
||||
Datum
|
||||
ghstore_same(PG_FUNCTION_ARGS) {
|
||||
ghstore_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);
|
||||
|
@ -176,13 +188,16 @@ ghstore_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;
|
||||
}
|
||||
|
@ -192,8 +207,11 @@ ghstore_same(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);
|
||||
|
@ -202,8 +220,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))
|
||||
|
@ -213,13 +233,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));
|
||||
|
@ -240,7 +263,8 @@ unionkey(BITVECP sbase, GISTTYPE * add)
|
|||
}
|
||||
|
||||
Datum
|
||||
ghstore_union(PG_FUNCTION_ARGS) {
|
||||
ghstore_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
||||
int4 len = entryvec->n;
|
||||
|
||||
|
@ -251,8 +275,10 @@ ghstore_union(PG_FUNCTION_ARGS) {
|
|||
GISTTYPE *result;
|
||||
|
||||
MemSet((void *) base, 0, sizeof(BITVEC));
|
||||
for (i = 0; i < len; i++) {
|
||||
if (unionkey(base, GETENTRY(entryvec, i))) {
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
if (unionkey(base, GETENTRY(entryvec, i)))
|
||||
{
|
||||
flag = ALLISTRUE;
|
||||
break;
|
||||
}
|
||||
|
@ -269,7 +295,8 @@ ghstore_union(PG_FUNCTION_ARGS) {
|
|||
}
|
||||
|
||||
Datum
|
||||
ghstore_penalty(PG_FUNCTION_ARGS) {
|
||||
ghstore_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);
|
||||
|
@ -281,19 +308,22 @@ ghstore_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
|
||||
ghstore_picksplit(PG_FUNCTION_ARGS) {
|
||||
ghstore_picksplit(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
||||
OffsetNumber maxoff = entryvec->n - 2;
|
||||
|
||||
|
@ -304,7 +334,8 @@ ghstore_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;
|
||||
|
@ -322,11 +353,14 @@ ghstore_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;
|
||||
|
@ -346,22 +380,28 @@ ghstore_picksplit(PG_FUNCTION_ARGS) {
|
|||
}
|
||||
|
||||
/* form initial .. */
|
||||
if (ISALLTRUE(GETENTRY(entryvec, seed_1))) {
|
||||
if (ISALLTRUE(GETENTRY(entryvec, seed_1)))
|
||||
{
|
||||
datum_l = (GISTTYPE *) palloc(GTHDRSIZE);
|
||||
datum_l->len = GTHDRSIZE;
|
||||
datum_l->flag = ALLISTRUE;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
datum_l = (GISTTYPE *) palloc(GTHDRSIZE + SIGLEN);
|
||||
datum_l->len = GTHDRSIZE + SIGLEN;
|
||||
datum_l->flag = 0;
|
||||
memcpy((void *) GETSIGN(datum_l), (void *) GETSIGN(GETENTRY(entryvec, seed_1)), sizeof(BITVEC))
|
||||
;
|
||||
}
|
||||
if (ISALLTRUE(GETENTRY(entryvec, seed_2))) {
|
||||
if (ISALLTRUE(GETENTRY(entryvec, seed_2)))
|
||||
{
|
||||
datum_r = (GISTTYPE *) palloc(GTHDRSIZE);
|
||||
datum_r->len = GTHDRSIZE;
|
||||
datum_r->flag = ALLISTRUE;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
datum_r = (GISTTYPE *) palloc(GTHDRSIZE + SIGLEN);
|
||||
datum_r->len = GTHDRSIZE + SIGLEN;
|
||||
datum_r->flag = 0;
|
||||
|
@ -384,13 +424,17 @@ ghstore_picksplit(PG_FUNCTION_ARGS) {
|
|||
union_l = GETSIGN(datum_l);
|
||||
union_r = GETSIGN(datum_r);
|
||||
|
||||
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;
|
||||
|
@ -399,11 +443,15 @@ ghstore_picksplit(PG_FUNCTION_ARGS) {
|
|||
size_alpha = hemdist(datum_l, _j);
|
||||
size_beta = hemdist(datum_r, _j);
|
||||
|
||||
if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.0001)) {
|
||||
if (ISALLTRUE(datum_l) || ISALLTRUE(_j) ) {
|
||||
if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.0001))
|
||||
{
|
||||
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];
|
||||
|
@ -411,11 +459,16 @@ ghstore_picksplit(PG_FUNCTION_ARGS) {
|
|||
}
|
||||
*left++ = j;
|
||||
v->spl_nleft++;
|
||||
} else {
|
||||
if (ISALLTRUE(datum_r) || ISALLTRUE(_j) ) {
|
||||
}
|
||||
else
|
||||
{
|
||||
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];
|
||||
|
@ -437,7 +490,8 @@ ghstore_picksplit(PG_FUNCTION_ARGS) {
|
|||
|
||||
|
||||
Datum
|
||||
ghstore_consistent(PG_FUNCTION_ARGS) {
|
||||
ghstore_consistent(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTTYPE *entry = (GISTTYPE *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
|
||||
HStore *query = PG_GETARG_HS(1);
|
||||
bool res = true;
|
||||
|
@ -445,21 +499,27 @@ ghstore_consistent(PG_FUNCTION_ARGS) {
|
|||
char *qv = STRPTR(query);
|
||||
BITVECP sign;
|
||||
|
||||
if ( ISALLTRUE(entry) ) {
|
||||
if (ISALLTRUE(entry))
|
||||
{
|
||||
PG_FREE_IF_COPY(query, 1);
|
||||
PG_RETURN_BOOL(true);
|
||||
}
|
||||
|
||||
sign = GETSIGN(entry);
|
||||
while(res && qe-ARRPTR(query) < query->size) {
|
||||
while (res && qe - ARRPTR(query) < query->size)
|
||||
{
|
||||
int crc = crc32_sz((char *) (qv + qe->pos), qe->keylen);
|
||||
if (GETBIT(sign,HASHVAL(crc))) {
|
||||
if ( !qe->valisnull ) {
|
||||
|
||||
if (GETBIT(sign, HASHVAL(crc)))
|
||||
{
|
||||
if (!qe->valisnull)
|
||||
{
|
||||
crc = crc32_sz((char *) (qv + qe->pos + qe->keylen), qe->vallen);
|
||||
if (!GETBIT(sign, HASHVAL(crc)))
|
||||
res = false;
|
||||
}
|
||||
} else
|
||||
}
|
||||
else
|
||||
res = false;
|
||||
qe++;
|
||||
}
|
||||
|
@ -467,5 +527,3 @@ ghstore_consistent(PG_FUNCTION_ARGS) {
|
|||
PG_FREE_IF_COPY(query, 1);
|
||||
PG_RETURN_BOOL(res);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
|
||||
PG_MODULE_MAGIC;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
char *begin;
|
||||
char *ptr;
|
||||
char *cur;
|
||||
|
@ -34,74 +35,114 @@ do { \
|
|||
#define GV_WAITESCESCIN 4
|
||||
|
||||
static bool
|
||||
get_val( HSParser *state, bool ignoreeq, bool *escaped ) {
|
||||
get_val(HSParser * state, bool ignoreeq, bool *escaped)
|
||||
{
|
||||
int st = GV_WAITVAL;
|
||||
|
||||
state->wordlen = 32;
|
||||
state->cur = state->word = palloc(state->wordlen);
|
||||
*escaped = false;
|
||||
|
||||
while(1) {
|
||||
if ( st == GV_WAITVAL ) {
|
||||
if ( *(state->ptr) == '"' ) {
|
||||
while (1)
|
||||
{
|
||||
if (st == GV_WAITVAL)
|
||||
{
|
||||
if (*(state->ptr) == '"')
|
||||
{
|
||||
*escaped = true;
|
||||
st = GV_INESCVAL;
|
||||
} else if ( *(state->ptr) == '\0' ) {
|
||||
}
|
||||
else if (*(state->ptr) == '\0')
|
||||
{
|
||||
return false;
|
||||
} else if ( *(state->ptr) == '=' && !ignoreeq ) {
|
||||
}
|
||||
else if (*(state->ptr) == '=' && !ignoreeq)
|
||||
{
|
||||
elog(ERROR, "Syntax error near '%c' at postion %d", *(state->ptr), (int4) (state->ptr - state->begin));
|
||||
} else if ( *(state->ptr) == '\\' ) {
|
||||
}
|
||||
else if (*(state->ptr) == '\\')
|
||||
{
|
||||
st = GV_WAITESCIN;
|
||||
} else if ( !isspace((unsigned char) *(state->ptr)) ) {
|
||||
}
|
||||
else if (!isspace((unsigned char) *(state->ptr)))
|
||||
{
|
||||
*(state->cur) = *(state->ptr);
|
||||
state->cur++;
|
||||
st = GV_INVAL;
|
||||
}
|
||||
} else if ( st == GV_INVAL ) {
|
||||
if ( *(state->ptr) == '\\' ) {
|
||||
}
|
||||
else if (st == GV_INVAL)
|
||||
{
|
||||
if (*(state->ptr) == '\\')
|
||||
{
|
||||
st = GV_WAITESCIN;
|
||||
} else if ( *(state->ptr) == '=' && !ignoreeq ) {
|
||||
}
|
||||
else if (*(state->ptr) == '=' && !ignoreeq)
|
||||
{
|
||||
state->ptr--;
|
||||
return true;
|
||||
} else if ( *(state->ptr) == ',' && ignoreeq ) {
|
||||
}
|
||||
else if (*(state->ptr) == ',' && ignoreeq)
|
||||
{
|
||||
state->ptr--;
|
||||
return true;
|
||||
} else if ( isspace((unsigned char) *(state->ptr)) ) {
|
||||
}
|
||||
else if (isspace((unsigned char) *(state->ptr)))
|
||||
{
|
||||
return true;
|
||||
} else if ( *(state->ptr) == '\0' ) {
|
||||
}
|
||||
else if (*(state->ptr) == '\0')
|
||||
{
|
||||
state->ptr--;
|
||||
return true;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
RESIZEPRSBUF;
|
||||
*(state->cur) = *(state->ptr);
|
||||
state->cur++;
|
||||
}
|
||||
} else if ( st == GV_INESCVAL ) {
|
||||
if ( *(state->ptr) == '\\' ) {
|
||||
}
|
||||
else if (st == GV_INESCVAL)
|
||||
{
|
||||
if (*(state->ptr) == '\\')
|
||||
{
|
||||
st = GV_WAITESCESCIN;
|
||||
} else if ( *(state->ptr) == '"' ) {
|
||||
}
|
||||
else if (*(state->ptr) == '"')
|
||||
{
|
||||
return true;
|
||||
} else if ( *(state->ptr) == '\0' ) {
|
||||
}
|
||||
else if (*(state->ptr) == '\0')
|
||||
{
|
||||
elog(ERROR, "Unexpected end of string");
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
RESIZEPRSBUF;
|
||||
*(state->cur) = *(state->ptr);
|
||||
state->cur++;
|
||||
}
|
||||
} else if ( st == GV_WAITESCIN ) {
|
||||
}
|
||||
else if (st == GV_WAITESCIN)
|
||||
{
|
||||
if (*(state->ptr) == '\0')
|
||||
elog(ERROR, "Unexpected end of string");
|
||||
RESIZEPRSBUF;
|
||||
*(state->cur) = *(state->ptr);
|
||||
state->cur++;
|
||||
st = GV_INVAL;
|
||||
} else if ( st == GV_WAITESCESCIN ) {
|
||||
}
|
||||
else if (st == GV_WAITESCESCIN)
|
||||
{
|
||||
if (*(state->ptr) == '\0')
|
||||
elog(ERROR, "Unexpected end of string");
|
||||
RESIZEPRSBUF;
|
||||
*(state->cur) = *(state->ptr);
|
||||
state->cur++;
|
||||
st = GV_INESCVAL;
|
||||
} else
|
||||
}
|
||||
else
|
||||
elog(ERROR, "Unknown state %d at postion line %d in file '%s'", st, __LINE__, __FILE__);
|
||||
|
||||
state->ptr++;
|
||||
|
@ -118,7 +159,8 @@ get_val( HSParser *state, bool ignoreeq, bool *escaped ) {
|
|||
|
||||
|
||||
static void
|
||||
parse_hstore( HSParser *state ) {
|
||||
parse_hstore(HSParser * state)
|
||||
{
|
||||
int st = WKEY;
|
||||
bool escaped = false;
|
||||
|
||||
|
@ -128,11 +170,14 @@ parse_hstore( HSParser *state ) {
|
|||
state->ptr = state->begin;
|
||||
state->word = NULL;
|
||||
|
||||
while(1) {
|
||||
if (st == WKEY) {
|
||||
while (1)
|
||||
{
|
||||
if (st == WKEY)
|
||||
{
|
||||
if (!get_val(state, false, &escaped))
|
||||
return;
|
||||
if ( state->pcur >= state->plen ) {
|
||||
if (state->pcur >= state->plen)
|
||||
{
|
||||
state->plen *= 2;
|
||||
state->pairs = (Pairs *) repalloc(state->pairs, sizeof(Pairs) * state->plen);
|
||||
}
|
||||
|
@ -141,30 +186,47 @@ parse_hstore( HSParser *state ) {
|
|||
state->pairs[state->pcur].val = NULL;
|
||||
state->word = NULL;
|
||||
st = WEQ;
|
||||
} else if ( st == WEQ ) {
|
||||
if ( *(state->ptr) == '=' ) {
|
||||
}
|
||||
else if (st == WEQ)
|
||||
{
|
||||
if (*(state->ptr) == '=')
|
||||
{
|
||||
st = WGT;
|
||||
} else if ( *(state->ptr) == '\0' ) {
|
||||
}
|
||||
else if (*(state->ptr) == '\0')
|
||||
{
|
||||
elog(ERROR, "Unexpectd end of string");
|
||||
} else if (!isspace((unsigned char) *(state->ptr))) {
|
||||
}
|
||||
else if (!isspace((unsigned char) *(state->ptr)))
|
||||
{
|
||||
elog(ERROR, "Syntax error near '%c' at postion %d", *(state->ptr), (int4) (state->ptr - state->begin));
|
||||
}
|
||||
} else if ( st == WGT ) {
|
||||
if ( *(state->ptr) == '>' ) {
|
||||
}
|
||||
else if (st == WGT)
|
||||
{
|
||||
if (*(state->ptr) == '>')
|
||||
{
|
||||
st = WVAL;
|
||||
} else if ( *(state->ptr) == '\0' ) {
|
||||
}
|
||||
else if (*(state->ptr) == '\0')
|
||||
{
|
||||
elog(ERROR, "Unexpectd end of string");
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
elog(ERROR, "Syntax error near '%c' at postion %d", *(state->ptr), (int4) (state->ptr - state->begin));
|
||||
}
|
||||
} else if ( st == WVAL ) {
|
||||
}
|
||||
else if (st == WVAL)
|
||||
{
|
||||
if (!get_val(state, true, &escaped))
|
||||
elog(ERROR, "Unexpected end of string");
|
||||
state->pairs[state->pcur].val = state->word;
|
||||
state->pairs[state->pcur].vallen = state->cur - state->word;
|
||||
state->pairs[state->pcur].isnull = false;
|
||||
state->pairs[state->pcur].needfree = true;
|
||||
if ( state->cur - state->word == 4 && !escaped) {
|
||||
if (state->cur - state->word == 4 && !escaped)
|
||||
{
|
||||
state->word[4] = '\0';
|
||||
if (0 == pg_strcasecmp(state->word, "null"))
|
||||
state->pairs[state->pcur].isnull = true;
|
||||
|
@ -172,15 +234,23 @@ parse_hstore( HSParser *state ) {
|
|||
state->word = NULL;
|
||||
state->pcur++;
|
||||
st = WDEL;
|
||||
} else if ( st == WDEL ) {
|
||||
if ( *(state->ptr) == ',' ) {
|
||||
}
|
||||
else if (st == WDEL)
|
||||
{
|
||||
if (*(state->ptr) == ',')
|
||||
{
|
||||
st = WKEY;
|
||||
} else if ( *(state->ptr) == '\0' ) {
|
||||
}
|
||||
else if (*(state->ptr) == '\0')
|
||||
{
|
||||
return;
|
||||
} else if (!isspace((unsigned char) *(state->ptr))) {
|
||||
}
|
||||
else if (!isspace((unsigned char) *(state->ptr)))
|
||||
{
|
||||
elog(ERROR, "Syntax error near '%c' at postion %d", *(state->ptr), (int4) (state->ptr - state->begin));
|
||||
}
|
||||
} else
|
||||
}
|
||||
else
|
||||
elog(ERROR, "Unknown state %d at line %d in file '%s'", st, __LINE__, __FILE__);
|
||||
|
||||
state->ptr++;
|
||||
|
@ -188,13 +258,16 @@ parse_hstore( HSParser *state ) {
|
|||
}
|
||||
|
||||
int
|
||||
comparePairs(const void *a, const void *b) {
|
||||
if ( ((Pairs*)a)->keylen == ((Pairs*)b)->keylen ) {
|
||||
comparePairs(const void *a, const void *b)
|
||||
{
|
||||
if (((Pairs *) a)->keylen == ((Pairs *) b)->keylen)
|
||||
{
|
||||
int res = strncmp(
|
||||
((Pairs *) a)->key,
|
||||
((Pairs *) b)->key,
|
||||
((Pairs *) a)->keylen
|
||||
);
|
||||
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
|
@ -210,11 +283,14 @@ comparePairs(const void *a, const void *b) {
|
|||
}
|
||||
|
||||
int
|
||||
uniquePairs(Pairs * a, int4 l, int4 *buflen) {
|
||||
Pairs *ptr, *res;
|
||||
uniquePairs(Pairs * a, int4 l, int4 *buflen)
|
||||
{
|
||||
Pairs *ptr,
|
||||
*res;
|
||||
|
||||
*buflen = 0;
|
||||
if ( l < 2 ) {
|
||||
if (l < 2)
|
||||
{
|
||||
if (l == 1)
|
||||
*buflen = a->keylen + ((a->isnull) ? 0 : a->vallen);
|
||||
return l;
|
||||
|
@ -223,13 +299,18 @@ uniquePairs(Pairs * a, int4 l, int4 *buflen) {
|
|||
qsort((void *) a, l, sizeof(Pairs), comparePairs);
|
||||
ptr = a + 1;
|
||||
res = a;
|
||||
while( ptr - a < l ) {
|
||||
if ( ptr->keylen == res->keylen && strncmp( ptr->key, res->key, res->keylen )==0 ) {
|
||||
if ( ptr->needfree ) {
|
||||
while (ptr - a < l)
|
||||
{
|
||||
if (ptr->keylen == res->keylen && strncmp(ptr->key, res->key, res->keylen) == 0)
|
||||
{
|
||||
if (ptr->needfree)
|
||||
{
|
||||
pfree(ptr->key);
|
||||
pfree(ptr->val);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
*buflen += res->keylen + ((res->isnull) ? 0 : res->vallen);
|
||||
res++;
|
||||
memcpy(res, ptr, sizeof(Pairs));
|
||||
|
@ -243,14 +324,19 @@ uniquePairs(Pairs * a, int4 l, int4 *buflen) {
|
|||
}
|
||||
|
||||
static void
|
||||
freeHSParse(HSParser *state) {
|
||||
freeHSParse(HSParser * state)
|
||||
{
|
||||
int i;
|
||||
|
||||
if ( state->word ) pfree( state->word );
|
||||
if (state->word)
|
||||
pfree(state->word);
|
||||
for (i = 0; i < state->pcur; i++)
|
||||
if ( state->pairs[i].needfree ) {
|
||||
if (state->pairs[i].key) pfree(state->pairs[i].key);
|
||||
if (state->pairs[i].val) pfree(state->pairs[i].val);
|
||||
if (state->pairs[i].needfree)
|
||||
{
|
||||
if (state->pairs[i].key)
|
||||
pfree(state->pairs[i].key);
|
||||
if (state->pairs[i].val)
|
||||
pfree(state->pairs[i].val);
|
||||
}
|
||||
pfree(state->pairs);
|
||||
}
|
||||
|
@ -258,9 +344,12 @@ freeHSParse(HSParser *state) {
|
|||
PG_FUNCTION_INFO_V1(hstore_in);
|
||||
Datum hstore_in(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
hstore_in(PG_FUNCTION_ARGS) {
|
||||
hstore_in(PG_FUNCTION_ARGS)
|
||||
{
|
||||
HSParser state;
|
||||
int4 len,buflen,i;
|
||||
int4 len,
|
||||
buflen,
|
||||
i;
|
||||
HStore *out;
|
||||
HEntry *entries;
|
||||
char *ptr;
|
||||
|
@ -269,7 +358,8 @@ hstore_in(PG_FUNCTION_ARGS) {
|
|||
|
||||
parse_hstore(&state);
|
||||
|
||||
if ( state.pcur == 0 ) {
|
||||
if (state.pcur == 0)
|
||||
{
|
||||
freeHSParse(&state);
|
||||
len = CALCDATASIZE(0, 0);
|
||||
out = palloc(len);
|
||||
|
@ -288,7 +378,8 @@ hstore_in(PG_FUNCTION_ARGS) {
|
|||
entries = ARRPTR(out);
|
||||
ptr = STRPTR(out);
|
||||
|
||||
for(i=0;i<out->size;i++) {
|
||||
for (i = 0; i < out->size; i++)
|
||||
{
|
||||
entries[i].keylen = state.pairs[i].keylen;
|
||||
entries[i].pos = ptr - STRPTR(out);
|
||||
memcpy(ptr, state.pairs[i].key, state.pairs[i].keylen);
|
||||
|
@ -297,7 +388,8 @@ hstore_in(PG_FUNCTION_ARGS) {
|
|||
entries[i].valisnull = state.pairs[i].isnull;
|
||||
if (entries[i].valisnull)
|
||||
entries[i].vallen = 4; /* null */
|
||||
else {
|
||||
else
|
||||
{
|
||||
entries[i].vallen = state.pairs[i].vallen;
|
||||
memcpy(ptr, state.pairs[i].val, state.pairs[i].vallen);
|
||||
ptr += entries[i].vallen;
|
||||
|
@ -309,10 +401,12 @@ hstore_in(PG_FUNCTION_ARGS) {
|
|||
}
|
||||
|
||||
static char *
|
||||
cpw(char *dst, char *src, int len) {
|
||||
cpw(char *dst, char *src, int len)
|
||||
{
|
||||
char *ptr = src;
|
||||
|
||||
while(ptr-src<len) {
|
||||
while (ptr - src < len)
|
||||
{
|
||||
if (*ptr == '"' || *ptr == '\\')
|
||||
*dst++ = '\\';
|
||||
*dst++ = *ptr++;
|
||||
|
@ -323,14 +417,18 @@ cpw(char *dst, char *src, int len) {
|
|||
PG_FUNCTION_INFO_V1(hstore_out);
|
||||
Datum hstore_out(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
hstore_out(PG_FUNCTION_ARGS) {
|
||||
hstore_out(PG_FUNCTION_ARGS)
|
||||
{
|
||||
HStore *in = PG_GETARG_HS(0);
|
||||
int buflen,i;
|
||||
char *out,*ptr;
|
||||
int buflen,
|
||||
i;
|
||||
char *out,
|
||||
*ptr;
|
||||
char *base = STRPTR(in);
|
||||
HEntry *entries = ARRPTR(in);
|
||||
|
||||
if ( in->size==0 ) {
|
||||
if (in->size == 0)
|
||||
{
|
||||
out = palloc(1);
|
||||
*out = '\0';
|
||||
PG_FREE_IF_COPY(in, 0);
|
||||
|
@ -341,24 +439,29 @@ hstore_out(PG_FUNCTION_ARGS) {
|
|||
2 /* esc */ * (in->len - CALCDATASIZE(in->size, 0));
|
||||
|
||||
out = ptr = palloc(buflen);
|
||||
for(i=0;i<in->size;i++) {
|
||||
for (i = 0; i < in->size; i++)
|
||||
{
|
||||
*ptr++ = '"';
|
||||
ptr = cpw(ptr, base + entries[i].pos, entries[i].keylen);
|
||||
*ptr++ = '"';
|
||||
*ptr++ = '=';
|
||||
*ptr++ = '>';
|
||||
if ( entries[i].valisnull ) {
|
||||
if (entries[i].valisnull)
|
||||
{
|
||||
*ptr++ = 'N';
|
||||
*ptr++ = 'U';
|
||||
*ptr++ = 'L';
|
||||
*ptr++ = 'L';
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
*ptr++ = '"';
|
||||
ptr = cpw(ptr, base + entries[i].pos + entries[i].keylen, entries[i].vallen);
|
||||
*ptr++ = '"';
|
||||
}
|
||||
|
||||
if ( i+1 != in->size ) {
|
||||
if (i + 1 != in->size)
|
||||
{
|
||||
*ptr++ = ',';
|
||||
*ptr++ = ' ';
|
||||
}
|
||||
|
|
|
@ -7,14 +7,16 @@
|
|||
|
||||
|
||||
static HEntry *
|
||||
findkey(HStore *hs, char *key, int keylen) {
|
||||
findkey(HStore * hs, char *key, int keylen)
|
||||
{
|
||||
HEntry *StopLow = ARRPTR(hs);
|
||||
HEntry *StopHigh = StopLow + hs->size;
|
||||
HEntry *StopMiddle;
|
||||
int difference;
|
||||
char *base = STRPTR(hs);
|
||||
|
||||
while (StopLow < StopHigh) {
|
||||
while (StopLow < StopHigh)
|
||||
{
|
||||
StopMiddle = StopLow + (StopHigh - StopLow) / 2;
|
||||
|
||||
if (StopMiddle->keylen == keylen)
|
||||
|
@ -36,13 +38,15 @@ findkey(HStore *hs, char *key, int keylen) {
|
|||
PG_FUNCTION_INFO_V1(fetchval);
|
||||
Datum fetchval(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
fetchval(PG_FUNCTION_ARGS) {
|
||||
fetchval(PG_FUNCTION_ARGS)
|
||||
{
|
||||
HStore *hs = PG_GETARG_HS(0);
|
||||
text *key = PG_GETARG_TEXT_P(1);
|
||||
HEntry *entry;
|
||||
text *out;
|
||||
|
||||
if ((entry=findkey(hs,VARDATA(key), VARSIZE(key)-VARHDRSZ))==NULL || entry->valisnull) {
|
||||
if ((entry = findkey(hs, VARDATA(key), VARSIZE(key) - VARHDRSZ)) == NULL || entry->valisnull)
|
||||
{
|
||||
PG_FREE_IF_COPY(hs, 0);
|
||||
PG_FREE_IF_COPY(key, 1);
|
||||
PG_RETURN_NULL();
|
||||
|
@ -60,7 +64,8 @@ fetchval(PG_FUNCTION_ARGS) {
|
|||
PG_FUNCTION_INFO_V1(exists);
|
||||
Datum exists(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
exists(PG_FUNCTION_ARGS) {
|
||||
exists(PG_FUNCTION_ARGS)
|
||||
{
|
||||
HStore *hs = PG_GETARG_HS(0);
|
||||
text *key = PG_GETARG_TEXT_P(1);
|
||||
HEntry *entry;
|
||||
|
@ -76,7 +81,8 @@ exists(PG_FUNCTION_ARGS) {
|
|||
PG_FUNCTION_INFO_V1(defined);
|
||||
Datum defined(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
defined(PG_FUNCTION_ARGS) {
|
||||
defined(PG_FUNCTION_ARGS)
|
||||
{
|
||||
HStore *hs = PG_GETARG_HS(0);
|
||||
text *key = PG_GETARG_TEXT_P(1);
|
||||
HEntry *entry;
|
||||
|
@ -95,12 +101,15 @@ defined(PG_FUNCTION_ARGS) {
|
|||
PG_FUNCTION_INFO_V1(delete);
|
||||
Datum delete(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
delete(PG_FUNCTION_ARGS) {
|
||||
delete(PG_FUNCTION_ARGS)
|
||||
{
|
||||
HStore *hs = PG_GETARG_HS(0);
|
||||
text *key = PG_GETARG_TEXT_P(1);
|
||||
HStore *out = palloc(hs->len);
|
||||
char *ptrs, *ptrd;
|
||||
HEntry *es, *ed;
|
||||
char *ptrs,
|
||||
*ptrd;
|
||||
HEntry *es,
|
||||
*ed;
|
||||
|
||||
out->len = hs->len;
|
||||
out->size = hs->size; /* temprorary! */
|
||||
|
@ -110,8 +119,10 @@ delete(PG_FUNCTION_ARGS) {
|
|||
ptrd = STRPTR(out);
|
||||
ed = ARRPTR(out);
|
||||
|
||||
while( es - ARRPTR(hs) < hs->size ) {
|
||||
if ( !(es->keylen == VARSIZE(key) - VARHDRSZ && strncmp(ptrs, VARDATA(key), es->keylen)==0) ) {
|
||||
while (es - ARRPTR(hs) < hs->size)
|
||||
{
|
||||
if (!(es->keylen == VARSIZE(key) - VARHDRSZ && strncmp(ptrs, VARDATA(key), es->keylen) == 0))
|
||||
{
|
||||
memcpy(ed, es, sizeof(HEntry));
|
||||
memcpy(ptrd, ptrs, es->keylen + ((es->valisnull) ? 0 : es->vallen));
|
||||
ed->pos = ptrd - STRPTR(out);
|
||||
|
@ -122,8 +133,10 @@ delete(PG_FUNCTION_ARGS) {
|
|||
es++;
|
||||
}
|
||||
|
||||
if ( ed - ARRPTR(out) != out->size ) {
|
||||
if (ed - ARRPTR(out) != out->size)
|
||||
{
|
||||
int buflen = ptrd - STRPTR(out);
|
||||
|
||||
ptrd = STRPTR(out);
|
||||
|
||||
out->size = ed - ARRPTR(out);
|
||||
|
@ -142,12 +155,17 @@ delete(PG_FUNCTION_ARGS) {
|
|||
PG_FUNCTION_INFO_V1(hs_concat);
|
||||
Datum hs_concat(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
hs_concat(PG_FUNCTION_ARGS) {
|
||||
hs_concat(PG_FUNCTION_ARGS)
|
||||
{
|
||||
HStore *s1 = PG_GETARG_HS(0);
|
||||
HStore *s2 = PG_GETARG_HS(1);
|
||||
HStore *out = palloc(s1->len + s2->len);
|
||||
char *ps1, *ps2, *pd;
|
||||
HEntry *es1, *es2, *ed;
|
||||
char *ps1,
|
||||
*ps2,
|
||||
*pd;
|
||||
HEntry *es1,
|
||||
*es2,
|
||||
*ed;
|
||||
|
||||
out->len = s1->len + s2->len;
|
||||
out->size = s1->size + s2->size;
|
||||
|
@ -159,14 +177,17 @@ hs_concat(PG_FUNCTION_ARGS) {
|
|||
es2 = ARRPTR(s2);
|
||||
ed = ARRPTR(out);
|
||||
|
||||
while( es1 - ARRPTR(s1) < s1->size && es2 - ARRPTR(s2) < s2->size ) {
|
||||
while (es1 - ARRPTR(s1) < s1->size && es2 - ARRPTR(s2) < s2->size)
|
||||
{
|
||||
int difference;
|
||||
|
||||
if (es1->keylen == es2->keylen)
|
||||
difference = strncmp(ps1, ps2, es1->keylen);
|
||||
else
|
||||
difference = (es1->keylen > es2->keylen) ? 1 : -1;
|
||||
|
||||
if ( difference == 0 ) {
|
||||
if (difference == 0)
|
||||
{
|
||||
memcpy(ed, es2, sizeof(HEntry));
|
||||
memcpy(pd, ps2, es2->keylen + ((es2->valisnull) ? 0 : es2->vallen));
|
||||
ed->pos = pd - STRPTR(out);
|
||||
|
@ -177,7 +198,9 @@ hs_concat(PG_FUNCTION_ARGS) {
|
|||
es1++;
|
||||
ps2 += es2->keylen + ((es2->valisnull) ? 0 : es2->vallen);
|
||||
es2++;
|
||||
} else if ( difference > 0 ) {
|
||||
}
|
||||
else if (difference > 0)
|
||||
{
|
||||
memcpy(ed, es2, sizeof(HEntry));
|
||||
memcpy(pd, ps2, es2->keylen + ((es2->valisnull) ? 0 : es2->vallen));
|
||||
ed->pos = pd - STRPTR(out);
|
||||
|
@ -186,7 +209,9 @@ hs_concat(PG_FUNCTION_ARGS) {
|
|||
|
||||
ps2 += es2->keylen + ((es2->valisnull) ? 0 : es2->vallen);
|
||||
es2++;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(ed, es1, sizeof(HEntry));
|
||||
memcpy(pd, ps1, es1->keylen + ((es1->valisnull) ? 0 : es1->vallen));
|
||||
ed->pos = pd - STRPTR(out);
|
||||
|
@ -198,7 +223,8 @@ hs_concat(PG_FUNCTION_ARGS) {
|
|||
}
|
||||
}
|
||||
|
||||
while( es1 - ARRPTR(s1) < s1->size ) {
|
||||
while (es1 - ARRPTR(s1) < s1->size)
|
||||
{
|
||||
memcpy(ed, es1, sizeof(HEntry));
|
||||
memcpy(pd, ps1, es1->keylen + ((es1->valisnull) ? 0 : es1->vallen));
|
||||
ed->pos = pd - STRPTR(out);
|
||||
|
@ -209,7 +235,8 @@ hs_concat(PG_FUNCTION_ARGS) {
|
|||
es1++;
|
||||
}
|
||||
|
||||
while( es2 - ARRPTR(s2) < s2->size ) {
|
||||
while (es2 - ARRPTR(s2) < s2->size)
|
||||
{
|
||||
memcpy(ed, es2, sizeof(HEntry));
|
||||
memcpy(pd, ps2, es2->keylen + ((es2->valisnull) ? 0 : es2->vallen));
|
||||
ed->pos = pd - STRPTR(out);
|
||||
|
@ -220,8 +247,10 @@ hs_concat(PG_FUNCTION_ARGS) {
|
|||
es2++;
|
||||
}
|
||||
|
||||
if ( ed - ARRPTR(out) != out->size ) {
|
||||
if (ed - ARRPTR(out) != out->size)
|
||||
{
|
||||
int buflen = pd - STRPTR(out);
|
||||
|
||||
pd = STRPTR(out);
|
||||
|
||||
out->size = ed - ARRPTR(out);
|
||||
|
@ -239,7 +268,8 @@ hs_concat(PG_FUNCTION_ARGS) {
|
|||
PG_FUNCTION_INFO_V1(tconvert);
|
||||
Datum tconvert(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
tconvert(PG_FUNCTION_ARGS) {
|
||||
tconvert(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *key = PG_GETARG_TEXT_P(0);
|
||||
text *val = PG_GETARG_TEXT_P(1);
|
||||
int len;
|
||||
|
@ -267,7 +297,8 @@ tconvert(PG_FUNCTION_ARGS) {
|
|||
PG_FUNCTION_INFO_V1(akeys);
|
||||
Datum akeys(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
akeys(PG_FUNCTION_ARGS) {
|
||||
akeys(PG_FUNCTION_ARGS)
|
||||
{
|
||||
HStore *hs = PG_GETARG_HS(0);
|
||||
Datum *d;
|
||||
ArrayType *a;
|
||||
|
@ -275,8 +306,10 @@ akeys(PG_FUNCTION_ARGS) {
|
|||
char *base = STRPTR(hs);
|
||||
|
||||
d = (Datum *) palloc(sizeof(Datum) * (hs->size + 1));
|
||||
while( ptr-ARRPTR(hs) < hs->size ) {
|
||||
while (ptr - ARRPTR(hs) < hs->size)
|
||||
{
|
||||
text *item = (text *) palloc(VARHDRSZ + ptr->keylen);
|
||||
|
||||
VARATT_SIZEP(item) = VARHDRSZ + ptr->keylen;
|
||||
memcpy(VARDATA(item), base + ptr->pos, ptr->keylen);
|
||||
d[ptr - ARRPTR(hs)] = PointerGetDatum(item);
|
||||
|
@ -293,7 +326,8 @@ akeys(PG_FUNCTION_ARGS) {
|
|||
);
|
||||
|
||||
ptr = ARRPTR(hs);
|
||||
while( ptr-ARRPTR(hs) < hs->size ) {
|
||||
while (ptr - ARRPTR(hs) < hs->size)
|
||||
{
|
||||
pfree(DatumGetPointer(d[ptr - ARRPTR(hs)]));
|
||||
ptr++;
|
||||
}
|
||||
|
@ -307,7 +341,8 @@ akeys(PG_FUNCTION_ARGS) {
|
|||
PG_FUNCTION_INFO_V1(avals);
|
||||
Datum avals(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
avals(PG_FUNCTION_ARGS) {
|
||||
avals(PG_FUNCTION_ARGS)
|
||||
{
|
||||
HStore *hs = PG_GETARG_HS(0);
|
||||
Datum *d;
|
||||
ArrayType *a;
|
||||
|
@ -315,9 +350,11 @@ avals(PG_FUNCTION_ARGS) {
|
|||
char *base = STRPTR(hs);
|
||||
|
||||
d = (Datum *) palloc(sizeof(Datum) * (hs->size + 1));
|
||||
while( ptr-ARRPTR(hs) < hs->size ) {
|
||||
while (ptr - ARRPTR(hs) < hs->size)
|
||||
{
|
||||
int vallen = (ptr->valisnull) ? 0 : ptr->vallen;
|
||||
text *item = (text *) palloc(VARHDRSZ + vallen);
|
||||
|
||||
VARATT_SIZEP(item) = VARHDRSZ + vallen;
|
||||
memcpy(VARDATA(item), base + ptr->pos + ptr->keylen, vallen);
|
||||
d[ptr - ARRPTR(hs)] = PointerGetDatum(item);
|
||||
|
@ -334,7 +371,8 @@ avals(PG_FUNCTION_ARGS) {
|
|||
);
|
||||
|
||||
ptr = ARRPTR(hs);
|
||||
while( ptr-ARRPTR(hs) < hs->size ) {
|
||||
while (ptr - ARRPTR(hs) < hs->size)
|
||||
{
|
||||
pfree(DatumGetPointer(d[ptr - ARRPTR(hs)]));
|
||||
ptr++;
|
||||
}
|
||||
|
@ -345,13 +383,15 @@ avals(PG_FUNCTION_ARGS) {
|
|||
PG_RETURN_POINTER(a);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
HStore *hs;
|
||||
int i;
|
||||
} AKStore;
|
||||
|
||||
static void
|
||||
setup_firstcall(FuncCallContext *funcctx, HStore *hs) {
|
||||
setup_firstcall(FuncCallContext *funcctx, HStore * hs)
|
||||
{
|
||||
MemoryContext oldcontext;
|
||||
AKStore *st;
|
||||
|
||||
|
@ -369,12 +409,15 @@ setup_firstcall(FuncCallContext *funcctx, HStore *hs) {
|
|||
PG_FUNCTION_INFO_V1(skeys);
|
||||
Datum skeys(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
skeys(PG_FUNCTION_ARGS) {
|
||||
skeys(PG_FUNCTION_ARGS)
|
||||
{
|
||||
FuncCallContext *funcctx;
|
||||
AKStore *st;
|
||||
|
||||
if (SRF_IS_FIRSTCALL()) {
|
||||
if (SRF_IS_FIRSTCALL())
|
||||
{
|
||||
HStore *hs = PG_GETARG_HS(0);
|
||||
|
||||
funcctx = SRF_FIRSTCALL_INIT();
|
||||
setup_firstcall(funcctx, hs);
|
||||
PG_FREE_IF_COPY(hs, 0);
|
||||
|
@ -383,7 +426,8 @@ skeys(PG_FUNCTION_ARGS) {
|
|||
funcctx = SRF_PERCALL_SETUP();
|
||||
st = (AKStore *) funcctx->user_fctx;
|
||||
|
||||
if ( st->i < st->hs->size ) {
|
||||
if (st->i < st->hs->size)
|
||||
{
|
||||
HEntry *ptr = &(ARRPTR(st->hs)[st->i]);
|
||||
text *item = (text *) palloc(VARHDRSZ + ptr->keylen);
|
||||
|
||||
|
@ -403,12 +447,15 @@ skeys(PG_FUNCTION_ARGS) {
|
|||
PG_FUNCTION_INFO_V1(svals);
|
||||
Datum svals(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
svals(PG_FUNCTION_ARGS) {
|
||||
svals(PG_FUNCTION_ARGS)
|
||||
{
|
||||
FuncCallContext *funcctx;
|
||||
AKStore *st;
|
||||
|
||||
if (SRF_IS_FIRSTCALL()) {
|
||||
if (SRF_IS_FIRSTCALL())
|
||||
{
|
||||
HStore *hs = PG_GETARG_HS(0);
|
||||
|
||||
funcctx = SRF_FIRSTCALL_INIT();
|
||||
setup_firstcall(funcctx, hs);
|
||||
PG_FREE_IF_COPY(hs, 0);
|
||||
|
@ -417,10 +464,12 @@ svals(PG_FUNCTION_ARGS) {
|
|||
funcctx = SRF_PERCALL_SETUP();
|
||||
st = (AKStore *) funcctx->user_fctx;
|
||||
|
||||
if ( st->i < st->hs->size ) {
|
||||
if (st->i < st->hs->size)
|
||||
{
|
||||
HEntry *ptr = &(ARRPTR(st->hs)[st->i]);
|
||||
|
||||
if ( ptr->valisnull ) {
|
||||
if (ptr->valisnull)
|
||||
{
|
||||
ReturnSetInfo *rsi;
|
||||
|
||||
st->i++;
|
||||
|
@ -428,7 +477,9 @@ svals(PG_FUNCTION_ARGS) {
|
|||
rsi = (ReturnSetInfo *) fcinfo->resultinfo;
|
||||
rsi->isDone = ExprMultipleResult;
|
||||
PG_RETURN_NULL();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
int vallen = ptr->vallen;
|
||||
text *item = (text *) palloc(VARHDRSZ + vallen);
|
||||
|
||||
|
@ -449,7 +500,8 @@ svals(PG_FUNCTION_ARGS) {
|
|||
PG_FUNCTION_INFO_V1(hs_contains);
|
||||
Datum hs_contains(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
hs_contains(PG_FUNCTION_ARGS) {
|
||||
hs_contains(PG_FUNCTION_ARGS)
|
||||
{
|
||||
HStore *val = PG_GETARG_HS(0);
|
||||
HStore *tmpl = PG_GETARG_HS(1);
|
||||
bool res = true;
|
||||
|
@ -457,10 +509,14 @@ hs_contains(PG_FUNCTION_ARGS) {
|
|||
char *vv = STRPTR(val);
|
||||
char *tv = STRPTR(tmpl);
|
||||
|
||||
while(res && te-ARRPTR(tmpl) < tmpl->size) {
|
||||
while (res && te - ARRPTR(tmpl) < tmpl->size)
|
||||
{
|
||||
HEntry *entry = findkey(val, tv + te->pos, te->keylen);
|
||||
if ( entry ) {
|
||||
if ( ! te->valisnull ) {
|
||||
|
||||
if (entry)
|
||||
{
|
||||
if (!te->valisnull)
|
||||
{
|
||||
if (entry->valisnull || !(
|
||||
te->vallen == entry->vallen &&
|
||||
strncmp(
|
||||
|
@ -470,7 +526,8 @@ hs_contains(PG_FUNCTION_ARGS) {
|
|||
))
|
||||
res = false;
|
||||
}
|
||||
} else
|
||||
}
|
||||
else
|
||||
res = false;
|
||||
te++;
|
||||
}
|
||||
|
@ -484,7 +541,8 @@ hs_contains(PG_FUNCTION_ARGS) {
|
|||
PG_FUNCTION_INFO_V1(hs_contained);
|
||||
Datum hs_contained(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
hs_contained(PG_FUNCTION_ARGS) {
|
||||
hs_contained(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_DATUM(DirectFunctionCall2(
|
||||
hs_contains,
|
||||
PG_GETARG_DATUM(1),
|
||||
|
@ -495,11 +553,13 @@ hs_contained(PG_FUNCTION_ARGS) {
|
|||
PG_FUNCTION_INFO_V1(each);
|
||||
Datum each(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
each(PG_FUNCTION_ARGS) {
|
||||
each(PG_FUNCTION_ARGS)
|
||||
{
|
||||
FuncCallContext *funcctx;
|
||||
AKStore *st;
|
||||
|
||||
if (SRF_IS_FIRSTCALL()) {
|
||||
if (SRF_IS_FIRSTCALL())
|
||||
{
|
||||
TupleDesc tupdesc;
|
||||
MemoryContext oldcontext;
|
||||
HStore *hs = PG_GETARG_HS(0);
|
||||
|
@ -523,9 +583,11 @@ each(PG_FUNCTION_ARGS) {
|
|||
funcctx = SRF_PERCALL_SETUP();
|
||||
st = (AKStore *) funcctx->user_fctx;
|
||||
|
||||
if ( st->i < st->hs->size ) {
|
||||
if (st->i < st->hs->size)
|
||||
{
|
||||
HEntry *ptr = &(ARRPTR(st->hs)[st->i]);
|
||||
Datum res, dvalues[2];
|
||||
Datum res,
|
||||
dvalues[2];
|
||||
char nulls[] = {' ', ' '};
|
||||
text *item;
|
||||
HeapTuple tuple;
|
||||
|
@ -535,10 +597,13 @@ each(PG_FUNCTION_ARGS) {
|
|||
memcpy(VARDATA(item), STRPTR(st->hs) + ptr->pos, ptr->keylen);
|
||||
dvalues[0] = PointerGetDatum(item);
|
||||
|
||||
if ( ptr->valisnull ) {
|
||||
if (ptr->valisnull)
|
||||
{
|
||||
dvalues[1] = (Datum) 0;
|
||||
nulls[1] = 'n';
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
int vallen = ptr->vallen;
|
||||
|
||||
item = (text *) palloc(VARHDRSZ + vallen);
|
||||
|
@ -563,5 +628,3 @@ each(PG_FUNCTION_ARGS) {
|
|||
|
||||
SRF_RETURN_DONE(funcctx);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -319,23 +319,27 @@ execconsistent(QUERYTYPE * query, ArrayType *array, bool calcnot)
|
|||
);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
ITEM *first;
|
||||
bool *mapped_check;
|
||||
} GinChkVal;
|
||||
|
||||
static bool
|
||||
checkcondition_gin(void *checkval, ITEM *item) {
|
||||
checkcondition_gin(void *checkval, ITEM * item)
|
||||
{
|
||||
GinChkVal *gcv = (GinChkVal *) checkval;
|
||||
|
||||
return gcv->mapped_check[item - gcv->first];
|
||||
}
|
||||
|
||||
bool
|
||||
ginconsistent(QUERYTYPE * query, bool *check) {
|
||||
ginconsistent(QUERYTYPE * query, bool *check)
|
||||
{
|
||||
GinChkVal gcv;
|
||||
ITEM *items = GETQUERY(query);
|
||||
int i, j=0;
|
||||
int i,
|
||||
j = 0;
|
||||
|
||||
if (query->size < 0)
|
||||
return FALSE;
|
||||
|
|
|
@ -4,14 +4,16 @@ PG_FUNCTION_INFO_V1(ginint4_queryextract);
|
|||
Datum ginint4_queryextract(PG_FUNCTION_ARGS);
|
||||
|
||||
Datum
|
||||
ginint4_queryextract(PG_FUNCTION_ARGS) {
|
||||
ginint4_queryextract(PG_FUNCTION_ARGS)
|
||||
{
|
||||
uint32 *nentries = (uint32 *) PG_GETARG_POINTER(1);
|
||||
StrategyNumber strategy = PG_GETARG_UINT16(2);
|
||||
Datum *res = NULL;
|
||||
|
||||
*nentries = 0;
|
||||
|
||||
if ( strategy == BooleanSearchStrategy ) {
|
||||
if (strategy == BooleanSearchStrategy)
|
||||
{
|
||||
QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM_COPY(PG_GETARG_POINTER(0));
|
||||
ITEM *items = GETQUERY(query);
|
||||
int i;
|
||||
|
@ -31,18 +33,22 @@ ginint4_queryextract(PG_FUNCTION_ARGS) {
|
|||
*nentries = 0;
|
||||
|
||||
for (i = 0; i < query->size; i++)
|
||||
if ( items[i].type == VAL ) {
|
||||
if (items[i].type == VAL)
|
||||
{
|
||||
res[*nentries] = Int32GetDatum(items[i].val);
|
||||
(*nentries)++;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ArrayType *query = PG_GETARG_ARRAYTYPE_P(0);
|
||||
int4 *arr;
|
||||
uint32 i;
|
||||
|
||||
CHECKARRVALID(query);
|
||||
*nentries = ARRNELEMS(query);
|
||||
if ( *nentries > 0 ) {
|
||||
if (*nentries > 0)
|
||||
{
|
||||
res = (Datum *) palloc(sizeof(Datum) * (*nentries));
|
||||
|
||||
arr = ARRPTR(query);
|
||||
|
@ -58,14 +64,19 @@ PG_FUNCTION_INFO_V1(ginint4_consistent);
|
|||
Datum ginint4_consistent(PG_FUNCTION_ARGS);
|
||||
|
||||
Datum
|
||||
ginint4_consistent(PG_FUNCTION_ARGS) {
|
||||
ginint4_consistent(PG_FUNCTION_ARGS)
|
||||
{
|
||||
bool *check = (bool *) PG_GETARG_POINTER(0);
|
||||
StrategyNumber strategy = PG_GETARG_UINT16(1);
|
||||
int res = FALSE;
|
||||
|
||||
/* we can do not check array carefully, it's done by previous ginarrayextract call */
|
||||
/*
|
||||
* we can do not check array carefully, it's done by previous
|
||||
* ginarrayextract call
|
||||
*/
|
||||
|
||||
switch( strategy ) {
|
||||
switch (strategy)
|
||||
{
|
||||
case RTOverlapStrategyNumber:
|
||||
case RTContainedByStrategyNumber:
|
||||
case RTOldContainedByStrategyNumber:
|
||||
|
@ -77,20 +88,25 @@ ginint4_consistent(PG_FUNCTION_ARGS) {
|
|||
case RTContainsStrategyNumber:
|
||||
case RTOldContainsStrategyNumber:
|
||||
res = TRUE;
|
||||
do {
|
||||
do
|
||||
{
|
||||
ArrayType *query = PG_GETARG_ARRAYTYPE_P(2);
|
||||
int i, nentries=ARRNELEMS(query);
|
||||
int i,
|
||||
nentries = ARRNELEMS(query);
|
||||
|
||||
for (i = 0; i < nentries; i++)
|
||||
if ( !check[i] ) {
|
||||
if (!check[i])
|
||||
{
|
||||
res = FALSE;
|
||||
break;
|
||||
}
|
||||
} while (0);
|
||||
break;
|
||||
case BooleanSearchStrategy:
|
||||
do {
|
||||
do
|
||||
{
|
||||
QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_POINTER(2));
|
||||
|
||||
res = ginconsistent(query, check);
|
||||
} while (0);
|
||||
break;
|
||||
|
|
|
@ -36,7 +36,8 @@ g_int_consistent(PG_FUNCTION_ARGS)
|
|||
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
|
||||
bool retval;
|
||||
|
||||
if (strategy == BooleanSearchStrategy) {
|
||||
if (strategy == BooleanSearchStrategy)
|
||||
{
|
||||
retval = execconsistent((QUERYTYPE *) query,
|
||||
(ArrayType *) DatumGetPointer(entry->key),
|
||||
GIST_LEAF(entry));
|
||||
|
@ -47,7 +48,8 @@ g_int_consistent(PG_FUNCTION_ARGS)
|
|||
|
||||
/* sort query for fast search, key is already sorted */
|
||||
CHECKARRVALID(query);
|
||||
if (ARRISVOID(query)) {
|
||||
if (ARRISVOID(query))
|
||||
{
|
||||
pfree(query);
|
||||
PG_RETURN_BOOL(false);
|
||||
}
|
||||
|
|
|
@ -93,18 +93,23 @@ inner_int_union(ArrayType *a, ArrayType *b)
|
|||
nb = ARRNELEMS(b);
|
||||
int *da = ARRPTR(a),
|
||||
*db = ARRPTR(b);
|
||||
int i,j, *dr;
|
||||
int i,
|
||||
j,
|
||||
*dr;
|
||||
|
||||
r = new_intArrayType(na + nb);
|
||||
dr = ARRPTR(r);
|
||||
|
||||
/* union */
|
||||
i = j = 0;
|
||||
while (i < na && j < nb) {
|
||||
if (da[i] == db[j]) {
|
||||
while (i < na && j < nb)
|
||||
{
|
||||
if (da[i] == db[j])
|
||||
{
|
||||
*dr++ = da[i++];
|
||||
j++;
|
||||
} else if (da[i] < db[j])
|
||||
}
|
||||
else if (da[i] < db[j])
|
||||
*dr++ = da[i++];
|
||||
else
|
||||
*dr++ = db[j++];
|
||||
|
|
|
@ -514,7 +514,8 @@ g_intbig_consistent(PG_FUNCTION_ARGS)
|
|||
}
|
||||
|
||||
CHECKARRVALID(query);
|
||||
if (ARRISVOID(query)) {
|
||||
if (ARRISVOID(query))
|
||||
{
|
||||
PG_FREE_IF_COPY(query, 1);
|
||||
PG_RETURN_BOOL(FALSE);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* http://www.gs1.org/productssolutions/idkeys/support/prefix_list.html
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/contrib/isn/EAN13.h,v 1.1 2006/09/09 04:07:52 tgl Exp $
|
||||
* $PostgreSQL: pgsql/contrib/isn/EAN13.h,v 1.2 2006/10/04 00:29:45 momjian Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -139,7 +139,8 @@ const char *EAN13_range[][2] = {
|
|||
{"958", "958"}, /* GS1 Macau */
|
||||
{"977", "977"}, /* Serial publications (ISSN) */
|
||||
{"978", "978"}, /* Bookland (ISBN) */
|
||||
{"979", "979"}, /* International Standard Music Number (ISMN) and ISBN contingent */
|
||||
{"979", "979"}, /* International Standard Music Number (ISMN)
|
||||
* and ISBN contingent */
|
||||
{"980", "980"}, /* Refund receipts */
|
||||
{"981", "982"}, /* Common Currency Coupons */
|
||||
{"990", "999"}, /* Coupons */
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* http://www.isbn.org/
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/contrib/isn/ISBN.h,v 1.1 2006/09/09 04:07:52 tgl Exp $
|
||||
* $PostgreSQL: pgsql/contrib/isn/ISBN.h,v 1.2 2006/10/04 00:29:45 momjian Exp $
|
||||
*
|
||||
* 0-393-04002-X => 039304002(X) <=> 039304002 <=> (978)039304002 <=> 978039304002(9) <=> 978-0-393-04002-9
|
||||
*
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* http://www.ismn-international.org
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/contrib/isn/ISMN.h,v 1.1 2006/09/09 04:07:52 tgl Exp $
|
||||
* $PostgreSQL: pgsql/contrib/isn/ISMN.h,v 1.2 2006/10/04 00:29:45 momjian Exp $
|
||||
*
|
||||
* M-3452-4680-5 <=> (0)-3452-4680-5 <=> 0345246805 <=> 9790345246805 <=> 979-0-3452-4680-5
|
||||
*
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* http://www.issn.org/
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/contrib/isn/ISSN.h,v 1.1 2006/09/09 04:07:52 tgl Exp $
|
||||
* $PostgreSQL: pgsql/contrib/isn/ISSN.h,v 1.2 2006/10/04 00:29:45 momjian Exp $
|
||||
*
|
||||
* 1144-875X <=> 1144875(X) <=> 1144875 <=> (977)1144875 <=> 9771144875(00) <=> 977114487500(7) <=> 977-1144-875-00-7
|
||||
*
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/contrib/isn/UPC.h,v 1.1 2006/09/09 04:07:52 tgl Exp $
|
||||
* $PostgreSQL: pgsql/contrib/isn/UPC.h,v 1.2 2006/10/04 00:29:45 momjian Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/contrib/isn/isn.c,v 1.3 2006/09/22 21:39:57 tgl Exp $
|
||||
* $PostgreSQL: pgsql/contrib/isn/isn.c,v 1.4 2006/10/04 00:29:45 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -29,7 +29,10 @@ PG_MODULE_MAGIC;
|
|||
|
||||
#define MAXEAN13LEN 18
|
||||
|
||||
enum isn_type { INVALID, ANY, EAN13, ISBN, ISMN, ISSN, UPC };
|
||||
enum isn_type
|
||||
{
|
||||
INVALID, ANY, EAN13, ISBN, ISMN, ISSN, UPC
|
||||
};
|
||||
|
||||
static const char *isn_names[] = {"EAN13/UPC/ISxN", "EAN13/UPC/ISxN", "EAN13", "ISBN", "ISMN", "ISSN", "UPC"};
|
||||
|
||||
|
@ -60,14 +63,25 @@ static bool g_initialized = false;
|
|||
*/
|
||||
#ifdef ISN_DEBUG
|
||||
static
|
||||
bool check_table(const char *(*TABLE)[2], const unsigned TABLE_index[10][2])
|
||||
bool
|
||||
check_table(const char *(*TABLE)[2], const unsigned TABLE_index[10][2])
|
||||
{
|
||||
const char *aux1, *aux2;
|
||||
int a, b, x=0, y=-1, i=0, j, cnt=0, init=0;
|
||||
const char *aux1,
|
||||
*aux2;
|
||||
int a,
|
||||
b,
|
||||
x = 0,
|
||||
y = -1,
|
||||
i = 0,
|
||||
j,
|
||||
cnt = 0,
|
||||
init = 0;
|
||||
|
||||
if(TABLE == NULL || TABLE_index == NULL) return true;
|
||||
if (TABLE == NULL || TABLE_index == NULL)
|
||||
return true;
|
||||
|
||||
while(TABLE[i][0] && TABLE[i][1]) {
|
||||
while (TABLE[i][0] && TABLE[i][1])
|
||||
{
|
||||
aux1 = TABLE[i][0];
|
||||
aux2 = TABLE[i][1];
|
||||
|
||||
|
@ -78,7 +92,8 @@ bool check_table(const char *(*TABLE)[2], const unsigned TABLE_index[10][2])
|
|||
b = *aux2 - '0';
|
||||
|
||||
/* must always have the same format and length: */
|
||||
while(*aux1 && *aux2) {
|
||||
while (*aux1 && *aux2)
|
||||
{
|
||||
if (!(isdigit((unsigned char) *aux1) &&
|
||||
isdigit((unsigned char) *aux2)) &&
|
||||
(*aux1 != *aux2 || *aux1 != '-'))
|
||||
|
@ -86,14 +101,19 @@ bool check_table(const char *(*TABLE)[2], const unsigned TABLE_index[10][2])
|
|||
aux1++;
|
||||
aux2++;
|
||||
}
|
||||
if(*aux1!=*aux2) goto invalidtable;
|
||||
if (*aux1 != *aux2)
|
||||
goto invalidtable;
|
||||
|
||||
/* found a new range */
|
||||
if(a>y) {
|
||||
if (a > y)
|
||||
{
|
||||
/* check current range in the index: */
|
||||
for(j=x;j<=y;j++) {
|
||||
if(TABLE_index[j][0] != init) goto invalidindex;
|
||||
if(TABLE_index[j][1] != i-init) goto invalidindex;
|
||||
for (j = x; j <= y; j++)
|
||||
{
|
||||
if (TABLE_index[j][0] != init)
|
||||
goto invalidindex;
|
||||
if (TABLE_index[j][1] != i - init)
|
||||
goto invalidindex;
|
||||
}
|
||||
init = i;
|
||||
x = a;
|
||||
|
@ -101,7 +121,8 @@ bool check_table(const char *(*TABLE)[2], const unsigned TABLE_index[10][2])
|
|||
|
||||
/* Always get the new limit */
|
||||
y = b;
|
||||
if(y<x) goto invalidtable;
|
||||
if (y < x)
|
||||
goto invalidtable;
|
||||
i++;
|
||||
}
|
||||
|
||||
|
@ -123,11 +144,15 @@ invalidindex:
|
|||
*---------------------------------------------------------*/
|
||||
|
||||
static
|
||||
unsigned dehyphenate(char *bufO, char *bufI)
|
||||
unsigned
|
||||
dehyphenate(char *bufO, char *bufI)
|
||||
{
|
||||
unsigned ret = 0;
|
||||
while(*bufI) {
|
||||
if(isdigit((unsigned char) *bufI)) {
|
||||
|
||||
while (*bufI)
|
||||
{
|
||||
if (isdigit((unsigned char) *bufI))
|
||||
{
|
||||
*bufO++ = *bufI;
|
||||
ret++;
|
||||
}
|
||||
|
@ -145,17 +170,28 @@ unsigned dehyphenate(char *bufO, char *bufI)
|
|||
* Returns the number of characters acctually hyphenated.
|
||||
*/
|
||||
static
|
||||
unsigned hyphenate(char *bufO, char *bufI, const char *(*TABLE)[2], const unsigned TABLE_index[10][2])
|
||||
unsigned
|
||||
hyphenate(char *bufO, char *bufI, const char *(*TABLE)[2], const unsigned TABLE_index[10][2])
|
||||
{
|
||||
unsigned ret = 0;
|
||||
const char *ean_aux1, *ean_aux2, *ean_p;
|
||||
char *firstdig, *aux1, *aux2;
|
||||
unsigned search, upper, lower, step;
|
||||
bool ean_in1, ean_in2;
|
||||
const char *ean_aux1,
|
||||
*ean_aux2,
|
||||
*ean_p;
|
||||
char *firstdig,
|
||||
*aux1,
|
||||
*aux2;
|
||||
unsigned search,
|
||||
upper,
|
||||
lower,
|
||||
step;
|
||||
bool ean_in1,
|
||||
ean_in2;
|
||||
|
||||
/* just compress the string if no further hyphenation is required */
|
||||
if(TABLE == NULL || TABLE_index == NULL) {
|
||||
while(*bufI) {
|
||||
if (TABLE == NULL || TABLE_index == NULL)
|
||||
{
|
||||
while (*bufI)
|
||||
{
|
||||
*bufO++ = *bufI++;
|
||||
ret++;
|
||||
}
|
||||
|
@ -171,26 +207,41 @@ unsigned hyphenate(char *bufO, char *bufI, const char *(*TABLE)[2], const unsign
|
|||
lower--;
|
||||
|
||||
step = (upper - lower) / 2;
|
||||
if(step == 0) return 0;
|
||||
if (step == 0)
|
||||
return 0;
|
||||
search = lower + step;
|
||||
|
||||
firstdig = bufI;
|
||||
ean_in1 = ean_in2 = false;
|
||||
ean_aux1 = TABLE[search][0];
|
||||
ean_aux2 = TABLE[search][1];
|
||||
do {
|
||||
if((ean_in1 || *firstdig>=*ean_aux1) && (ean_in2 || *firstdig<=*ean_aux2)) {
|
||||
if(*firstdig > *ean_aux1) ean_in1 = true;
|
||||
if(*firstdig < *ean_aux2) ean_in2 = true;
|
||||
if(ean_in1 && ean_in2) break;
|
||||
do
|
||||
{
|
||||
if ((ean_in1 || *firstdig >= *ean_aux1) && (ean_in2 || *firstdig <= *ean_aux2))
|
||||
{
|
||||
if (*firstdig > *ean_aux1)
|
||||
ean_in1 = true;
|
||||
if (*firstdig < *ean_aux2)
|
||||
ean_in2 = true;
|
||||
if (ean_in1 && ean_in2)
|
||||
break;
|
||||
|
||||
firstdig++, ean_aux1++, ean_aux2++;
|
||||
if(!(*ean_aux1 && *ean_aux2 && *firstdig)) break;
|
||||
if(!isdigit((unsigned char) *ean_aux1)) ean_aux1++, ean_aux2++;
|
||||
} else {
|
||||
/* check in what direction we should go and move the pointer accordingly */
|
||||
if(*firstdig < *ean_aux1 && !ean_in1) upper = search;
|
||||
else lower = search;
|
||||
if (!(*ean_aux1 && *ean_aux2 && *firstdig))
|
||||
break;
|
||||
if (!isdigit((unsigned char) *ean_aux1))
|
||||
ean_aux1++, ean_aux2++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* check in what direction we should go and move the pointer
|
||||
* accordingly
|
||||
*/
|
||||
if (*firstdig < *ean_aux1 && !ean_in1)
|
||||
upper = search;
|
||||
else
|
||||
lower = search;
|
||||
|
||||
step = (upper - lower) / 2;
|
||||
search = lower + step;
|
||||
|
@ -203,13 +254,17 @@ unsigned hyphenate(char *bufO, char *bufI, const char *(*TABLE)[2], const unsign
|
|||
}
|
||||
} while (step);
|
||||
|
||||
if(step) {
|
||||
if (step)
|
||||
{
|
||||
aux1 = bufO;
|
||||
aux2 = bufI;
|
||||
ean_p = TABLE[search][0];
|
||||
while(*ean_p && *aux2) {
|
||||
if(*ean_p++!='-') *aux1++ = *aux2++;
|
||||
else *aux1++ = '-';
|
||||
while (*ean_p && *aux2)
|
||||
{
|
||||
if (*ean_p++ != '-')
|
||||
*aux1++ = *aux2++;
|
||||
else
|
||||
*aux1++ = '-';
|
||||
ret++;
|
||||
}
|
||||
*aux1++ = '-';
|
||||
|
@ -226,17 +281,22 @@ unsigned hyphenate(char *bufO, char *bufI, const char *(*TABLE)[2], const unsign
|
|||
* Returns the weight of the number (the check digit value, 0-10)
|
||||
*/
|
||||
static
|
||||
unsigned weight_checkdig(char *isn, unsigned size)
|
||||
unsigned
|
||||
weight_checkdig(char *isn, unsigned size)
|
||||
{
|
||||
unsigned weight = 0;
|
||||
while(*isn && size>1) {
|
||||
if(isdigit((unsigned char) *isn)) {
|
||||
|
||||
while (*isn && size > 1)
|
||||
{
|
||||
if (isdigit((unsigned char) *isn))
|
||||
{
|
||||
weight += size-- * (*isn - '0');
|
||||
}
|
||||
isn++;
|
||||
}
|
||||
weight = weight % 11;
|
||||
if(weight != 0) weight = 11 - weight;
|
||||
if (weight != 0)
|
||||
weight = 11 - weight;
|
||||
return weight;
|
||||
}
|
||||
|
||||
|
@ -248,24 +308,33 @@ unsigned weight_checkdig(char *isn, unsigned size)
|
|||
* Returns the check digit value (0-9)
|
||||
*/
|
||||
static
|
||||
unsigned checkdig(char *num, unsigned size)
|
||||
unsigned
|
||||
checkdig(char *num, unsigned size)
|
||||
{
|
||||
unsigned check=0, check3=0;
|
||||
unsigned check = 0,
|
||||
check3 = 0;
|
||||
unsigned pos = 0;
|
||||
if(*num == 'M') { /* ISMN start with 'M' */
|
||||
|
||||
if (*num == 'M')
|
||||
{ /* ISMN start with 'M' */
|
||||
check3 = 3;
|
||||
pos = 1;
|
||||
}
|
||||
while(*num && size>1) {
|
||||
if(isdigit((unsigned char) *num)) {
|
||||
if(pos++%2) check3 += *num - '0';
|
||||
else check += *num - '0';
|
||||
while (*num && size > 1)
|
||||
{
|
||||
if (isdigit((unsigned char) *num))
|
||||
{
|
||||
if (pos++ % 2)
|
||||
check3 += *num - '0';
|
||||
else
|
||||
check += *num - '0';
|
||||
size--;
|
||||
}
|
||||
num++;
|
||||
}
|
||||
check = (check + 3 * check3) % 10;
|
||||
if(check != 0) check = 10 - check;
|
||||
if (check != 0)
|
||||
check = 10 - check;
|
||||
return check;
|
||||
}
|
||||
|
||||
|
@ -277,12 +346,14 @@ unsigned checkdig(char *num, unsigned size)
|
|||
* If errorOK is true, just return "false" for bad input.
|
||||
*/
|
||||
static
|
||||
bool ean2isn(ean13 ean, bool errorOK, ean13 *result, enum isn_type accept)
|
||||
bool
|
||||
ean2isn(ean13 ean, bool errorOK, ean13 * result, enum isn_type accept)
|
||||
{
|
||||
enum isn_type type = INVALID;
|
||||
|
||||
char buf[MAXEAN13LEN + 1];
|
||||
char *firstdig, *aux;
|
||||
char *firstdig,
|
||||
*aux;
|
||||
unsigned digval;
|
||||
unsigned search;
|
||||
ean13 ret = ean;
|
||||
|
@ -296,40 +367,58 @@ bool ean2isn(ean13 ean, bool errorOK, ean13 *result, enum isn_type accept)
|
|||
search = 0;
|
||||
firstdig = aux = buf + 13;
|
||||
*aux = '\0'; /* terminate string; aux points to last digit */
|
||||
do {
|
||||
do
|
||||
{
|
||||
digval = (unsigned) (ean % 10); /* get the decimal value */
|
||||
ean /= 10; /* get next digit */
|
||||
*--aux = (char) (digval + '0'); /* convert to ascii and store */
|
||||
} while (ean && search++ < 12);
|
||||
while(search++<12) *--aux = '0'; /* fill the remaining EAN13 with '0' */
|
||||
while (search++ < 12)
|
||||
*--aux = '0'; /* fill the remaining EAN13 with '0' */
|
||||
|
||||
/* find out the data type: */
|
||||
if(!strncmp("978", buf, 3)) { /* ISBN */
|
||||
if (!strncmp("978", buf, 3))
|
||||
{ /* ISBN */
|
||||
type = ISBN;
|
||||
} else if(!strncmp("977", buf, 3)) { /* ISSN */
|
||||
}
|
||||
else if (!strncmp("977", buf, 3))
|
||||
{ /* ISSN */
|
||||
type = ISSN;
|
||||
} else if(!strncmp("9790", buf, 4)) { /* ISMN */
|
||||
}
|
||||
else if (!strncmp("9790", buf, 4))
|
||||
{ /* ISMN */
|
||||
type = ISMN;
|
||||
} else if(!strncmp("979", buf, 3)) { /* ISBN-13 */
|
||||
}
|
||||
else if (!strncmp("979", buf, 3))
|
||||
{ /* ISBN-13 */
|
||||
type = ISBN;
|
||||
} else if(*buf == '0') { /* UPC */
|
||||
}
|
||||
else if (*buf == '0')
|
||||
{ /* UPC */
|
||||
type = UPC;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
type = EAN13;
|
||||
}
|
||||
if(accept != ANY && accept != EAN13 && accept != type) goto eanwrongtype;
|
||||
if (accept != ANY && accept != EAN13 && accept != type)
|
||||
goto eanwrongtype;
|
||||
|
||||
*result = ret;
|
||||
return true;
|
||||
|
||||
eanwrongtype:
|
||||
if(!errorOK) {
|
||||
if(type!=EAN13) {
|
||||
if (!errorOK)
|
||||
{
|
||||
if (type != EAN13)
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||
errmsg("cannot cast EAN13(%s) to %s for number: \"%s\"",
|
||||
isn_names[type], isn_names[accept], buf)));
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||
errmsg("cannot cast %s to %s for number: \"%s\"",
|
||||
|
@ -339,12 +428,13 @@ eanwrongtype:
|
|||
return false;
|
||||
|
||||
eantoobig:
|
||||
if(!errorOK) {
|
||||
if (!errorOK)
|
||||
{
|
||||
char eanbuf[64];
|
||||
|
||||
/*
|
||||
* Format the number separately to keep the machine-dependent
|
||||
* format code out of the translatable message text
|
||||
* Format the number separately to keep the machine-dependent format
|
||||
* code out of the translatable message text
|
||||
*/
|
||||
snprintf(eanbuf, sizeof(eanbuf), EAN13_FORMAT, ean);
|
||||
ereport(ERROR,
|
||||
|
@ -360,21 +450,26 @@ eantoobig:
|
|||
* UPC/ISxN string number. Assumes the input string is normalized.
|
||||
*/
|
||||
static inline
|
||||
void ean2ISBN(char *isn)
|
||||
void
|
||||
ean2ISBN(char *isn)
|
||||
{
|
||||
char *aux;
|
||||
unsigned check;
|
||||
|
||||
/* the number should come in this format: 978-0-000-00000-0 */
|
||||
/* Strip the first part and calculate the new check digit */
|
||||
hyphenate(isn, isn + 4, NULL, NULL);
|
||||
check = weight_checkdig(isn, 10);
|
||||
aux = strchr(isn, '\0');
|
||||
while (!isdigit((unsigned char) *--aux));
|
||||
if(check == 10) *aux = 'X';
|
||||
else *aux = check + '0';
|
||||
if (check == 10)
|
||||
*aux = 'X';
|
||||
else
|
||||
*aux = check + '0';
|
||||
}
|
||||
static inline
|
||||
void ean2ISMN(char *isn)
|
||||
void
|
||||
ean2ISMN(char *isn)
|
||||
{
|
||||
/* the number should come in this format: 979-0-000-00000-0 */
|
||||
/* Just strip the first part and change the first digit ('0') to 'M' */
|
||||
|
@ -382,19 +477,24 @@ void ean2ISMN(char *isn)
|
|||
isn[0] = 'M';
|
||||
}
|
||||
static inline
|
||||
void ean2ISSN(char *isn)
|
||||
void
|
||||
ean2ISSN(char *isn)
|
||||
{
|
||||
unsigned check;
|
||||
|
||||
/* the number should come in this format: 977-0000-000-00-0 */
|
||||
/* Strip the first part, crop, and calculate the new check digit */
|
||||
hyphenate(isn, isn + 4, NULL, NULL);
|
||||
check = weight_checkdig(isn, 8);
|
||||
if(check == 10) isn[8] = 'X';
|
||||
else isn[8] = check + '0';
|
||||
if (check == 10)
|
||||
isn[8] = 'X';
|
||||
else
|
||||
isn[8] = check + '0';
|
||||
isn[9] = '\0';
|
||||
}
|
||||
static inline
|
||||
void ean2UPC(char *isn)
|
||||
void
|
||||
ean2UPC(char *isn)
|
||||
{
|
||||
/* the number should come in this format: 000-000000000-0 */
|
||||
/* Strip the first part, crop, and dehyphenate */
|
||||
|
@ -410,11 +510,15 @@ void ean2UPC(char *isn)
|
|||
* Returns the ean13 value of the string.
|
||||
*/
|
||||
static
|
||||
ean13 str2ean(const char *num)
|
||||
ean13
|
||||
str2ean(const char *num)
|
||||
{
|
||||
ean13 ean = 0; /* current ean */
|
||||
while(*num) {
|
||||
if(isdigit((unsigned char) *num)) ean = 10 * ean + (*num - '0');
|
||||
|
||||
while (*num)
|
||||
{
|
||||
if (isdigit((unsigned char) *num))
|
||||
ean = 10 * ean + (*num - '0');
|
||||
num++;
|
||||
}
|
||||
return (ean << 1); /* also give room to a flag */
|
||||
|
@ -431,20 +535,24 @@ ean13 str2ean(const char *num)
|
|||
* If errorOK is true, just return "false" for bad input.
|
||||
*/
|
||||
static
|
||||
bool ean2string(ean13 ean, bool errorOK, char *result, bool shortType)
|
||||
bool
|
||||
ean2string(ean13 ean, bool errorOK, char *result, bool shortType)
|
||||
{
|
||||
const char *(*TABLE)[2];
|
||||
const unsigned (*TABLE_index)[2];
|
||||
enum isn_type type = INVALID;
|
||||
|
||||
char *firstdig, *aux;
|
||||
char *firstdig,
|
||||
*aux;
|
||||
unsigned digval;
|
||||
unsigned search;
|
||||
char valid = '\0'; /* was the number initially written with a valid check digit? */
|
||||
char valid = '\0'; /* was the number initially written with a
|
||||
* valid check digit? */
|
||||
|
||||
TABLE_index = ISBN_index;
|
||||
|
||||
if((ean & 1)!=0) valid = '!';
|
||||
if ((ean & 1) != 0)
|
||||
valid = '!';
|
||||
ean >>= 1;
|
||||
/* verify it's in the EAN13 range */
|
||||
if (ean > UINT64CONST(9999999999999))
|
||||
|
@ -454,46 +562,60 @@ bool ean2string(ean13 ean, bool errorOK, char *result, bool shortType)
|
|||
search = 0;
|
||||
firstdig = aux = result + MAXEAN13LEN;
|
||||
*aux = '\0'; /* terminate string; aux points to last digit */
|
||||
*--aux = valid; /* append '!' for numbers with invalid but corrected check digit */
|
||||
do {
|
||||
*--aux = valid; /* append '!' for numbers with invalid but
|
||||
* corrected check digit */
|
||||
do
|
||||
{
|
||||
digval = (unsigned) (ean % 10); /* get the decimal value */
|
||||
ean /= 10; /* get next digit */
|
||||
*--aux = (char) (digval + '0'); /* convert to ascii and store */
|
||||
if(search == 0) *--aux = '-'; /* the check digit is always there */
|
||||
if (search == 0)
|
||||
*--aux = '-'; /* the check digit is always there */
|
||||
} while (ean && search++ < 13);
|
||||
while(search++<13) *--aux = '0'; /* fill the remaining EAN13 with '0' */
|
||||
while (search++ < 13)
|
||||
*--aux = '0'; /* fill the remaining EAN13 with '0' */
|
||||
|
||||
/* The string should be in this form: ???DDDDDDDDDDDD-D" */
|
||||
search = hyphenate(result, result + 3, EAN13_range, EAN13_index);
|
||||
|
||||
/* verify it's a logically valid EAN13 */
|
||||
if(search == 0) {
|
||||
if (search == 0)
|
||||
{
|
||||
search = hyphenate(result, result + 3, NULL, NULL);
|
||||
goto okay;
|
||||
}
|
||||
|
||||
/* find out what type of hyphenation is needed: */
|
||||
if(!strncmp("978-", result, search)) { /* ISBN */
|
||||
if (!strncmp("978-", result, search))
|
||||
{ /* ISBN */
|
||||
/* The string should be in this form: 978-??000000000-0" */
|
||||
type = ISBN;
|
||||
TABLE = ISBN_range;
|
||||
TABLE_index = ISBN_index;
|
||||
} else if(!strncmp("977-", result, search)) { /* ISSN */
|
||||
}
|
||||
else if (!strncmp("977-", result, search))
|
||||
{ /* ISSN */
|
||||
/* The string should be in this form: 977-??000000000-0" */
|
||||
type = ISSN;
|
||||
TABLE = ISSN_range;
|
||||
TABLE_index = ISSN_index;
|
||||
} else if(!strncmp("979-0", result, search+1)) { /* ISMN */
|
||||
}
|
||||
else if (!strncmp("979-0", result, search + 1))
|
||||
{ /* ISMN */
|
||||
/* The string should be in this form: 979-0?000000000-0" */
|
||||
type = ISMN;
|
||||
TABLE = ISMN_range;
|
||||
TABLE_index = ISMN_index;
|
||||
} else if(*result == '0') { /* UPC */
|
||||
}
|
||||
else if (*result == '0')
|
||||
{ /* UPC */
|
||||
/* The string should be in this form: 000-00000000000-0" */
|
||||
type = UPC;
|
||||
TABLE = UPC_range;
|
||||
TABLE_index = UPC_index;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
type = EAN13;
|
||||
TABLE = NULL;
|
||||
TABLE_index = NULL;
|
||||
|
@ -504,7 +626,8 @@ bool ean2string(ean13 ean, bool errorOK, char *result, bool shortType)
|
|||
search = hyphenate(result + digval, result + digval + 2, TABLE, TABLE_index);
|
||||
|
||||
/* verify it's a valid EAN13 */
|
||||
if(search == 0) {
|
||||
if (search == 0)
|
||||
{
|
||||
search = hyphenate(result + digval, result + digval + 2, NULL, NULL);
|
||||
goto okay;
|
||||
}
|
||||
|
@ -512,7 +635,8 @@ bool ean2string(ean13 ean, bool errorOK, char *result, bool shortType)
|
|||
okay:
|
||||
/* convert to the old short type: */
|
||||
if (shortType)
|
||||
switch(type) {
|
||||
switch (type)
|
||||
{
|
||||
case ISBN:
|
||||
ean2ISBN(result);
|
||||
break;
|
||||
|
@ -536,8 +660,8 @@ eantoobig:
|
|||
char eanbuf[64];
|
||||
|
||||
/*
|
||||
* Format the number separately to keep the machine-dependent
|
||||
* format code out of the translatable message text
|
||||
* Format the number separately to keep the machine-dependent format
|
||||
* code out of the translatable message text
|
||||
*/
|
||||
snprintf(eanbuf, sizeof(eanbuf), EAN13_FORMAT, ean);
|
||||
ereport(ERROR,
|
||||
|
@ -558,103 +682,161 @@ eantoobig:
|
|||
* (even if the check digit is valid)
|
||||
*/
|
||||
static
|
||||
bool string2ean(const char *str, bool errorOK, ean13 *result,
|
||||
bool
|
||||
string2ean(const char *str, bool errorOK, ean13 * result,
|
||||
enum isn_type accept)
|
||||
{
|
||||
bool digit, last;
|
||||
bool digit,
|
||||
last;
|
||||
char buf[17] = " ";
|
||||
char *aux1 = buf + 3; /* leave space for the first part, in case it's needed */
|
||||
char *aux1 = buf + 3; /* leave space for the first part, in case
|
||||
* it's needed */
|
||||
const char *aux2 = str;
|
||||
enum isn_type type = INVALID;
|
||||
unsigned check = 0, rcheck = (unsigned)-1;
|
||||
unsigned check = 0,
|
||||
rcheck = (unsigned) -1;
|
||||
unsigned length = 0;
|
||||
bool magic = false, valid = true;
|
||||
bool magic = false,
|
||||
valid = true;
|
||||
|
||||
/* recognize and validate the number: */
|
||||
while(*aux2 && length <= 13) {
|
||||
while (*aux2 && length <= 13)
|
||||
{
|
||||
last = (*(aux2 + 1) == '!' || *(aux2 + 1) == '\0'); /* is the last character */
|
||||
digit = (isdigit((unsigned char) *aux2)!=0); /* is current character a digit? */
|
||||
if(*aux2=='?' && last) /* automagically calculate check digit if it's '?' */
|
||||
digit = (isdigit((unsigned char) *aux2) != 0); /* is current character
|
||||
* a digit? */
|
||||
if (*aux2 == '?' && last) /* automagically calculate check digit
|
||||
* if it's '?' */
|
||||
magic = digit = true;
|
||||
if(length == 0 && (*aux2=='M' || *aux2=='m')) {
|
||||
if (length == 0 && (*aux2 == 'M' || *aux2 == 'm'))
|
||||
{
|
||||
/* only ISMN can be here */
|
||||
if(type != INVALID) goto eaninvalid;
|
||||
if (type != INVALID)
|
||||
goto eaninvalid;
|
||||
type = ISMN;
|
||||
*aux1++ = 'M';
|
||||
length++;
|
||||
} else if(length == 7 && (digit || *aux2=='X' || *aux2=='x') && last) {
|
||||
}
|
||||
else if (length == 7 && (digit || *aux2 == 'X' || *aux2 == 'x') && last)
|
||||
{
|
||||
/* only ISSN can be here */
|
||||
if(type != INVALID) goto eaninvalid;
|
||||
if (type != INVALID)
|
||||
goto eaninvalid;
|
||||
type = ISSN;
|
||||
*aux1++ = toupper((unsigned char) *aux2);
|
||||
length++;
|
||||
} else if(length == 9 && (digit || *aux2=='X' || *aux2=='x') && last) {
|
||||
}
|
||||
else if (length == 9 && (digit || *aux2 == 'X' || *aux2 == 'x') && last)
|
||||
{
|
||||
/* only ISBN and ISMN can be here */
|
||||
if(type != INVALID && type != ISMN) goto eaninvalid;
|
||||
if(type == INVALID) type = ISBN; /* ISMN must start with 'M' */
|
||||
if (type != INVALID && type != ISMN)
|
||||
goto eaninvalid;
|
||||
if (type == INVALID)
|
||||
type = ISBN; /* ISMN must start with 'M' */
|
||||
*aux1++ = toupper((unsigned char) *aux2);
|
||||
length++;
|
||||
} else if(length == 11 && digit && last) {
|
||||
}
|
||||
else if (length == 11 && digit && last)
|
||||
{
|
||||
/* only UPC can be here */
|
||||
if(type != INVALID) goto eaninvalid;
|
||||
if (type != INVALID)
|
||||
goto eaninvalid;
|
||||
type = UPC;
|
||||
*aux1++ = *aux2;
|
||||
length++;
|
||||
} else if(*aux2 == '-' || *aux2 == ' ') {
|
||||
}
|
||||
else if (*aux2 == '-' || *aux2 == ' ')
|
||||
{
|
||||
/* skip, we could validate but I think it's worthless */
|
||||
} else if(*aux2 == '!' && *(aux2+1) == '\0') {
|
||||
}
|
||||
else if (*aux2 == '!' && *(aux2 + 1) == '\0')
|
||||
{
|
||||
/* the invalid check digit sufix was found, set it */
|
||||
if(!magic) valid = false;
|
||||
if (!magic)
|
||||
valid = false;
|
||||
magic = true;
|
||||
} else if(!digit) {
|
||||
}
|
||||
else if (!digit)
|
||||
{
|
||||
goto eaninvalid;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
*aux1++ = *aux2;
|
||||
if(++length > 13) goto eantoobig;
|
||||
if (++length > 13)
|
||||
goto eantoobig;
|
||||
}
|
||||
aux2++;
|
||||
}
|
||||
*aux1 = '\0'; /* terminate the string */
|
||||
|
||||
/* find the current check digit value */
|
||||
if(length == 13) {
|
||||
if (length == 13)
|
||||
{
|
||||
/* only EAN13 can be here */
|
||||
if(type != INVALID) goto eaninvalid;
|
||||
if (type != INVALID)
|
||||
goto eaninvalid;
|
||||
type = EAN13;
|
||||
check = buf[15] - '0';
|
||||
} else if(length == 12) {
|
||||
}
|
||||
else if (length == 12)
|
||||
{
|
||||
/* only UPC can be here */
|
||||
if(type != UPC) goto eaninvalid;
|
||||
if (type != UPC)
|
||||
goto eaninvalid;
|
||||
check = buf[14] - '0';
|
||||
} else if(length == 10) {
|
||||
if(type != ISBN && type != ISMN) goto eaninvalid;
|
||||
if(buf[12] == 'X') check = 10;
|
||||
else check = buf[12]-'0';
|
||||
} else if(length == 8) {
|
||||
if(type != INVALID && type != ISSN) goto eaninvalid;
|
||||
}
|
||||
else if (length == 10)
|
||||
{
|
||||
if (type != ISBN && type != ISMN)
|
||||
goto eaninvalid;
|
||||
if (buf[12] == 'X')
|
||||
check = 10;
|
||||
else
|
||||
check = buf[12] - '0';
|
||||
}
|
||||
else if (length == 8)
|
||||
{
|
||||
if (type != INVALID && type != ISSN)
|
||||
goto eaninvalid;
|
||||
type = ISSN;
|
||||
if(buf[10] == 'X') check = 10;
|
||||
else check = buf[10]-'0';
|
||||
} else goto eaninvalid;
|
||||
if (buf[10] == 'X')
|
||||
check = 10;
|
||||
else
|
||||
check = buf[10] - '0';
|
||||
}
|
||||
else
|
||||
goto eaninvalid;
|
||||
|
||||
if(type == INVALID) goto eaninvalid;
|
||||
if (type == INVALID)
|
||||
goto eaninvalid;
|
||||
|
||||
/* obtain the real check digit value, validate, and convert to ean13: */
|
||||
if(accept == EAN13 && type != accept) goto eanwrongtype;
|
||||
if(accept != ANY && type != EAN13 && type != accept) goto eanwrongtype;
|
||||
switch(type) {
|
||||
if (accept == EAN13 && type != accept)
|
||||
goto eanwrongtype;
|
||||
if (accept != ANY && type != EAN13 && type != accept)
|
||||
goto eanwrongtype;
|
||||
switch (type)
|
||||
{
|
||||
case EAN13:
|
||||
valid = (valid && ((rcheck = checkdig(buf + 3, 13)) == check || magic));
|
||||
/* now get the subtype of EAN13: */
|
||||
if(buf[3] == '0') type = UPC;
|
||||
else if(!strncmp("977", buf+3, 3)) type = ISSN;
|
||||
else if(!strncmp("978", buf+3, 3)) type = ISBN;
|
||||
else if(!strncmp("9790", buf+3, 4)) type = ISMN;
|
||||
else if(!strncmp("979", buf+3, 3)) type = ISBN;
|
||||
if(accept != EAN13 && accept != ANY && type != accept) goto eanwrongtype;
|
||||
if (buf[3] == '0')
|
||||
type = UPC;
|
||||
else if (!strncmp("977", buf + 3, 3))
|
||||
type = ISSN;
|
||||
else if (!strncmp("978", buf + 3, 3))
|
||||
type = ISBN;
|
||||
else if (!strncmp("9790", buf + 3, 4))
|
||||
type = ISMN;
|
||||
else if (!strncmp("979", buf + 3, 3))
|
||||
type = ISBN;
|
||||
if (accept != EAN13 && accept != ANY && type != accept)
|
||||
goto eanwrongtype;
|
||||
break;
|
||||
case ISMN:
|
||||
strncpy(buf, "9790", 4); /* this isn't for sure yet, for now ISMN it's only 9790 */
|
||||
strncpy(buf, "9790", 4); /* this isn't for sure yet, for now
|
||||
* ISMN it's only 9790 */
|
||||
valid = (valid && ((rcheck = checkdig(buf + 3, 10)) == check || magic));
|
||||
break;
|
||||
case ISBN:
|
||||
|
@ -662,7 +844,8 @@ bool string2ean(const char *str, bool errorOK, ean13 *result,
|
|||
valid = (valid && ((rcheck = weight_checkdig(buf + 3, 10)) == check || magic));
|
||||
break;
|
||||
case ISSN:
|
||||
strncpy(buf+10, "00", 2); /* append 00 as the normal issue publication code */
|
||||
strncpy(buf + 10, "00", 2); /* append 00 as the normal issue
|
||||
* publication code */
|
||||
strncpy(buf, "977", 3);
|
||||
valid = (valid && ((rcheck = weight_checkdig(buf + 3, 8)) == check || magic));
|
||||
break;
|
||||
|
@ -678,27 +861,33 @@ bool string2ean(const char *str, bool errorOK, ean13 *result,
|
|||
aux1[12] = checkdig(aux1, 13) + '0';
|
||||
aux1[13] = '\0';
|
||||
|
||||
if(!valid && !magic) goto eanbadcheck;
|
||||
if (!valid && !magic)
|
||||
goto eanbadcheck;
|
||||
|
||||
*result = str2ean(aux1);
|
||||
*result |= valid ? 0 : 1;
|
||||
return true;
|
||||
|
||||
eanbadcheck:
|
||||
if(g_weak) { /* weak input mode is activated: */
|
||||
if (g_weak)
|
||||
{ /* weak input mode is activated: */
|
||||
/* set the "invalid-check-digit-on-input" flag */
|
||||
*result = str2ean(aux1);
|
||||
*result |= 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!errorOK) {
|
||||
if(rcheck == (unsigned)-1) {
|
||||
if (!errorOK)
|
||||
{
|
||||
if (rcheck == (unsigned) -1)
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||
errmsg("invalid %s number: \"%s\"",
|
||||
isn_names[accept], str)));
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||
errmsg("invalid check digit for %s number: \"%s\", should be %c",
|
||||
|
@ -736,7 +925,8 @@ eantoobig:
|
|||
* Exported routines.
|
||||
*---------------------------------------------------------*/
|
||||
|
||||
void initialize(void)
|
||||
void
|
||||
initialize(void)
|
||||
{
|
||||
#ifdef ISN_DEBUG
|
||||
if (!check_table(EAN13, EAN13_index))
|
||||
|
@ -987,6 +1177,7 @@ Datum
|
|||
is_valid(PG_FUNCTION_ARGS)
|
||||
{
|
||||
ean13 val = PG_GETARG_EAN13(0);
|
||||
|
||||
PG_RETURN_BOOL((val & 1) == 0);
|
||||
}
|
||||
|
||||
|
@ -997,6 +1188,7 @@ Datum
|
|||
make_valid(PG_FUNCTION_ARGS)
|
||||
{
|
||||
ean13 val = PG_GETARG_EAN13(0);
|
||||
|
||||
val &= ~((ean13) 1);
|
||||
PG_RETURN_EAN13(val);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* op function for ltree and lquery
|
||||
* Teodor Sigaev <teodor@stack.net>
|
||||
* $PostgreSQL: pgsql/contrib/ltree/lquery_op.c,v 1.10 2006/03/11 04:38:29 momjian Exp $
|
||||
* $PostgreSQL: pgsql/contrib/ltree/lquery_op.c,v 1.11 2006/10/04 00:29:45 momjian Exp $
|
||||
*/
|
||||
|
||||
#include "ltree.h"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $PostgreSQL: pgsql/contrib/ltree/ltree.h,v 1.16 2006/07/11 16:00:44 teodor Exp $ */
|
||||
/* $PostgreSQL: pgsql/contrib/ltree/ltree.h,v 1.17 2006/10/04 00:29:45 momjian Exp $ */
|
||||
|
||||
#ifndef __LTREE_H__
|
||||
#define __LTREE_H__
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* GiST support for ltree
|
||||
* Teodor Sigaev <teodor@stack.net>
|
||||
* $PostgreSQL: pgsql/contrib/ltree/ltree_gist.c,v 1.18 2006/08/08 15:45:18 teodor Exp $
|
||||
* $PostgreSQL: pgsql/contrib/ltree/ltree_gist.c,v 1.19 2006/10/04 00:29:45 momjian Exp $
|
||||
*/
|
||||
|
||||
#include "ltree.h"
|
||||
|
@ -457,8 +457,10 @@ gist_isparent(ltree_gist * key, ltree * query)
|
|||
}
|
||||
|
||||
static ltree *
|
||||
copy_ltree( ltree *src ) {
|
||||
copy_ltree(ltree * src)
|
||||
{
|
||||
ltree *dst = (ltree *) palloc(src->len);
|
||||
|
||||
memcpy(dst, src, src->len);
|
||||
return dst;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* op function for ltree
|
||||
* Teodor Sigaev <teodor@stack.net>
|
||||
* $PostgreSQL: pgsql/contrib/ltree/ltree_op.c,v 1.13 2006/09/20 19:50:21 tgl Exp $
|
||||
* $PostgreSQL: pgsql/contrib/ltree/ltree_op.c,v 1.14 2006/10/04 00:29:45 momjian Exp $
|
||||
*/
|
||||
|
||||
#include "ltree.h"
|
||||
|
@ -620,8 +620,8 @@ ltreeparentsel(PG_FUNCTION_ARGS)
|
|||
/*
|
||||
* If the histogram is large enough, see what fraction of it the
|
||||
* constant is "<@" to, and assume that's representative of the
|
||||
* non-MCV population. Otherwise use the default selectivity for
|
||||
* the non-MCV population.
|
||||
* non-MCV population. Otherwise use the default selectivity for the
|
||||
* non-MCV population.
|
||||
*/
|
||||
selec = histogram_selectivity(&vardata, &contproc,
|
||||
constval, varonleft,
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* pg_buffercache_pages.c
|
||||
* display some contents of the buffer cache
|
||||
*
|
||||
* $PostgreSQL: pgsql/contrib/pg_buffercache/pg_buffercache_pages.c,v 1.8 2006/07/23 03:07:57 tgl Exp $
|
||||
* $PostgreSQL: pgsql/contrib/pg_buffercache/pg_buffercache_pages.c,v 1.9 2006/10/04 00:29:45 momjian Exp $
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
@ -123,9 +123,9 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
|
|||
MemoryContextSwitchTo(oldcontext);
|
||||
|
||||
/*
|
||||
* To get a consistent picture of the buffer state, we must lock
|
||||
* all partitions of the buffer map. Needless to say, this is
|
||||
* horrible for concurrency...
|
||||
* To get a consistent picture of the buffer state, we must lock all
|
||||
* partitions of the buffer map. Needless to say, this is horrible
|
||||
* for concurrency...
|
||||
*/
|
||||
for (i = 0; i < NUM_BUFFER_PARTITIONS; i++)
|
||||
LWLockAcquire(FirstBufMappingLock + i, LW_SHARED);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* pg_freespacemap.c
|
||||
* display some contents of the free space relation and page maps.
|
||||
*
|
||||
* $PostgreSQL: pgsql/contrib/pg_freespacemap/pg_freespacemap.c,v 1.7 2006/09/21 20:31:21 tgl Exp $
|
||||
* $PostgreSQL: pgsql/contrib/pg_freespacemap/pg_freespacemap.c,v 1.8 2006/10/04 00:29:45 momjian Exp $
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
@ -138,8 +138,8 @@ pg_freespacemap_pages(PG_FUNCTION_ARGS)
|
|||
fctx->tupdesc = BlessTupleDesc(tupledesc);
|
||||
|
||||
/*
|
||||
* Allocate numPages worth of FreeSpacePagesRec records, this is
|
||||
* an upper bound.
|
||||
* Allocate numPages worth of FreeSpacePagesRec records, this is an
|
||||
* upper bound.
|
||||
*/
|
||||
fctx->record = (FreeSpacePagesRec *) palloc(sizeof(FreeSpacePagesRec) * numPages);
|
||||
|
||||
|
@ -147,8 +147,8 @@ pg_freespacemap_pages(PG_FUNCTION_ARGS)
|
|||
MemoryContextSwitchTo(oldcontext);
|
||||
|
||||
/*
|
||||
* Lock free space map and scan though all the relations.
|
||||
* For each relation, gets all its mapped pages.
|
||||
* Lock free space map and scan though all the relations. For each
|
||||
* relation, gets all its mapped pages.
|
||||
*/
|
||||
LWLockAcquire(FreeSpaceLock, LW_EXCLUSIVE);
|
||||
|
||||
|
@ -313,8 +313,8 @@ pg_freespacemap_relations(PG_FUNCTION_ARGS)
|
|||
fctx->tupdesc = BlessTupleDesc(tupledesc);
|
||||
|
||||
/*
|
||||
* Allocate numRelations worth of FreeSpaceRelationsRec records,
|
||||
* this is also an upper bound.
|
||||
* Allocate numRelations worth of FreeSpaceRelationsRec records, this
|
||||
* is also an upper bound.
|
||||
*/
|
||||
fctx->record = (FreeSpaceRelationsRec *) palloc(sizeof(FreeSpaceRelationsRec) * numRelations);
|
||||
|
||||
|
@ -368,6 +368,7 @@ pg_freespacemap_relations(PG_FUNCTION_ARGS)
|
|||
nulls[1] = false;
|
||||
values[2] = ObjectIdGetDatum(record->relfilenode);
|
||||
nulls[2] = false;
|
||||
|
||||
/*
|
||||
* avgrequest isn't meaningful for an index
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* $PostgreSQL: pgsql/contrib/pgbench/pgbench.c,v 1.55 2006/09/16 13:31:40 tgl Exp $
|
||||
* $PostgreSQL: pgsql/contrib/pgbench/pgbench.c,v 1.56 2006/10/04 00:29:45 momjian Exp $
|
||||
*
|
||||
* pgbench: a simple benchmark program for PostgreSQL
|
||||
* written by Tatsuo Ishii
|
||||
|
@ -1009,14 +1009,16 @@ process_file(char *filename)
|
|||
while (isspace((unsigned char) buf[i]))
|
||||
i++;
|
||||
|
||||
if (buf[i] != '\0' && strncmp(&buf[i], "--", 2) != 0) {
|
||||
if (buf[i] != '\0' && strncmp(&buf[i], "--", 2) != 0)
|
||||
{
|
||||
commands = process_commands(&buf[i]);
|
||||
if (commands == NULL)
|
||||
{
|
||||
fclose(fd);
|
||||
return false;
|
||||
}
|
||||
} else
|
||||
}
|
||||
else
|
||||
continue;
|
||||
|
||||
my_commands[lineno] = commands;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* Written by Solar Designer and placed in the public domain.
|
||||
* See crypt_blowfish.c for more information.
|
||||
*
|
||||
* $PostgreSQL: pgsql/contrib/pgcrypto/crypt-gensalt.c,v 1.9 2006/07/13 04:15:24 neilc Exp $
|
||||
* $PostgreSQL: pgsql/contrib/pgcrypto/crypt-gensalt.c,v 1.10 2006/10/04 00:29:46 momjian Exp $
|
||||
*
|
||||
* This file contains salt generation functions for the traditional and
|
||||
* other common crypt(3) algorithms, except for bcrypt which is defined
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
* $FreeBSD: src/lib/libcrypt/crypt-md5.c,v 1.5 1999/12/17 20:21:45 peter Exp $
|
||||
*
|
||||
* $PostgreSQL: pgsql/contrib/pgcrypto/crypt-md5.c,v 1.7 2006/07/13 04:15:24 neilc Exp $
|
||||
* $PostgreSQL: pgsql/contrib/pgcrypto/crypt-md5.c,v 1.8 2006/10/04 00:29:46 momjian Exp $
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $PostgreSQL: pgsql/contrib/pgcrypto/fortuna.c,v 1.7 2006/07/13 04:15:24 neilc Exp $
|
||||
* $PostgreSQL: pgsql/contrib/pgcrypto/fortuna.c,v 1.8 2006/10/04 00:29:46 momjian Exp $
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -26,7 +26,7 @@
|
|||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
/* $PostgreSQL: pgsql/contrib/pgcrypto/imath.h,v 1.4 2006/07/19 17:05:50 neilc Exp $ */
|
||||
/* $PostgreSQL: pgsql/contrib/pgcrypto/imath.h,v 1.5 2006/10/04 00:29:46 momjian Exp $ */
|
||||
|
||||
#ifndef IMATH_H_
|
||||
#define IMATH_H_
|
||||
|
@ -39,19 +39,23 @@
|
|||
typedef unsigned char mp_sign;
|
||||
typedef unsigned int mp_size;
|
||||
typedef int mp_result;
|
||||
|
||||
#ifdef USE_LONG_LONG
|
||||
typedef uint32 mp_digit;
|
||||
typedef uint64 mp_word;
|
||||
|
||||
#define MP_DIGIT_MAX 0xFFFFFFFFULL
|
||||
#define MP_WORD_MAX 0xFFFFFFFFFFFFFFFFULL
|
||||
#else
|
||||
typedef uint16 mp_digit;
|
||||
typedef uint32 mp_word;
|
||||
|
||||
#define MP_DIGIT_MAX 0xFFFFUL
|
||||
#define MP_WORD_MAX 0xFFFFFFFFUL
|
||||
#endif
|
||||
|
||||
typedef struct mpz {
|
||||
typedef struct mpz
|
||||
{
|
||||
mp_digit *digits;
|
||||
mp_size alloc;
|
||||
mp_size used;
|
||||
|
@ -111,13 +115,17 @@ mp_result mp_int_mul(mp_int a, mp_int b, mp_int c); /* c = a * b */
|
|||
mp_result mp_int_mul_value(mp_int a, int value, mp_int c);
|
||||
mp_result mp_int_mul_pow2(mp_int a, int p2, mp_int c);
|
||||
mp_result mp_int_sqr(mp_int a, mp_int c); /* c = a * a */
|
||||
mp_result mp_int_div(mp_int a, mp_int b, /* q = a / b */
|
||||
mp_result
|
||||
mp_int_div(mp_int a, mp_int b, /* q = a / b */
|
||||
mp_int q, mp_int r); /* r = a % b */
|
||||
mp_result mp_int_div_value(mp_int a, int value, /* q = a / value */
|
||||
mp_result
|
||||
mp_int_div_value(mp_int a, int value, /* q = a / value */
|
||||
mp_int q, int *r); /* r = a % value */
|
||||
mp_result mp_int_div_pow2(mp_int a, int p2, /* q = a / 2^p2 */
|
||||
mp_result
|
||||
mp_int_div_pow2(mp_int a, int p2, /* q = a / 2^p2 */
|
||||
mp_int q, mp_int r); /* r = q % 2^p2 */
|
||||
mp_result mp_int_mod(mp_int a, mp_int m, mp_int c); /* c = a % m */
|
||||
|
||||
#define mp_int_mod_value(A, V, R) mp_int_div_value((A), (V), 0, (R))
|
||||
mp_result mp_int_expt(mp_int a, int b, mp_int c); /* c = a^b */
|
||||
mp_result mp_int_expt_value(int a, int b, mp_int c); /* c = a^b */
|
||||
|
@ -133,13 +141,17 @@ int mp_int_divisible_value(mp_int a, int v);
|
|||
/* Returns k >= 0 such that z = 2^k, if one exists; otherwise < 0 */
|
||||
int mp_int_is_pow2(mp_int z);
|
||||
|
||||
mp_result mp_int_exptmod(mp_int a, mp_int b, mp_int m,
|
||||
mp_result
|
||||
mp_int_exptmod(mp_int a, mp_int b, mp_int m,
|
||||
mp_int c); /* c = a^b (mod m) */
|
||||
mp_result mp_int_exptmod_evalue(mp_int a, int value,
|
||||
mp_result
|
||||
mp_int_exptmod_evalue(mp_int a, int value,
|
||||
mp_int m, mp_int c); /* c = a^v (mod m) */
|
||||
mp_result mp_int_exptmod_bvalue(int value, mp_int b,
|
||||
mp_result
|
||||
mp_int_exptmod_bvalue(int value, mp_int b,
|
||||
mp_int m, mp_int c); /* c = v^b (mod m) */
|
||||
mp_result mp_int_exptmod_known(mp_int a, mp_int b,
|
||||
mp_result
|
||||
mp_int_exptmod_known(mp_int a, mp_int b,
|
||||
mp_int m, mp_int mu,
|
||||
mp_int c); /* c = a^b (mod m) */
|
||||
mp_result mp_int_redux_const(mp_int m, mp_int c);
|
||||
|
@ -148,7 +160,8 @@ mp_result mp_int_invmod(mp_int a, mp_int m, mp_int c); /* c = 1/a (mod m) */
|
|||
|
||||
mp_result mp_int_gcd(mp_int a, mp_int b, mp_int c); /* c = gcd(a, b) */
|
||||
|
||||
mp_result mp_int_egcd(mp_int a, mp_int b, mp_int c, /* c = gcd(a, b) */
|
||||
mp_result
|
||||
mp_int_egcd(mp_int a, mp_int b, mp_int c, /* c = gcd(a, b) */
|
||||
mp_int x, mp_int y); /* c = ax + by */
|
||||
|
||||
mp_result mp_int_sqrt(mp_int a, mp_int c); /* c = floor(sqrt(q)) */
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $PostgreSQL: pgsql/contrib/pgcrypto/internal-sha2.c,v 1.1 2006/07/13 04:15:24 neilc Exp $
|
||||
* $PostgreSQL: pgsql/contrib/pgcrypto/internal-sha2.c,v 1.2 2006/10/04 00:29:46 momjian Exp $
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
@ -314,4 +314,3 @@ init_sha512(PX_MD * md)
|
|||
|
||||
md->reset(md);
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $PostgreSQL: pgsql/contrib/pgcrypto/internal.c,v 1.24 2006/07/13 04:15:24 neilc Exp $
|
||||
* $PostgreSQL: pgsql/contrib/pgcrypto/internal.c,v 1.25 2006/10/04 00:29:46 momjian Exp $
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $PostgreSQL: pgsql/contrib/pgcrypto/openssl.c,v 1.29 2006/09/05 23:02:28 tgl Exp $
|
||||
* $PostgreSQL: pgsql/contrib/pgcrypto/openssl.c,v 1.30 2006/10/04 00:29:46 momjian Exp $
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
@ -58,7 +58,6 @@
|
|||
*/
|
||||
|
||||
#include <openssl/aes.h>
|
||||
|
||||
#else /* old OPENSSL */
|
||||
|
||||
/*
|
||||
|
@ -121,29 +120,32 @@
|
|||
* Emulate newer digest API.
|
||||
*/
|
||||
|
||||
static void EVP_MD_CTX_init(EVP_MD_CTX *ctx)
|
||||
static void
|
||||
EVP_MD_CTX_init(EVP_MD_CTX *ctx)
|
||||
{
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
}
|
||||
|
||||
static int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx)
|
||||
static int
|
||||
EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx)
|
||||
{
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *md, void *engine)
|
||||
static int
|
||||
EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *md, void *engine)
|
||||
{
|
||||
EVP_DigestInit(ctx, md);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *res, unsigned int *len)
|
||||
static int
|
||||
EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *res, unsigned int *len)
|
||||
{
|
||||
EVP_DigestFinal(ctx, res, len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* old OpenSSL */
|
||||
|
||||
/*
|
||||
|
@ -156,7 +158,8 @@ static int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *res, unsigned int
|
|||
|
||||
typedef void (*init_f) (PX_MD * md);
|
||||
|
||||
static int compat_find_digest(const char *name, PX_MD **res)
|
||||
static int
|
||||
compat_find_digest(const char *name, PX_MD ** res)
|
||||
{
|
||||
init_f init = NULL;
|
||||
|
||||
|
@ -175,7 +178,6 @@ static int compat_find_digest(const char *name, PX_MD **res)
|
|||
init(*res);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
#define compat_find_digest(name, res) (PXE_NO_HASH)
|
||||
#endif
|
||||
|
@ -184,7 +186,8 @@ static int compat_find_digest(const char *name, PX_MD **res)
|
|||
* Hashes
|
||||
*/
|
||||
|
||||
typedef struct OSSLDigest {
|
||||
typedef struct OSSLDigest
|
||||
{
|
||||
const EVP_MD *algo;
|
||||
EVP_MD_CTX ctx;
|
||||
} OSSLDigest;
|
||||
|
@ -193,6 +196,7 @@ static unsigned
|
|||
digest_result_size(PX_MD * h)
|
||||
{
|
||||
OSSLDigest *digest = (OSSLDigest *) h->p.ptr;
|
||||
|
||||
return EVP_MD_CTX_size(&digest->ctx);
|
||||
}
|
||||
|
||||
|
@ -200,6 +204,7 @@ static unsigned
|
|||
digest_block_size(PX_MD * h)
|
||||
{
|
||||
OSSLDigest *digest = (OSSLDigest *) h->p.ptr;
|
||||
|
||||
return EVP_MD_CTX_block_size(&digest->ctx);
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $PostgreSQL: pgsql/contrib/pgcrypto/pgcrypto.c,v 1.23 2006/09/05 21:26:48 tgl Exp $
|
||||
* $PostgreSQL: pgsql/contrib/pgcrypto/pgcrypto.c,v 1.24 2006/10/04 00:29:46 momjian Exp $
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-mpi-internal.c,v 1.6 2006/07/13 04:52:51 neilc Exp $
|
||||
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-mpi-internal.c,v 1.7 2006/10/04 00:29:46 momjian Exp $
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
|
@ -36,14 +36,17 @@
|
|||
#include "mbuf.h"
|
||||
#include "pgp.h"
|
||||
|
||||
static mpz_t *mp_new()
|
||||
static mpz_t *
|
||||
mp_new()
|
||||
{
|
||||
mpz_t *mp = mp_int_alloc();
|
||||
|
||||
mp_int_init_size(mp, 256);
|
||||
return mp;
|
||||
}
|
||||
|
||||
static void mp_clear_free(mpz_t *a)
|
||||
static void
|
||||
mp_clear_free(mpz_t * a)
|
||||
{
|
||||
if (!a)
|
||||
return;
|
||||
|
@ -52,7 +55,8 @@ static void mp_clear_free(mpz_t *a)
|
|||
}
|
||||
|
||||
|
||||
static int mp_px_rand(uint32 bits, mpz_t *res)
|
||||
static int
|
||||
mp_px_rand(uint32 bits, mpz_t * res)
|
||||
{
|
||||
int err;
|
||||
unsigned bytes = (bits + 7) / 8;
|
||||
|
@ -61,16 +65,19 @@ static int mp_px_rand(uint32 bits, mpz_t *res)
|
|||
|
||||
buf = px_alloc(bytes);
|
||||
err = px_get_random_bytes(buf, bytes);
|
||||
if (err < 0) {
|
||||
if (err < 0)
|
||||
{
|
||||
px_free(buf);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* clear unnecessary bits and set last bit to one */
|
||||
if (last_bits) {
|
||||
if (last_bits)
|
||||
{
|
||||
buf[0] >>= 8 - last_bits;
|
||||
buf[0] |= 1 << (last_bits - 1);
|
||||
} else
|
||||
}
|
||||
else
|
||||
buf[0] |= 1 << 7;
|
||||
|
||||
mp_int_read_unsigned(res, buf, bytes);
|
||||
|
@ -80,9 +87,11 @@ static int mp_px_rand(uint32 bits, mpz_t *res)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void mp_modmul(mpz_t *a, mpz_t *b, mpz_t *p, mpz_t *res)
|
||||
static void
|
||||
mp_modmul(mpz_t * a, mpz_t * b, mpz_t * p, mpz_t * res)
|
||||
{
|
||||
mpz_t *tmp = mp_new();
|
||||
|
||||
mp_int_mul(a, b, tmp);
|
||||
mp_int_mod(tmp, p, res);
|
||||
mp_clear_free(tmp);
|
||||
|
@ -92,6 +101,7 @@ static mpz_t *
|
|||
mpi_to_bn(PGP_MPI * n)
|
||||
{
|
||||
mpz_t *bn = mp_new();
|
||||
|
||||
mp_int_read_unsigned(bn, n->data, n->bytes);
|
||||
|
||||
if (!bn)
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
*
|
||||
* $From: sha2.c,v 1.1 2001/11/08 00:01:51 adg Exp adg $
|
||||
*
|
||||
* $PostgreSQL: pgsql/contrib/pgcrypto/sha2.c,v 1.7 2006/07/13 04:15:25 neilc Exp $
|
||||
* $PostgreSQL: pgsql/contrib/pgcrypto/sha2.c,v 1.8 2006/10/04 00:29:46 momjian Exp $
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
@ -1023,4 +1023,3 @@ SHA224_Final(uint8 digest[], SHA224_CTX * context)
|
|||
/* Clean up state data: */
|
||||
memset(context, 0, sizeof(*context));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* $PostgreSQL: pgsql/contrib/pgrowlocks/pgrowlocks.c,v 1.4 2006/07/13 16:57:31 momjian Exp $
|
||||
* $PostgreSQL: pgsql/contrib/pgrowlocks/pgrowlocks.c,v 1.5 2006/10/04 00:29:46 momjian Exp $
|
||||
*
|
||||
* Copyright (c) 2005-2006 Tatsuo Ishii
|
||||
*
|
||||
|
@ -63,7 +63,8 @@ extern Datum pgrowlocks(PG_FUNCTION_ARGS);
|
|||
*/
|
||||
#undef MAKERANGEVARFROMNAMELIST_HAS_TWO_ARGS
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
Relation rel;
|
||||
HeapScanDesc scan;
|
||||
int ncolumns;
|
||||
|
@ -97,7 +98,6 @@ pgrowlocks(PG_FUNCTION_ARGS)
|
|||
relname = PG_GETARG_TEXT_P(0);
|
||||
#ifdef MAKERANGEVARFROMNAMELIST_HAS_TWO_ARGS
|
||||
relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname, "pgrowlocks"));
|
||||
|
||||
#else
|
||||
relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
|
||||
#endif
|
||||
|
@ -198,7 +198,6 @@ pgrowlocks(PG_FUNCTION_ARGS)
|
|||
values[i] = palloc(NCHARS * sizeof(char));
|
||||
snprintf(values[i++], NCHARS, "{%d}", BackendXidGetPid(HeapTupleHeaderGetXmax(tuple->t_data)));
|
||||
}
|
||||
|
||||
#else
|
||||
values[i++] = pstrdup("false");
|
||||
values[i++] = pstrdup("{}");
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* $PostgreSQL: pgsql/contrib/pgstattuple/pgstattuple.c,v 1.24 2006/09/04 02:03:04 tgl Exp $
|
||||
* $PostgreSQL: pgsql/contrib/pgstattuple/pgstattuple.c,v 1.25 2006/10/04 00:29:46 momjian Exp $
|
||||
*
|
||||
* Copyright (c) 2001,2002 Tatsuo Ishii
|
||||
*
|
||||
|
@ -329,6 +329,7 @@ pgstat_btree_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno)
|
|||
else
|
||||
{
|
||||
BTPageOpaque opaque;
|
||||
|
||||
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||
if (opaque->btpo_flags & (BTP_DELETED | BTP_HALF_DEAD))
|
||||
{
|
||||
|
@ -365,6 +366,7 @@ pgstat_hash_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno)
|
|||
if (PageGetSpecialSize(page) == MAXALIGN(sizeof(HashPageOpaqueData)))
|
||||
{
|
||||
HashPageOpaque opaque;
|
||||
|
||||
opaque = (HashPageOpaque) PageGetSpecialPointer(page);
|
||||
switch (opaque->hasho_flag)
|
||||
{
|
||||
|
@ -441,6 +443,7 @@ pgstat_index(Relation rel, BlockNumber start, pgstat_page pagefn,
|
|||
if (blkno >= nblocks)
|
||||
{
|
||||
stat.table_len = (uint64) nblocks *BLCKSZ;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* Written by Victor B. Wagner <vitus@cryptocom.ru>, Cryptocom LTD
|
||||
* This file is distributed under BSD-style license.
|
||||
*
|
||||
* $PostgreSQL: pgsql/contrib/sslinfo/sslinfo.c,v 1.4 2006/09/30 18:44:37 tgl Exp $
|
||||
* $PostgreSQL: pgsql/contrib/sslinfo/sslinfo.c,v 1.5 2006/10/04 00:29:46 momjian Exp $
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
@ -41,7 +41,8 @@ Datum ASN1_STRING_to_text(ASN1_STRING *str);
|
|||
* is SSL session and false if it is local or non-ssl session.
|
||||
*/
|
||||
PG_FUNCTION_INFO_V1(ssl_is_used);
|
||||
Datum ssl_is_used(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
ssl_is_used(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_BOOL(MyProcPort->ssl != NULL);
|
||||
}
|
||||
|
@ -54,7 +55,8 @@ Datum ssl_is_used(PG_FUNCTION_ARGS)
|
|||
* is SSL session and client certificate is verified, otherwise false.
|
||||
*/
|
||||
PG_FUNCTION_INFO_V1(ssl_client_cert_present);
|
||||
Datum ssl_client_cert_present(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
ssl_client_cert_present(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_BOOL(MyProcPort->peer != NULL);
|
||||
}
|
||||
|
@ -69,7 +71,8 @@ Datum ssl_client_cert_present(PG_FUNCTION_ARGS)
|
|||
* SSL connection is established without sending client certificate.
|
||||
*/
|
||||
PG_FUNCTION_INFO_V1(ssl_client_serial);
|
||||
Datum ssl_client_serial(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
ssl_client_serial(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum result;
|
||||
Port *port = MyProcPort;
|
||||
|
@ -83,6 +86,7 @@ Datum ssl_client_serial(PG_FUNCTION_ARGS)
|
|||
serial = X509_get_serialNumber(peer);
|
||||
b = ASN1_INTEGER_to_BN(serial, NULL);
|
||||
decimal = BN_bn2dec(b);
|
||||
|
||||
BN_free(b);
|
||||
result = DirectFunctionCall3(numeric_in,
|
||||
CStringGetDatum(decimal),
|
||||
|
@ -106,10 +110,12 @@ Datum ssl_client_serial(PG_FUNCTION_ARGS)
|
|||
* Returns Datum, which can be directly returned from a C language SQL
|
||||
* function.
|
||||
*/
|
||||
Datum ASN1_STRING_to_text(ASN1_STRING *str)
|
||||
Datum
|
||||
ASN1_STRING_to_text(ASN1_STRING *str)
|
||||
{
|
||||
BIO *membuf = NULL;
|
||||
size_t size, outlen;
|
||||
size_t size,
|
||||
outlen;
|
||||
char *sp;
|
||||
char *dp;
|
||||
text *result;
|
||||
|
@ -151,13 +157,16 @@ Datum ASN1_STRING_to_text(ASN1_STRING *str)
|
|||
* Returns result of ASN1_STRING_to_text applied to appropriate
|
||||
* part of name
|
||||
*/
|
||||
Datum X509_NAME_field_to_text(X509_NAME *name, text *fieldName)
|
||||
Datum
|
||||
X509_NAME_field_to_text(X509_NAME *name, text *fieldName)
|
||||
{
|
||||
char *sp;
|
||||
char *string_fieldname;
|
||||
char *dp;
|
||||
size_t name_len = VARSIZE(fieldName) - VARHDRSZ;
|
||||
int nid, index, i;
|
||||
int nid,
|
||||
index,
|
||||
i;
|
||||
ASN1_STRING *data;
|
||||
|
||||
string_fieldname = palloc(name_len + 1);
|
||||
|
@ -198,7 +207,8 @@ Datum X509_NAME_field_to_text(X509_NAME *name, text *fieldName)
|
|||
* there is no field with such name in the certificate.
|
||||
*/
|
||||
PG_FUNCTION_INFO_V1(ssl_client_dn_field);
|
||||
Datum ssl_client_dn_field(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
ssl_client_dn_field(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *fieldname = PG_GETARG_TEXT_P(0);
|
||||
Datum result;
|
||||
|
@ -232,7 +242,8 @@ Datum ssl_client_dn_field(PG_FUNCTION_ARGS)
|
|||
* there is no field with such name in the certificate.
|
||||
*/
|
||||
PG_FUNCTION_INFO_V1(ssl_issuer_field);
|
||||
Datum ssl_issuer_field(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
ssl_issuer_field(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *fieldname = PG_GETARG_TEXT_P(0);
|
||||
Datum result;
|
||||
|
@ -260,15 +271,19 @@ Datum ssl_issuer_field(PG_FUNCTION_ARGS)
|
|||
* Returns: text datum which contains string representation of
|
||||
* X509_NAME
|
||||
*/
|
||||
Datum X509_NAME_to_text(X509_NAME *name)
|
||||
Datum
|
||||
X509_NAME_to_text(X509_NAME *name)
|
||||
{
|
||||
BIO *membuf = BIO_new(BIO_s_mem());
|
||||
int i,nid,count = X509_NAME_entry_count(name);
|
||||
int i,
|
||||
nid,
|
||||
count = X509_NAME_entry_count(name);
|
||||
X509_NAME_ENTRY *e;
|
||||
ASN1_STRING *v;
|
||||
|
||||
const char *field_name;
|
||||
size_t size,outlen;
|
||||
size_t size,
|
||||
outlen;
|
||||
char *sp;
|
||||
char *dp;
|
||||
text *result;
|
||||
|
@ -301,8 +316,10 @@ Datum X509_NAME_to_text(X509_NAME *name)
|
|||
result = palloc(VARHDRSZ + outlen);
|
||||
memcpy(VARDATA(result), dp, outlen);
|
||||
|
||||
/* pg_do_encoding_conversion has annoying habit of returning
|
||||
* source pointer */
|
||||
/*
|
||||
* pg_do_encoding_conversion has annoying habit of returning source
|
||||
* pointer
|
||||
*/
|
||||
if (dp != sp)
|
||||
pfree(dp);
|
||||
VARATT_SIZEP(result) = outlen + VARHDRSZ;
|
||||
|
@ -320,7 +337,8 @@ Datum X509_NAME_to_text(X509_NAME *name)
|
|||
* Returns text datum.
|
||||
*/
|
||||
PG_FUNCTION_INFO_V1(ssl_client_dn);
|
||||
Datum ssl_client_dn(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
ssl_client_dn(PG_FUNCTION_ARGS)
|
||||
{
|
||||
if (!(MyProcPort->peer))
|
||||
PG_RETURN_NULL();
|
||||
|
@ -338,7 +356,8 @@ Datum ssl_client_dn(PG_FUNCTION_ARGS)
|
|||
* Returns text datum.
|
||||
*/
|
||||
PG_FUNCTION_INFO_V1(ssl_issuer_dn);
|
||||
Datum ssl_issuer_dn(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
ssl_issuer_dn(PG_FUNCTION_ARGS)
|
||||
{
|
||||
if (!(MyProcPort->peer))
|
||||
PG_RETURN_NULL();
|
||||
|
|
|
@ -166,10 +166,13 @@ get_oidnamespace(Oid funcoid)
|
|||
|
||||
/* if path is relative, take it as relative to share dir */
|
||||
char *
|
||||
to_absfilename(char *filename) {
|
||||
if (!is_absolute_path(filename)) {
|
||||
to_absfilename(char *filename)
|
||||
{
|
||||
if (!is_absolute_path(filename))
|
||||
{
|
||||
char sharepath[MAXPGPATH];
|
||||
char *absfn;
|
||||
|
||||
#ifdef WIN32
|
||||
char delim = '\\';
|
||||
#else
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $PostgreSQL: pgsql/contrib/tsearch2/dict.c,v 1.12 2006/05/31 14:05:31 teodor Exp $ */
|
||||
/* $PostgreSQL: pgsql/contrib/tsearch2/dict.c,v 1.13 2006/10/04 00:29:46 momjian Exp $ */
|
||||
|
||||
/*
|
||||
* interface functions to dictionary
|
||||
|
@ -102,7 +102,8 @@ comparedict(const void *a, const void *b)
|
|||
}
|
||||
|
||||
static void
|
||||
insertdict(Oid id) {
|
||||
insertdict(Oid id)
|
||||
{
|
||||
DictInfo newdict;
|
||||
|
||||
if (DList.len == DList.reallen)
|
||||
|
@ -215,7 +216,8 @@ lexize(PG_FUNCTION_ARGS)
|
|||
)
|
||||
);
|
||||
|
||||
if (dstate.getnext) {
|
||||
if (dstate.getnext)
|
||||
{
|
||||
dstate.isend = true;
|
||||
ptr = res = (TSLexeme *) DatumGetPointer(
|
||||
FunctionCall4(&(dict->lexize_info),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $PostgreSQL: pgsql/contrib/tsearch2/dict.h,v 1.7 2006/05/31 14:05:31 teodor Exp $ */
|
||||
/* $PostgreSQL: pgsql/contrib/tsearch2/dict.h,v 1.8 2006/10/04 00:29:46 momjian Exp $ */
|
||||
|
||||
#ifndef __DICT_H__
|
||||
#define __DICT_H__
|
||||
|
@ -30,10 +30,13 @@ DictInfo *finddict(Oid id);
|
|||
Oid name2id_dict(text *name);
|
||||
void reset_dict(void);
|
||||
|
||||
typedef struct {
|
||||
bool isend; /* in: marks for lexize_info about text end is reached */
|
||||
typedef struct
|
||||
{
|
||||
bool isend; /* in: marks for lexize_info about text end is
|
||||
* reached */
|
||||
bool getnext; /* out: dict wants next lexeme */
|
||||
void *private; /* internal dict state between calls with getnext == true */
|
||||
void *private; /* internal dict state between calls with
|
||||
* getnext == true */
|
||||
} DictSubState;
|
||||
|
||||
/* simple parser of cfg string */
|
||||
|
@ -51,13 +54,8 @@ typedef struct
|
|||
/*
|
||||
* number of variant of split word , for example Word 'fotballklubber'
|
||||
* (norwegian) has two varian to split: ( fotball, klubb ) and ( fot,
|
||||
* ball, klubb ). So, dictionary should return:
|
||||
* nvariant lexeme
|
||||
* 1 fotball
|
||||
* 1 klubb
|
||||
* 2 fot
|
||||
* 2 ball
|
||||
* 2 klubb
|
||||
* ball, klubb ). So, dictionary should return: nvariant lexeme 1
|
||||
* fotball 1 klubb 2 fot 2 ball 2 klubb
|
||||
*/
|
||||
uint16 nvariant;
|
||||
|
||||
|
@ -74,7 +72,8 @@ typedef struct
|
|||
* Lexize subsystem
|
||||
*/
|
||||
|
||||
typedef struct ParsedLex {
|
||||
typedef struct ParsedLex
|
||||
{
|
||||
int type;
|
||||
char *lemm;
|
||||
int lenlemm;
|
||||
|
@ -82,12 +81,14 @@ typedef struct ParsedLex {
|
|||
struct ParsedLex *next;
|
||||
} ParsedLex;
|
||||
|
||||
typedef struct ListParsedLex {
|
||||
typedef struct ListParsedLex
|
||||
{
|
||||
ParsedLex *head;
|
||||
ParsedLex *tail;
|
||||
} ListParsedLex;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
TSCfgInfo *cfg;
|
||||
Oid curDictId;
|
||||
int posDict;
|
||||
|
@ -96,8 +97,10 @@ typedef struct {
|
|||
ListParsedLex towork; /* current list to work */
|
||||
ListParsedLex waste; /* list of lexemes that already lexized */
|
||||
|
||||
/* fields to store last variant to lexize (basically, thesaurus
|
||||
or similar to, which wants several lexemes */
|
||||
/*
|
||||
* fields to store last variant to lexize (basically, thesaurus or similar
|
||||
* to, which wants several lexemes
|
||||
*/
|
||||
|
||||
ParsedLex *lastRes;
|
||||
TSLexeme *tmpRes;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $PostgreSQL: pgsql/contrib/tsearch2/dict_thesaurus.c,v 1.5 2006/06/06 16:25:55 teodor Exp $ */
|
||||
/* $PostgreSQL: pgsql/contrib/tsearch2/dict_thesaurus.c,v 1.6 2006/10/04 00:29:46 momjian Exp $ */
|
||||
|
||||
/*
|
||||
* thesaurus
|
||||
|
@ -18,7 +18,8 @@
|
|||
*/
|
||||
#define DT_USEASIS 0x1000
|
||||
|
||||
typedef struct LexemeInfo {
|
||||
typedef struct LexemeInfo
|
||||
{
|
||||
uint16 idsubst; /* entry's number in DictThesaurus->subst */
|
||||
uint16 posinsubst; /* pos info in entry */
|
||||
uint16 tnvariant; /* total num lexemes in one variant */
|
||||
|
@ -26,12 +27,14 @@ typedef struct LexemeInfo {
|
|||
struct LexemeInfo *nextvariant;
|
||||
} LexemeInfo;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
char *lexeme;
|
||||
LexemeInfo *entries;
|
||||
} TheLexeme;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
uint16 lastlexeme; /* number lexemes to substitute */
|
||||
uint16 reslen;
|
||||
TSLexeme *res; /* prepared substituted result */
|
||||
|
@ -47,8 +50,9 @@ typedef struct
|
|||
int nwrds;
|
||||
int ntwrds;
|
||||
|
||||
/* Storage of substituted result, n-th element is for
|
||||
n-th expression */
|
||||
/*
|
||||
* Storage of substituted result, n-th element is for n-th expression
|
||||
*/
|
||||
TheSubstitute *subst;
|
||||
int nsubst;
|
||||
} DictThesaurus;
|
||||
|
@ -66,14 +70,19 @@ freeDictThesaurus(DictThesaurus * d)
|
|||
}
|
||||
|
||||
static void
|
||||
newLexeme( DictThesaurus *d, char *b, char *e, uint16 idsubst, uint16 posinsubst ) {
|
||||
newLexeme(DictThesaurus * d, char *b, char *e, uint16 idsubst, uint16 posinsubst)
|
||||
{
|
||||
TheLexeme *ptr;
|
||||
|
||||
if ( d->nwrds >= d->ntwrds ) {
|
||||
if ( d->ntwrds == 0 ) {
|
||||
if (d->nwrds >= d->ntwrds)
|
||||
{
|
||||
if (d->ntwrds == 0)
|
||||
{
|
||||
d->ntwrds = 16;
|
||||
d->wrds = (TheLexeme *) malloc(sizeof(TheLexeme) * d->ntwrds);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
d->ntwrds *= 2;
|
||||
d->wrds = (TheLexeme *) realloc(d->wrds, sizeof(TheLexeme) * d->ntwrds);
|
||||
}
|
||||
|
@ -99,19 +108,25 @@ newLexeme( DictThesaurus *d, char *b, char *e, uint16 idsubst, uint16 posinsubst
|
|||
}
|
||||
|
||||
static void
|
||||
addWrd( DictThesaurus *d, char *b, char *e, uint16 idsubst, uint16 nwrd, uint16 posinsubst, bool useasis ) {
|
||||
addWrd(DictThesaurus * d, char *b, char *e, uint16 idsubst, uint16 nwrd, uint16 posinsubst, bool useasis)
|
||||
{
|
||||
static int nres = 0;
|
||||
static int ntres = 0;
|
||||
TheSubstitute *ptr;
|
||||
|
||||
if ( nwrd == 0 ) {
|
||||
if (nwrd == 0)
|
||||
{
|
||||
nres = ntres = 0;
|
||||
|
||||
if ( idsubst <= d->nsubst ) {
|
||||
if ( d->nsubst == 0 ) {
|
||||
if (idsubst <= d->nsubst)
|
||||
{
|
||||
if (d->nsubst == 0)
|
||||
{
|
||||
d->nsubst = 16;
|
||||
d->subst = (TheSubstitute *) malloc(sizeof(TheSubstitute) * d->nsubst);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
d->nsubst *= 2;
|
||||
d->subst = (TheSubstitute *) realloc(d->subst, sizeof(TheSubstitute) * d->nsubst);
|
||||
}
|
||||
|
@ -124,11 +139,15 @@ addWrd( DictThesaurus *d, char *b, char *e, uint16 idsubst, uint16 nwrd, uint16
|
|||
|
||||
ptr->lastlexeme = posinsubst - 1;
|
||||
|
||||
if ( nres+1 >= ntres ) {
|
||||
if ( ntres == 0 ) {
|
||||
if (nres + 1 >= ntres)
|
||||
{
|
||||
if (ntres == 0)
|
||||
{
|
||||
ntres = 2;
|
||||
ptr->res = (TSLexeme *) malloc(sizeof(TSLexeme) * ntres);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ntres *= 2;
|
||||
ptr->res = (TSLexeme *) realloc(ptr->res, sizeof(TSLexeme) * ntres);
|
||||
}
|
||||
|
@ -157,7 +176,8 @@ addWrd( DictThesaurus *d, char *b, char *e, uint16 idsubst, uint16 nwrd, uint16
|
|||
#define TR_INSUBS 4
|
||||
|
||||
static void
|
||||
thesaurusRead( char *filename, DictThesaurus *d ) {
|
||||
thesaurusRead(char *filename, DictThesaurus * d)
|
||||
{
|
||||
FILE *fh;
|
||||
char str[BUFSIZ];
|
||||
int lineno = 0;
|
||||
|
@ -168,7 +188,8 @@ thesaurusRead( char *filename, DictThesaurus *d ) {
|
|||
if (!fh)
|
||||
elog(ERROR, "Thesaurus: can't open '%s' file", filename);
|
||||
|
||||
while( fgets(str, sizeof(str), fh)) {
|
||||
while (fgets(str, sizeof(str), fh))
|
||||
{
|
||||
char *ptr = str;
|
||||
int state = TR_WAITLEX;
|
||||
char *beginwrd = NULL;
|
||||
|
@ -184,54 +205,77 @@ thesaurusRead( char *filename, DictThesaurus *d ) {
|
|||
continue;
|
||||
|
||||
pg_verifymbstr(ptr, strlen(ptr), false);
|
||||
while(*ptr) {
|
||||
if ( state == TR_WAITLEX ) {
|
||||
if ( t_iseq(ptr, ':' ) ) {
|
||||
if ( posinsubst == 0 ) {
|
||||
while (*ptr)
|
||||
{
|
||||
if (state == TR_WAITLEX)
|
||||
{
|
||||
if (t_iseq(ptr, ':'))
|
||||
{
|
||||
if (posinsubst == 0)
|
||||
{
|
||||
fclose(fh);
|
||||
elog(ERROR, "Thesaurus: Unexpected delimiter at %d line", lineno);
|
||||
}
|
||||
state = TR_WAITSUBS;
|
||||
} else if ( !t_isspace(ptr) ) {
|
||||
}
|
||||
else if (!t_isspace(ptr))
|
||||
{
|
||||
beginwrd = ptr;
|
||||
state = TR_INLEX;
|
||||
}
|
||||
} else if ( state == TR_INLEX ) {
|
||||
if ( t_iseq(ptr, ':') ) {
|
||||
}
|
||||
else if (state == TR_INLEX)
|
||||
{
|
||||
if (t_iseq(ptr, ':'))
|
||||
{
|
||||
newLexeme(d, beginwrd, ptr, idsubst, posinsubst++);
|
||||
state = TR_WAITSUBS;
|
||||
} else if ( t_isspace(ptr) ) {
|
||||
}
|
||||
else if (t_isspace(ptr))
|
||||
{
|
||||
newLexeme(d, beginwrd, ptr, idsubst, posinsubst++);
|
||||
state = TR_WAITLEX;
|
||||
}
|
||||
} else if ( state == TR_WAITSUBS ) {
|
||||
if ( t_iseq(ptr, '*') ) {
|
||||
}
|
||||
else if (state == TR_WAITSUBS)
|
||||
{
|
||||
if (t_iseq(ptr, '*'))
|
||||
{
|
||||
useasis = true;
|
||||
state = TR_INSUBS;
|
||||
beginwrd = ptr + pg_mblen(ptr);
|
||||
} else if ( t_iseq(ptr, '\\') ) {
|
||||
}
|
||||
else if (t_iseq(ptr, '\\'))
|
||||
{
|
||||
useasis = false;
|
||||
state = TR_INSUBS;
|
||||
beginwrd = ptr + pg_mblen(ptr);
|
||||
} else if ( !t_isspace(ptr) ) {
|
||||
}
|
||||
else if (!t_isspace(ptr))
|
||||
{
|
||||
useasis = false;
|
||||
beginwrd = ptr;
|
||||
state = TR_INSUBS;
|
||||
}
|
||||
} else if ( state == TR_INSUBS ) {
|
||||
if ( t_isspace(ptr) ) {
|
||||
}
|
||||
else if (state == TR_INSUBS)
|
||||
{
|
||||
if (t_isspace(ptr))
|
||||
{
|
||||
if (ptr == beginwrd)
|
||||
elog(ERROR, "Thesaurus: Unexpected end of line or lexeme at %d line", lineno);
|
||||
addWrd(d, beginwrd, ptr, idsubst, nwrd++, posinsubst, useasis);
|
||||
state = TR_WAITSUBS;
|
||||
}
|
||||
} else
|
||||
}
|
||||
else
|
||||
elog(ERROR, "Thesaurus: Unknown state: %d", state);
|
||||
|
||||
ptr += pg_mblen(ptr);
|
||||
}
|
||||
|
||||
if ( state == TR_INSUBS ) {
|
||||
if (state == TR_INSUBS)
|
||||
{
|
||||
if (ptr == beginwrd)
|
||||
elog(ERROR, "Thesaurus: Unexpected end of line or lexeme at %d line", lineno);
|
||||
addWrd(d, beginwrd, ptr, idsubst, nwrd++, posinsubst, useasis);
|
||||
|
@ -239,7 +283,8 @@ thesaurusRead( char *filename, DictThesaurus *d ) {
|
|||
|
||||
idsubst++;
|
||||
|
||||
if ( !(nwrd && posinsubst) ) {
|
||||
if (!(nwrd && posinsubst))
|
||||
{
|
||||
fclose(fh);
|
||||
elog(ERROR, "Thesaurus: Unexpected end of line at %d line", lineno);
|
||||
}
|
||||
|
@ -252,9 +297,11 @@ thesaurusRead( char *filename, DictThesaurus *d ) {
|
|||
}
|
||||
|
||||
static TheLexeme *
|
||||
addCompiledLexeme(TheLexeme *newwrds, int *nnw, int *tnm, TSLexeme *lexeme, LexemeInfo* src, uint16 tnvariant) {
|
||||
addCompiledLexeme(TheLexeme * newwrds, int *nnw, int *tnm, TSLexeme * lexeme, LexemeInfo * src, uint16 tnvariant)
|
||||
{
|
||||
|
||||
if ( *nnw >= *tnm ) {
|
||||
if (*nnw >= *tnm)
|
||||
{
|
||||
*tnm *= 2;
|
||||
newwrds = (TheLexeme *) realloc(newwrds, sizeof(TheLexeme) * *tnm);
|
||||
if (!newwrds)
|
||||
|
@ -265,13 +312,16 @@ addCompiledLexeme(TheLexeme *newwrds, int *nnw, int *tnm, TSLexeme *lexeme, Le
|
|||
if (!newwrds[*nnw].entries)
|
||||
elog(ERROR, "Out of memory");
|
||||
|
||||
if ( lexeme && lexeme->lexeme ) {
|
||||
if (lexeme && lexeme->lexeme)
|
||||
{
|
||||
newwrds[*nnw].lexeme = strdup(lexeme->lexeme);
|
||||
if (!newwrds[*nnw].lexeme)
|
||||
elog(ERROR, "Out of memory");
|
||||
|
||||
newwrds[*nnw].entries->tnvariant = tnvariant;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
newwrds[*nnw].lexeme = NULL;
|
||||
newwrds[*nnw].entries->tnvariant = 1;
|
||||
}
|
||||
|
@ -286,12 +336,15 @@ addCompiledLexeme(TheLexeme *newwrds, int *nnw, int *tnm, TSLexeme *lexeme, Le
|
|||
}
|
||||
|
||||
static int
|
||||
cmpLexemeInfo(LexemeInfo *a, LexemeInfo *b) {
|
||||
cmpLexemeInfo(LexemeInfo * a, LexemeInfo * b)
|
||||
{
|
||||
if (a == NULL || b == NULL)
|
||||
return 0;
|
||||
|
||||
if ( a->idsubst == b->idsubst ) {
|
||||
if ( a->posinsubst == b->posinsubst ) {
|
||||
if (a->idsubst == b->idsubst)
|
||||
{
|
||||
if (a->posinsubst == b->posinsubst)
|
||||
{
|
||||
if (a->tnvariant == b->tnvariant)
|
||||
return 0;
|
||||
|
||||
|
@ -305,24 +358,30 @@ cmpLexemeInfo(LexemeInfo *a, LexemeInfo *b) {
|
|||
}
|
||||
|
||||
static int
|
||||
cmpLexeme(TheLexeme *a, TheLexeme* b) {
|
||||
if ( a->lexeme == NULL ) {
|
||||
cmpLexeme(TheLexeme * a, TheLexeme * b)
|
||||
{
|
||||
if (a->lexeme == NULL)
|
||||
{
|
||||
if (b->lexeme == NULL)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
} else if ( b->lexeme == NULL )
|
||||
}
|
||||
else if (b->lexeme == NULL)
|
||||
return -1;
|
||||
|
||||
return strcmp(a->lexeme, b->lexeme);
|
||||
}
|
||||
|
||||
static int
|
||||
cmpLexemeQ(const void *a, const void *b) {
|
||||
cmpLexemeQ(const void *a, const void *b)
|
||||
{
|
||||
return cmpLexeme((TheLexeme *) a, (TheLexeme *) b);
|
||||
}
|
||||
|
||||
static int cmpTheLexeme(const void *a, const void *b) {
|
||||
static int
|
||||
cmpTheLexeme(const void *a, const void *b)
|
||||
{
|
||||
TheLexeme *la = (TheLexeme *) a;
|
||||
TheLexeme *lb = (TheLexeme *) b;
|
||||
int res;
|
||||
|
@ -334,14 +393,19 @@ static int cmpTheLexeme(const void *a, const void *b) {
|
|||
}
|
||||
|
||||
static void
|
||||
compileTheLexeme(DictThesaurus *d) {
|
||||
int i,nnw=0, tnm=16;
|
||||
TheLexeme *newwrds = (TheLexeme*)malloc(sizeof(TheLexeme)*tnm), *ptrwrds;
|
||||
compileTheLexeme(DictThesaurus * d)
|
||||
{
|
||||
int i,
|
||||
nnw = 0,
|
||||
tnm = 16;
|
||||
TheLexeme *newwrds = (TheLexeme *) malloc(sizeof(TheLexeme) * tnm),
|
||||
*ptrwrds;
|
||||
|
||||
if (!newwrds)
|
||||
elog(ERROR, "Out of memory");
|
||||
|
||||
for(i=0;i<d->nwrds;i++) {
|
||||
for (i = 0; i < d->nwrds; i++)
|
||||
{
|
||||
TSLexeme *ptr;
|
||||
|
||||
ptr = (TSLexeme *) DatumGetPointer(
|
||||
|
@ -354,7 +418,8 @@ compileTheLexeme(DictThesaurus *d) {
|
|||
)
|
||||
);
|
||||
|
||||
if ( !(ptr && ptr->lexeme) ) {
|
||||
if (!(ptr && ptr->lexeme))
|
||||
{
|
||||
if (!ptr)
|
||||
elog(ERROR, "Thesaurus: word-sample '%s' isn't recognized by subdictionary (rule %d)",
|
||||
d->wrds[i].lexeme, d->wrds[i].entries->idsubst + 1);
|
||||
|
@ -363,14 +428,18 @@ compileTheLexeme(DictThesaurus *d) {
|
|||
d->wrds[i].lexeme, d->wrds[i].entries->idsubst + 1);
|
||||
|
||||
newwrds = addCompiledLexeme(newwrds, &nnw, &tnm, NULL, d->wrds[i].entries, 0);
|
||||
} else {
|
||||
while( ptr->lexeme ) {
|
||||
}
|
||||
else
|
||||
{
|
||||
while (ptr->lexeme)
|
||||
{
|
||||
TSLexeme *remptr = ptr + 1;
|
||||
int tnvar = 1;
|
||||
int curvar = ptr->nvariant;
|
||||
|
||||
/* compute n words in one variant */
|
||||
while( remptr->lexeme ) {
|
||||
while (remptr->lexeme)
|
||||
{
|
||||
if (remptr->nvariant != (remptr - 1)->nvariant)
|
||||
break;
|
||||
tnvar++;
|
||||
|
@ -378,7 +447,8 @@ compileTheLexeme(DictThesaurus *d) {
|
|||
}
|
||||
|
||||
remptr = ptr;
|
||||
while( remptr->lexeme && remptr->nvariant == curvar ) {
|
||||
while (remptr->lexeme && remptr->nvariant == curvar)
|
||||
{
|
||||
newwrds = addCompiledLexeme(newwrds, &nnw, &tnm, remptr, d->wrds[i].entries, tnvar);
|
||||
remptr++;
|
||||
}
|
||||
|
@ -396,23 +466,30 @@ compileTheLexeme(DictThesaurus *d) {
|
|||
d->nwrds = nnw;
|
||||
d->ntwrds = tnm;
|
||||
|
||||
if ( d->nwrds > 1 ) {
|
||||
if (d->nwrds > 1)
|
||||
{
|
||||
qsort(d->wrds, d->nwrds, sizeof(TheLexeme), cmpTheLexeme);
|
||||
|
||||
/* uniq */
|
||||
newwrds = d->wrds;
|
||||
ptrwrds = d->wrds + 1;
|
||||
while( ptrwrds - d->wrds < d->nwrds ) {
|
||||
if ( cmpLexeme( ptrwrds, newwrds ) == 0 ) {
|
||||
if ( cmpLexemeInfo(ptrwrds->entries, newwrds->entries) ) {
|
||||
while (ptrwrds - d->wrds < d->nwrds)
|
||||
{
|
||||
if (cmpLexeme(ptrwrds, newwrds) == 0)
|
||||
{
|
||||
if (cmpLexemeInfo(ptrwrds->entries, newwrds->entries))
|
||||
{
|
||||
ptrwrds->entries->nextentry = newwrds->entries;
|
||||
newwrds->entries = ptrwrds->entries;
|
||||
} else
|
||||
}
|
||||
else
|
||||
free(ptrwrds->entries);
|
||||
|
||||
if (ptrwrds->lexeme)
|
||||
free(ptrwrds->lexeme);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
newwrds++;
|
||||
*newwrds = *ptrwrds;
|
||||
}
|
||||
|
@ -426,11 +503,15 @@ compileTheLexeme(DictThesaurus *d) {
|
|||
}
|
||||
|
||||
static void
|
||||
compileTheSubstitute(DictThesaurus *d) {
|
||||
compileTheSubstitute(DictThesaurus * d)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0;i<d->nsubst;i++) {
|
||||
TSLexeme *rem = d->subst[i].res, *outptr, *inptr;
|
||||
for (i = 0; i < d->nsubst; i++)
|
||||
{
|
||||
TSLexeme *rem = d->subst[i].res,
|
||||
*outptr,
|
||||
*inptr;
|
||||
int n = 2;
|
||||
|
||||
outptr = d->subst[i].res = (TSLexeme *) malloc(sizeof(TSLexeme) * n);
|
||||
|
@ -439,15 +520,20 @@ compileTheSubstitute(DictThesaurus *d) {
|
|||
outptr->lexeme = NULL;
|
||||
inptr = rem;
|
||||
|
||||
while( inptr && inptr->lexeme ) {
|
||||
TSLexeme *lexized, tmplex[2];
|
||||
while (inptr && inptr->lexeme)
|
||||
{
|
||||
TSLexeme *lexized,
|
||||
tmplex[2];
|
||||
|
||||
if ( inptr->flags & DT_USEASIS ) { /* do not lexize */
|
||||
if (inptr->flags & DT_USEASIS)
|
||||
{ /* do not lexize */
|
||||
tmplex[0] = *inptr;
|
||||
tmplex[0].flags = 0;
|
||||
tmplex[1].lexeme = NULL;
|
||||
lexized = tmplex;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
lexized = (TSLexeme *) DatumGetPointer(
|
||||
FunctionCall4(
|
||||
&(d->subdict.lexize_info),
|
||||
|
@ -459,12 +545,16 @@ compileTheSubstitute(DictThesaurus *d) {
|
|||
);
|
||||
}
|
||||
|
||||
if ( lexized && lexized->lexeme ) {
|
||||
if (lexized && lexized->lexeme)
|
||||
{
|
||||
int toset = (lexized->lexeme && outptr != d->subst[i].res) ? (outptr - d->subst[i].res) : -1;
|
||||
|
||||
while( lexized->lexeme ) {
|
||||
if ( outptr - d->subst[i].res + 1 >= n ) {
|
||||
while (lexized->lexeme)
|
||||
{
|
||||
if (outptr - d->subst[i].res + 1 >= n)
|
||||
{
|
||||
int diff = outptr - d->subst[i].res;
|
||||
|
||||
n *= 2;
|
||||
d->subst[i].res = (TSLexeme *) realloc(d->subst[i].res, sizeof(TSLexeme) * n);
|
||||
if (d->subst[i].res == NULL)
|
||||
|
@ -482,9 +572,13 @@ compileTheSubstitute(DictThesaurus *d) {
|
|||
|
||||
if (toset > 0)
|
||||
d->subst[i].res[toset].flags |= TSL_ADDPOS;
|
||||
} else if ( lexized ) {
|
||||
}
|
||||
else if (lexized)
|
||||
{
|
||||
elog(NOTICE, "Thesaurus: word '%s' in substition is a stop-word, ignored (rule %d)", inptr->lexeme, i + 1);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
elog(ERROR, "Thesaurus: word '%s' in substition isn't recognized (rule %d)", inptr->lexeme, i + 1);
|
||||
}
|
||||
|
||||
|
@ -508,7 +602,8 @@ thesaurus_init(PG_FUNCTION_ARGS)
|
|||
DictThesaurus *d;
|
||||
Map *cfg,
|
||||
*pcfg;
|
||||
text *in, *subdictname=NULL;
|
||||
text *in,
|
||||
*subdictname = NULL;
|
||||
bool fileloaded = false;
|
||||
|
||||
if (PG_ARGISNULL(0) || PG_GETARG_POINTER(0) == NULL)
|
||||
|
@ -571,11 +666,13 @@ thesaurus_init(PG_FUNCTION_ARGS)
|
|||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
errmsg("Thesaurus file isn't defined")));
|
||||
|
||||
if ( subdictname ) {
|
||||
if (subdictname)
|
||||
{
|
||||
DictInfo *subdictptr;
|
||||
|
||||
/*
|
||||
* we already in SPI, but name2id_dict()/finddict()
|
||||
* invoke SPI_connect()
|
||||
* we already in SPI, but name2id_dict()/finddict() invoke
|
||||
* SPI_connect()
|
||||
*/
|
||||
SPI_push();
|
||||
|
||||
|
@ -584,7 +681,8 @@ thesaurus_init(PG_FUNCTION_ARGS)
|
|||
SPI_pop();
|
||||
|
||||
d->subdict = *subdictptr;
|
||||
} else
|
||||
}
|
||||
else
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
errmsg("Thesaurus: SubDictionary isn't defined")));
|
||||
|
@ -596,7 +694,8 @@ thesaurus_init(PG_FUNCTION_ARGS)
|
|||
}
|
||||
|
||||
static LexemeInfo *
|
||||
findTheLexeme(DictThesaurus *d, char * lexeme) {
|
||||
findTheLexeme(DictThesaurus * d, char *lexeme)
|
||||
{
|
||||
TheLexeme key = {lexeme, NULL}, *res;
|
||||
|
||||
if (d->nwrds == 0)
|
||||
|
@ -610,14 +709,17 @@ findTheLexeme(DictThesaurus *d, char * lexeme) {
|
|||
}
|
||||
|
||||
static bool
|
||||
matchIdSubst(LexemeInfo *stored, uint16 idsubst) {
|
||||
matchIdSubst(LexemeInfo * stored, uint16 idsubst)
|
||||
{
|
||||
bool res = true;
|
||||
|
||||
if (stored) {
|
||||
if (stored)
|
||||
{
|
||||
res = false;
|
||||
|
||||
for (; stored; stored = stored->nextvariant)
|
||||
if ( stored->idsubst == idsubst ) {
|
||||
if (stored->idsubst == idsubst)
|
||||
{
|
||||
res = true;
|
||||
break;
|
||||
}
|
||||
|
@ -627,26 +729,32 @@ matchIdSubst(LexemeInfo *stored, uint16 idsubst) {
|
|||
}
|
||||
|
||||
static LexemeInfo *
|
||||
findVariant( LexemeInfo *in, LexemeInfo *stored, uint16 curpos, LexemeInfo **newin, int newn) {
|
||||
for(;;) {
|
||||
findVariant(LexemeInfo * in, LexemeInfo * stored, uint16 curpos, LexemeInfo ** newin, int newn)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
int i;
|
||||
LexemeInfo *ptr = newin[0];
|
||||
|
||||
for(i=0; i<newn; i++) {
|
||||
for (i = 0; i < newn; i++)
|
||||
{
|
||||
while (newin[i] && newin[i]->idsubst < ptr->idsubst)
|
||||
newin[i] = newin[i]->nextentry;
|
||||
|
||||
if (newin[i] == NULL)
|
||||
return in;
|
||||
|
||||
if ( newin[i]->idsubst > ptr->idsubst ) {
|
||||
if (newin[i]->idsubst > ptr->idsubst)
|
||||
{
|
||||
ptr = newin[i];
|
||||
i = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
while(newin[i]->idsubst == ptr->idsubst) {
|
||||
if ( newin[i]->posinsubst == curpos && newin[i]->tnvariant == newn ) {
|
||||
while (newin[i]->idsubst == ptr->idsubst)
|
||||
{
|
||||
if (newin[i]->posinsubst == curpos && newin[i]->tnvariant == newn)
|
||||
{
|
||||
ptr = newin[i];
|
||||
break;
|
||||
}
|
||||
|
@ -656,14 +764,16 @@ findVariant( LexemeInfo *in, LexemeInfo *stored, uint16 curpos, LexemeInfo **new
|
|||
return in;
|
||||
}
|
||||
|
||||
if ( newin[i]->idsubst != ptr->idsubst ) {
|
||||
if (newin[i]->idsubst != ptr->idsubst)
|
||||
{
|
||||
ptr = newin[i];
|
||||
i = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ( i==newn && matchIdSubst(stored, ptr->idsubst) && (in==NULL || !matchIdSubst(in, ptr->idsubst)) ) { /* found */
|
||||
if (i == newn && matchIdSubst(stored, ptr->idsubst) && (in == NULL || !matchIdSubst(in, ptr->idsubst)))
|
||||
{ /* found */
|
||||
|
||||
ptr->nextvariant = in;
|
||||
in = ptr;
|
||||
|
@ -678,12 +788,14 @@ findVariant( LexemeInfo *in, LexemeInfo *stored, uint16 curpos, LexemeInfo **new
|
|||
}
|
||||
|
||||
static TSLexeme *
|
||||
copyTSLexeme( TheSubstitute *ts ) {
|
||||
copyTSLexeme(TheSubstitute * ts)
|
||||
{
|
||||
TSLexeme *res;
|
||||
uint16 i;
|
||||
|
||||
res = (TSLexeme *) palloc(sizeof(TSLexeme) * (ts->reslen + 1));
|
||||
for(i=0;i<ts->reslen;i++) {
|
||||
for (i = 0; i < ts->reslen; i++)
|
||||
{
|
||||
res[i] = ts->res[i];
|
||||
res[i].lexeme = pstrdup(ts->res[i].lexeme);
|
||||
}
|
||||
|
@ -694,9 +806,11 @@ copyTSLexeme( TheSubstitute *ts ) {
|
|||
}
|
||||
|
||||
static TSLexeme *
|
||||
checkMatch(DictThesaurus *d, LexemeInfo *info, uint16 curpos, bool *moreres) {
|
||||
checkMatch(DictThesaurus * d, LexemeInfo * info, uint16 curpos, bool *moreres)
|
||||
{
|
||||
*moreres = false;
|
||||
while(info) {
|
||||
while (info)
|
||||
{
|
||||
Assert(info->idsubst < d->nsubst);
|
||||
if (info->nextvariant)
|
||||
*moreres = true;
|
||||
|
@ -714,7 +828,8 @@ thesaurus_lexize(PG_FUNCTION_ARGS)
|
|||
DictThesaurus *d = (DictThesaurus *) PG_GETARG_POINTER(0);
|
||||
DictSubState *dstate = (DictSubState *) PG_GETARG_POINTER(3);
|
||||
TSLexeme *res = NULL;
|
||||
LexemeInfo *stored, *info = NULL;
|
||||
LexemeInfo *stored,
|
||||
*info = NULL;
|
||||
uint16 curpos = 0;
|
||||
bool moreres = false;
|
||||
|
||||
|
@ -738,16 +853,21 @@ thesaurus_lexize(PG_FUNCTION_ARGS)
|
|||
)
|
||||
);
|
||||
|
||||
if ( res && res->lexeme ) {
|
||||
TSLexeme *ptr = res , *basevar;
|
||||
if (res && res->lexeme)
|
||||
{
|
||||
TSLexeme *ptr = res,
|
||||
*basevar;
|
||||
|
||||
while( ptr->lexeme ) {
|
||||
while (ptr->lexeme)
|
||||
{
|
||||
uint16 nv = ptr->nvariant;
|
||||
uint16 i,nlex = 0;
|
||||
uint16 i,
|
||||
nlex = 0;
|
||||
LexemeInfo **infos;
|
||||
|
||||
basevar = ptr;
|
||||
while( ptr->lexeme && nv == ptr->nvariant ) {
|
||||
while (ptr->lexeme && nv == ptr->nvariant)
|
||||
{
|
||||
nlex++;
|
||||
ptr++;
|
||||
}
|
||||
|
@ -757,7 +877,8 @@ thesaurus_lexize(PG_FUNCTION_ARGS)
|
|||
if ((infos[i] = findTheLexeme(d, basevar[i].lexeme)) == NULL)
|
||||
break;
|
||||
|
||||
if ( i<nlex ) {
|
||||
if (i < nlex)
|
||||
{
|
||||
/* no chance to find */
|
||||
pfree(infos);
|
||||
continue;
|
||||
|
@ -765,21 +886,28 @@ thesaurus_lexize(PG_FUNCTION_ARGS)
|
|||
|
||||
info = findVariant(info, stored, curpos, infos, nlex);
|
||||
}
|
||||
} else if ( res ) { /* stop-word */
|
||||
}
|
||||
else if (res)
|
||||
{ /* stop-word */
|
||||
LexemeInfo *infos = findTheLexeme(d, NULL);
|
||||
|
||||
info = findVariant(NULL, stored, curpos, &infos, 1);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
info = NULL; /* word isn't recognized */
|
||||
}
|
||||
|
||||
dstate->private = (void *) info;
|
||||
|
||||
if ( !info ) {
|
||||
if (!info)
|
||||
{
|
||||
dstate->getnext = false;
|
||||
PG_RETURN_POINTER(NULL);
|
||||
}
|
||||
|
||||
if ( (res=checkMatch(d, info, curpos,&moreres)) != NULL ) {
|
||||
if ((res = checkMatch(d, info, curpos, &moreres)) != NULL)
|
||||
{
|
||||
dstate->getnext = moreres;
|
||||
PG_RETURN_POINTER(res);
|
||||
}
|
||||
|
|
|
@ -18,20 +18,23 @@ PG_FUNCTION_INFO_V1(gin_extract_tsvector);
|
|||
Datum gin_extract_tsvector(PG_FUNCTION_ARGS);
|
||||
|
||||
Datum
|
||||
gin_extract_tsvector(PG_FUNCTION_ARGS) {
|
||||
gin_extract_tsvector(PG_FUNCTION_ARGS)
|
||||
{
|
||||
tsvector *vector = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
||||
uint32 *nentries = (uint32 *) PG_GETARG_POINTER(1);
|
||||
Datum *entries = NULL;
|
||||
|
||||
*nentries = 0;
|
||||
if ( vector->size > 0 ) {
|
||||
if (vector->size > 0)
|
||||
{
|
||||
int i;
|
||||
WordEntry *we = ARRPTR(vector);
|
||||
|
||||
*nentries = (uint32) vector->size;
|
||||
entries = (Datum *) palloc(sizeof(Datum) * vector->size);
|
||||
|
||||
for(i=0;i<vector->size;i++) {
|
||||
for (i = 0; i < vector->size; i++)
|
||||
{
|
||||
text *txt = (text *) palloc(VARHDRSZ + we->len);
|
||||
|
||||
VARATT_SIZEP(txt) = VARHDRSZ + we->len;
|
||||
|
@ -52,15 +55,19 @@ PG_FUNCTION_INFO_V1(gin_extract_tsquery);
|
|||
Datum gin_extract_tsquery(PG_FUNCTION_ARGS);
|
||||
|
||||
Datum
|
||||
gin_extract_tsquery(PG_FUNCTION_ARGS) {
|
||||
gin_extract_tsquery(PG_FUNCTION_ARGS)
|
||||
{
|
||||
QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
||||
uint32 *nentries = (uint32 *) PG_GETARG_POINTER(1);
|
||||
StrategyNumber strategy = DatumGetUInt16(PG_GETARG_DATUM(2));
|
||||
Datum *entries = NULL;
|
||||
|
||||
*nentries = 0;
|
||||
if ( query->size > 0 ) {
|
||||
int4 i, j=0, len;
|
||||
if (query->size > 0)
|
||||
{
|
||||
int4 i,
|
||||
j = 0,
|
||||
len;
|
||||
ITEM *item;
|
||||
|
||||
item = clean_NOT_v2(GETQUERY(query), &len);
|
||||
|
@ -76,7 +83,8 @@ gin_extract_tsquery(PG_FUNCTION_ARGS) {
|
|||
entries = (Datum *) palloc(sizeof(Datum) * (*nentries));
|
||||
|
||||
for (i = 0; i < query->size; i++)
|
||||
if ( item[i].type == VAL ) {
|
||||
if (item[i].type == VAL)
|
||||
{
|
||||
text *txt;
|
||||
|
||||
txt = (text *) palloc(VARHDRSZ + item[i].length);
|
||||
|
@ -96,13 +104,15 @@ gin_extract_tsquery(PG_FUNCTION_ARGS) {
|
|||
PG_RETURN_POINTER(entries);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
ITEM *frst;
|
||||
bool *mapped_check;
|
||||
} GinChkVal;
|
||||
|
||||
static bool
|
||||
checkcondition_gin(void *checkval, ITEM * val) {
|
||||
checkcondition_gin(void *checkval, ITEM * val)
|
||||
{
|
||||
GinChkVal *gcv = (GinChkVal *) checkval;
|
||||
|
||||
return gcv->mapped_check[val - gcv->frst];
|
||||
|
@ -112,13 +122,16 @@ PG_FUNCTION_INFO_V1(gin_ts_consistent);
|
|||
Datum gin_ts_consistent(PG_FUNCTION_ARGS);
|
||||
|
||||
Datum
|
||||
gin_ts_consistent(PG_FUNCTION_ARGS) {
|
||||
gin_ts_consistent(PG_FUNCTION_ARGS)
|
||||
{
|
||||
bool *check = (bool *) PG_GETARG_POINTER(0);
|
||||
QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_DATUM(2));
|
||||
bool res = FALSE;
|
||||
|
||||
if ( query->size > 0 ) {
|
||||
int4 i, j=0;
|
||||
if (query->size > 0)
|
||||
{
|
||||
int4 i,
|
||||
j = 0;
|
||||
ITEM *item;
|
||||
GinChkVal gcv;
|
||||
|
||||
|
@ -142,5 +155,3 @@ gin_ts_consistent(PG_FUNCTION_ARGS) {
|
|||
PG_FREE_IF_COPY(query, 2);
|
||||
PG_RETURN_BOOL(res);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $PostgreSQL: pgsql/contrib/tsearch2/gistidx.c,v 1.14 2006/06/28 12:00:06 teodor Exp $ */
|
||||
/* $PostgreSQL: pgsql/contrib/tsearch2/gistidx.c,v 1.15 2006/10/04 00:29:46 momjian Exp $ */
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
|
|
|
@ -133,19 +133,25 @@ RS_free(Regis * r)
|
|||
|
||||
#ifdef TS_USE_WIDE
|
||||
static bool
|
||||
mb_strchr(char *str, char *c) {
|
||||
int clen = pg_mblen(c), plen,i;
|
||||
mb_strchr(char *str, char *c)
|
||||
{
|
||||
int clen = pg_mblen(c),
|
||||
plen,
|
||||
i;
|
||||
char *ptr = str;
|
||||
bool res = false;
|
||||
|
||||
clen = pg_mblen(c);
|
||||
while( *ptr && !res) {
|
||||
while (*ptr && !res)
|
||||
{
|
||||
plen = pg_mblen(ptr);
|
||||
if ( plen == clen ) {
|
||||
if (plen == clen)
|
||||
{
|
||||
i = plen;
|
||||
res = true;
|
||||
while (i--)
|
||||
if ( *(ptr+i) != *(c+i) ) {
|
||||
if (*(ptr + i) != *(c + i))
|
||||
{
|
||||
res = false;
|
||||
break;
|
||||
}
|
||||
|
@ -168,7 +174,8 @@ RS_execute(Regis * r, char *str)
|
|||
char *c = str;
|
||||
int len = 0;
|
||||
|
||||
while(*c) {
|
||||
while (*c)
|
||||
{
|
||||
len++;
|
||||
c += pg_mblen(c);
|
||||
}
|
||||
|
@ -177,7 +184,8 @@ RS_execute(Regis * r, char *str)
|
|||
return 0;
|
||||
|
||||
c = str;
|
||||
if (r->issuffix) {
|
||||
if (r->issuffix)
|
||||
{
|
||||
len -= r->nchar;
|
||||
while (len-- > 0)
|
||||
c += pg_mblen(c);
|
||||
|
|
|
@ -41,8 +41,10 @@ strnduplicate(char *s, int len)
|
|||
}
|
||||
|
||||
static char *
|
||||
findchar(char *str, int c) {
|
||||
while( *str ) {
|
||||
findchar(char *str, int c)
|
||||
{
|
||||
while (*str)
|
||||
{
|
||||
if (t_iseq(str, c))
|
||||
return str;
|
||||
str += pg_mblen(str);
|
||||
|
@ -181,7 +183,8 @@ NIImportDictionary(IspellDict * Conf, const char *filename)
|
|||
s = str;
|
||||
while (*s)
|
||||
{
|
||||
if (t_isspace(s)) {
|
||||
if (t_isspace(s))
|
||||
{
|
||||
*s = '\0';
|
||||
break;
|
||||
}
|
||||
|
@ -269,6 +272,7 @@ NIAddAffix(IspellDict * Conf, int flag, char flagflags, const char *mask, const
|
|||
else
|
||||
{
|
||||
int masklen = strlen(mask);
|
||||
|
||||
Conf->Affix[Conf->naffixes].issimple = 0;
|
||||
Conf->Affix[Conf->naffixes].isregis = 0;
|
||||
Conf->Affix[Conf->naffixes].mask = (char *) malloc(masklen + 2);
|
||||
|
@ -286,10 +290,12 @@ NIAddAffix(IspellDict * Conf, int flag, char flagflags, const char *mask, const
|
|||
|
||||
Conf->Affix[Conf->naffixes].find = (find && *find) ? strdup(find) : VoidString;
|
||||
MEMOUT(Conf->Affix[Conf->naffixes].find);
|
||||
if ( (Conf->Affix[Conf->naffixes].replen = strlen(repl)) > 0 ) {
|
||||
if ((Conf->Affix[Conf->naffixes].replen = strlen(repl)) > 0)
|
||||
{
|
||||
Conf->Affix[Conf->naffixes].repl = strdup(repl);
|
||||
MEMOUT(Conf->Affix[Conf->naffixes].repl);
|
||||
} else
|
||||
}
|
||||
else
|
||||
Conf->Affix[Conf->naffixes].repl = VoidString;
|
||||
Conf->naffixes++;
|
||||
return (0);
|
||||
|
@ -303,66 +309,102 @@ NIAddAffix(IspellDict * Conf, int flag, char flagflags, const char *mask, const
|
|||
#define PAE_INREPL 5
|
||||
|
||||
static bool
|
||||
parse_affentry( char *str, char *mask, char *find, char *repl, int line ) {
|
||||
parse_affentry(char *str, char *mask, char *find, char *repl, int line)
|
||||
{
|
||||
int state = PAE_WAIT_MASK;
|
||||
char *pmask=mask, *pfind=find, *prepl=repl;
|
||||
char *pmask = mask,
|
||||
*pfind = find,
|
||||
*prepl = repl;
|
||||
|
||||
*mask = *find = *repl = '\0';
|
||||
|
||||
while(*str) {
|
||||
if ( state == PAE_WAIT_MASK ) {
|
||||
while (*str)
|
||||
{
|
||||
if (state == PAE_WAIT_MASK)
|
||||
{
|
||||
if (t_iseq(str, '#'))
|
||||
return false;
|
||||
else if (!t_isspace(str)) {
|
||||
else if (!t_isspace(str))
|
||||
{
|
||||
COPYCHAR(pmask, str);
|
||||
pmask += pg_mblen(str);
|
||||
state = PAE_INMASK;
|
||||
}
|
||||
} else if ( state == PAE_INMASK ) {
|
||||
if ( t_iseq(str,'>') ) {
|
||||
}
|
||||
else if (state == PAE_INMASK)
|
||||
{
|
||||
if (t_iseq(str, '>'))
|
||||
{
|
||||
*pmask = '\0';
|
||||
state = PAE_WAIT_FIND;
|
||||
} else if (!t_isspace(str)) {
|
||||
}
|
||||
else if (!t_isspace(str))
|
||||
{
|
||||
COPYCHAR(pmask, str);
|
||||
pmask += pg_mblen(str);
|
||||
}
|
||||
} else if ( state == PAE_WAIT_FIND ) {
|
||||
if ( t_iseq(str,'-') ) {
|
||||
}
|
||||
else if (state == PAE_WAIT_FIND)
|
||||
{
|
||||
if (t_iseq(str, '-'))
|
||||
{
|
||||
state = PAE_INFIND;
|
||||
} else if (t_isalpha(str) || t_iseq(str,'\'') /* english 's */) {
|
||||
}
|
||||
else if (t_isalpha(str) || t_iseq(str, '\'') /* english 's */ )
|
||||
{
|
||||
COPYCHAR(prepl, str);
|
||||
prepl += pg_mblen(str);
|
||||
state = PAE_INREPL;
|
||||
} else if (!t_isspace(str))
|
||||
}
|
||||
else if (!t_isspace(str))
|
||||
ts_error(ERROR, "Affix parse error at %d line", line);
|
||||
} else if ( state == PAE_INFIND ) {
|
||||
if ( t_iseq(str,',') ) {
|
||||
}
|
||||
else if (state == PAE_INFIND)
|
||||
{
|
||||
if (t_iseq(str, ','))
|
||||
{
|
||||
*pfind = '\0';
|
||||
state = PAE_WAIT_REPL;
|
||||
} else if (t_isalpha(str)) {
|
||||
}
|
||||
else if (t_isalpha(str))
|
||||
{
|
||||
COPYCHAR(pfind, str);
|
||||
pfind += pg_mblen(str);
|
||||
} else if (!t_isspace(str))
|
||||
}
|
||||
else if (!t_isspace(str))
|
||||
ts_error(ERROR, "Affix parse error at %d line", line);
|
||||
} else if ( state == PAE_WAIT_REPL ) {
|
||||
if ( t_iseq(str,'-') ) {
|
||||
}
|
||||
else if (state == PAE_WAIT_REPL)
|
||||
{
|
||||
if (t_iseq(str, '-'))
|
||||
{
|
||||
break; /* void repl */
|
||||
} else if ( t_isalpha(str) ) {
|
||||
}
|
||||
else if (t_isalpha(str))
|
||||
{
|
||||
COPYCHAR(prepl, str);
|
||||
prepl += pg_mblen(str);
|
||||
state = PAE_INREPL;
|
||||
} else if (!t_isspace(str))
|
||||
}
|
||||
else if (!t_isspace(str))
|
||||
ts_error(ERROR, "Affix parse error at %d line", line);
|
||||
} else if ( state == PAE_INREPL ) {
|
||||
if ( t_iseq(str,'#') ) {
|
||||
}
|
||||
else if (state == PAE_INREPL)
|
||||
{
|
||||
if (t_iseq(str, '#'))
|
||||
{
|
||||
*prepl = '\0';
|
||||
break;
|
||||
} else if ( t_isalpha(str) ) {
|
||||
}
|
||||
else if (t_isalpha(str))
|
||||
{
|
||||
COPYCHAR(prepl, str);
|
||||
prepl += pg_mblen(str);
|
||||
} else if (!t_isspace(str))
|
||||
}
|
||||
else if (!t_isspace(str))
|
||||
ts_error(ERROR, "Affix parse error at %d line", line);
|
||||
} else
|
||||
}
|
||||
else
|
||||
ts_error(ERROR, "Unknown state in parse_affentry: %d", state);
|
||||
|
||||
str += pg_mblen(str);
|
||||
|
@ -406,8 +448,10 @@ NIImportAffixes(IspellDict * Conf, const char *filename)
|
|||
s = findchar(str, 'l');
|
||||
if (s)
|
||||
{
|
||||
while (*s && !t_isspace(s)) s++;
|
||||
while (*s && t_isspace(s)) s++;
|
||||
while (*s && !t_isspace(s))
|
||||
s++;
|
||||
while (*s && t_isspace(s))
|
||||
s++;
|
||||
if (*s && pg_mblen(s) == 1)
|
||||
Conf->compoundcontrol = *s;
|
||||
oldformat++;
|
||||
|
@ -433,7 +477,8 @@ NIImportAffixes(IspellDict * Conf, const char *filename)
|
|||
s = str + 4;
|
||||
flagflags = 0;
|
||||
|
||||
while (*s && t_isspace(s)) s++;
|
||||
while (*s && t_isspace(s))
|
||||
s++;
|
||||
oldformat++;
|
||||
|
||||
/* allow only single-encoded flags */
|
||||
|
@ -455,7 +500,8 @@ NIImportAffixes(IspellDict * Conf, const char *filename)
|
|||
s++;
|
||||
|
||||
/* allow only single-encoded flags */
|
||||
if ( pg_mblen(s) != 1 ) {
|
||||
if (pg_mblen(s) != 1)
|
||||
{
|
||||
flagflags = 0;
|
||||
elog(ERROR, "Multiencoded flag at line %d: %s", line, s);
|
||||
}
|
||||
|
@ -464,7 +510,8 @@ NIImportAffixes(IspellDict * Conf, const char *filename)
|
|||
continue;
|
||||
}
|
||||
if (STRNCMP(str, "COMPOUNDFLAG") == 0 || STRNCMP(str, "COMPOUNDMIN") == 0 ||
|
||||
STRNCMP(str, "PFX")==0 || STRNCMP(str, "SFX")==0 ) {
|
||||
STRNCMP(str, "PFX") == 0 || STRNCMP(str, "SFX") == 0)
|
||||
{
|
||||
|
||||
if (oldformat)
|
||||
elog(ERROR, "Wrong affix file format");
|
||||
|
@ -488,7 +535,8 @@ NIImportAffixes(IspellDict * Conf, const char *filename)
|
|||
}
|
||||
|
||||
int
|
||||
NIImportOOAffixes(IspellDict * Conf, const char *filename) {
|
||||
NIImportOOAffixes(IspellDict * Conf, const char *filename)
|
||||
{
|
||||
char str[BUFSIZ];
|
||||
char type[BUFSIZ];
|
||||
char sflag[BUFSIZ];
|
||||
|
@ -516,9 +564,12 @@ NIImportOOAffixes(IspellDict * Conf, const char *filename) {
|
|||
continue;
|
||||
pg_verifymbstr(str, strlen(str), false);
|
||||
|
||||
if ( STRNCMP(str, "COMPOUNDFLAG")==0 ) {
|
||||
if (STRNCMP(str, "COMPOUNDFLAG") == 0)
|
||||
{
|
||||
char *s = str + strlen("COMPOUNDFLAG");
|
||||
while (*s && t_isspace(s)) s++;
|
||||
|
||||
while (*s && t_isspace(s))
|
||||
s++;
|
||||
if (*s && pg_mblen(s) == 1)
|
||||
Conf->compoundcontrol = *s;
|
||||
continue;
|
||||
|
@ -530,7 +581,8 @@ NIImportOOAffixes(IspellDict * Conf, const char *filename) {
|
|||
if (scanread < 4 || (STRNCMP(type, "sfx") && STRNCMP(type, "pfx")))
|
||||
continue;
|
||||
|
||||
if ( scanread == 4 ) {
|
||||
if (scanread == 4)
|
||||
{
|
||||
if (strlen(sflag) != 1)
|
||||
continue;
|
||||
flag = *sflag;
|
||||
|
@ -540,7 +592,9 @@ NIImportOOAffixes(IspellDict * Conf, const char *filename) {
|
|||
flagflags |= FF_CROSSPRODUCT;
|
||||
else
|
||||
flagflags = 0;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strlen(sflag) != 1 || flag != *sflag || flag == 0)
|
||||
continue;
|
||||
lowerstr(repl);
|
||||
|
@ -912,8 +966,10 @@ CheckAffix(const char *word, size_t len, AFFIX * Affix, char flagflags, char *ne
|
|||
}
|
||||
else
|
||||
{
|
||||
/* if prefix is a all non-chaged part's length then all word contains only prefix and suffix,
|
||||
so out */
|
||||
/*
|
||||
* if prefix is a all non-chaged part's length then all word contains
|
||||
* only prefix and suffix, so out
|
||||
*/
|
||||
if (baselen && *baselen + strlen(Affix->find) <= Affix->replen)
|
||||
return NULL;
|
||||
strcpy(newword, Affix->find);
|
||||
|
@ -944,6 +1000,7 @@ CheckAffix(const char *word, size_t len, AFFIX * Affix, char flagflags, char *ne
|
|||
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);
|
||||
|
||||
|
@ -1111,7 +1168,8 @@ typedef struct SplitVar
|
|||
static int
|
||||
CheckCompoundAffixes(CMPDAffix ** ptr, char *word, int len, bool CheckInPlace)
|
||||
{
|
||||
if ( CheckInPlace ) {
|
||||
if (CheckInPlace)
|
||||
{
|
||||
while ((*ptr)->affix)
|
||||
{
|
||||
if (len > (*ptr)->len && strncmp((*ptr)->affix, word, (*ptr)->len) == 0)
|
||||
|
@ -1122,8 +1180,11 @@ CheckCompoundAffixes(CMPDAffix ** ptr, char *word, int len, bool CheckInPlace)
|
|||
}
|
||||
(*ptr)++;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
char *affbegin;
|
||||
|
||||
while ((*ptr)->affix)
|
||||
{
|
||||
if (len > (*ptr)->len && (affbegin = strstr(word, (*ptr)->affix)) != NULL)
|
||||
|
@ -1243,7 +1304,8 @@ SplitToVariants(IspellDict * Conf, SPNode * snode, SplitVar * orig, char *word,
|
|||
StopHigh = StopMiddle;
|
||||
}
|
||||
|
||||
if (StopLow < StopHigh) {
|
||||
if (StopLow < StopHigh)
|
||||
{
|
||||
|
||||
/* find infinitive */
|
||||
if (StopMiddle->isword && StopMiddle->compoundallow && notprobed[level])
|
||||
|
@ -1279,7 +1341,8 @@ SplitToVariants(IspellDict * Conf, SPNode * snode, SplitVar * orig, char *word,
|
|||
}
|
||||
}
|
||||
node = StopMiddle->node;
|
||||
} else
|
||||
}
|
||||
else
|
||||
node = NULL;
|
||||
level++;
|
||||
}
|
||||
|
@ -1436,9 +1499,12 @@ NIFree(IspellDict * Conf)
|
|||
else
|
||||
pg_regfree(&(Affix[i].reg.regex));
|
||||
}
|
||||
if ( Affix[i].mask != VoidString ) free(Affix[i].mask);
|
||||
if ( Affix[i].find != VoidString ) free(Affix[i].find);
|
||||
if ( Affix[i].repl != VoidString ) free(Affix[i].repl);
|
||||
if (Affix[i].mask != VoidString)
|
||||
free(Affix[i].mask);
|
||||
if (Affix[i].find != VoidString)
|
||||
free(Affix[i].find);
|
||||
if (Affix[i].repl != VoidString)
|
||||
free(Affix[i].repl);
|
||||
}
|
||||
if (Conf->Spell)
|
||||
{
|
||||
|
|
|
@ -155,7 +155,8 @@ gettoken_query(QPRS_STATE * state, int4 *val, int4 *lenval, char **strval, int2
|
|||
case WAITOPERAND:
|
||||
if (t_iseq(state->buf, '!'))
|
||||
{
|
||||
(state->buf)++; /* can safely ++, t_iseq guarantee that pg_mblen()==1 */
|
||||
(state->buf)++; /* can safely ++, t_iseq guarantee
|
||||
* that pg_mblen()==1 */
|
||||
*val = (int4) '!';
|
||||
return OPR;
|
||||
}
|
||||
|
@ -702,6 +703,7 @@ Datum
|
|||
tsquery_in(PG_FUNCTION_ARGS)
|
||||
{
|
||||
char *in = (char *) PG_GETARG_POINTER(0);
|
||||
|
||||
pg_verifymbstr(in, strlen(in), false);
|
||||
|
||||
SET_FUNCOID();
|
||||
|
|
|
@ -337,7 +337,8 @@ calc_rank(float *w, tsvector * t, QUERYTYPE * q, int4 method)
|
|||
if ((method & RANK_NORM_LOGLENGTH) && t->size > 0)
|
||||
res /= log((double) (cnt_length(t) + 1)) / log(2.0);
|
||||
|
||||
if ( method & RANK_NORM_LENGTH ) {
|
||||
if (method & RANK_NORM_LENGTH)
|
||||
{
|
||||
len = cnt_length(t);
|
||||
if (len > 0)
|
||||
res /= (float) len;
|
||||
|
@ -457,7 +458,8 @@ reset_istrue_flag(QUERYTYPE * query)
|
|||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
int pos;
|
||||
int p;
|
||||
int q;
|
||||
|
@ -513,7 +515,8 @@ Cover(DocRepresentation * doc, int len, QUERYTYPE * query, Extention *ext)
|
|||
ptr->item[i]->istrue = 1;
|
||||
if (TS_execute(GETQUERY(query), NULL, true, checkcondition_ITEM))
|
||||
{
|
||||
if (ptr->pos < ext->p) {
|
||||
if (ptr->pos < ext->p)
|
||||
{
|
||||
ext->begin = ptr;
|
||||
ext->p = ptr->pos;
|
||||
}
|
||||
|
@ -629,7 +632,8 @@ get_docrep(tsvector * txt, QUERYTYPE * query, int *doclen)
|
|||
}
|
||||
|
||||
static float4
|
||||
calc_rank_cd(float4 *arrdata, tsvector *txt, QUERYTYPE *query, int method) {
|
||||
calc_rank_cd(float4 *arrdata, tsvector * txt, QUERYTYPE * query, int method)
|
||||
{
|
||||
DocRepresentation *doc;
|
||||
int len,
|
||||
i,
|
||||
|
@ -637,7 +641,9 @@ calc_rank_cd(float4 *arrdata, tsvector *txt, QUERYTYPE *query, int method) {
|
|||
Extention ext;
|
||||
double Wdoc = 0.0;
|
||||
double invws[lengthof(weights)];
|
||||
double SumDist=0.0, PrevExtPos=0.0, CurExtPos=0.0;
|
||||
double SumDist = 0.0,
|
||||
PrevExtPos = 0.0,
|
||||
CurExtPos = 0.0;
|
||||
int NExtent = 0;
|
||||
|
||||
for (i = 0; i < lengthof(weights); i++)
|
||||
|
@ -655,12 +661,14 @@ calc_rank_cd(float4 *arrdata, tsvector *txt, QUERYTYPE *query, int method) {
|
|||
return 0.0;
|
||||
|
||||
MemSet(&ext, 0, sizeof(Extention));
|
||||
while (Cover(doc, doclen, query, &ext)) {
|
||||
while (Cover(doc, doclen, query, &ext))
|
||||
{
|
||||
double Cpos = 0.0;
|
||||
double InvSum = 0.0;
|
||||
DocRepresentation *ptr = ext.begin;
|
||||
|
||||
while ( ptr<=ext.end ) {
|
||||
while (ptr <= ext.end)
|
||||
{
|
||||
InvSum += invws[ptr->wclass];
|
||||
ptr++;
|
||||
}
|
||||
|
@ -669,7 +677,9 @@ calc_rank_cd(float4 *arrdata, tsvector *txt, QUERYTYPE *query, int method) {
|
|||
Wdoc += Cpos / ((double) ((1 + (ext.q - ext.p) - (ext.end - ext.begin))));
|
||||
|
||||
CurExtPos = ((double) (ext.q + ext.p)) / 2.0;
|
||||
if ( NExtent>0 && CurExtPos > PrevExtPos /* prevent devision by zero in a case of multiple lexize */ )
|
||||
if (NExtent > 0 && CurExtPos > PrevExtPos /* prevent devision by
|
||||
* zero in a case of
|
||||
multiple lexize */ )
|
||||
SumDist += 1.0 / (CurExtPos - PrevExtPos);
|
||||
|
||||
PrevExtPos = CurExtPos;
|
||||
|
@ -679,7 +689,8 @@ calc_rank_cd(float4 *arrdata, tsvector *txt, QUERYTYPE *query, int method) {
|
|||
if ((method & RANK_NORM_LOGLENGTH) && txt->size > 0)
|
||||
Wdoc /= log((double) (cnt_length(txt) + 1));
|
||||
|
||||
if ( method & RANK_NORM_LENGTH ) {
|
||||
if (method & RANK_NORM_LENGTH)
|
||||
{
|
||||
len = cnt_length(txt);
|
||||
if (len > 0)
|
||||
Wdoc /= (double) len;
|
||||
|
|
|
@ -337,44 +337,68 @@ static symbol s_7[] = { 0xD0, 0xBD };
|
|||
static symbol s_8[] = {0xD0, 0xBD};
|
||||
static symbol s_9[] = {0xD0, 0xB8};
|
||||
|
||||
static int r_mark_regions(struct SN_env * z) {
|
||||
static int
|
||||
r_mark_regions(struct SN_env * z)
|
||||
{
|
||||
z->I[0] = z->l;
|
||||
z->I[1] = z->l;
|
||||
{ int c = z->c; /* do, line 61 */
|
||||
while(1) { /* gopast, line 62 */
|
||||
if (!(in_grouping_U(z, g_v, 1072, 1103))) goto lab1;
|
||||
{
|
||||
int c = z->c; /* do, line 61 */
|
||||
|
||||
while (1)
|
||||
{ /* gopast, line 62 */
|
||||
if (!(in_grouping_U(z, g_v, 1072, 1103)))
|
||||
goto lab1;
|
||||
break;
|
||||
lab1:
|
||||
{ int c = skip_utf8(z->p, z->c, 0, z->l, 1);
|
||||
if (c < 0) goto lab0;
|
||||
{
|
||||
int c = skip_utf8(z->p, z->c, 0, z->l, 1);
|
||||
|
||||
if (c < 0)
|
||||
goto lab0;
|
||||
z->c = c; /* gopast, line 62 */
|
||||
}
|
||||
}
|
||||
z->I[0] = z->c; /* setmark pV, line 62 */
|
||||
while(1) { /* gopast, line 62 */
|
||||
if (!(out_grouping_U(z, g_v, 1072, 1103))) goto lab2;
|
||||
while (1)
|
||||
{ /* gopast, line 62 */
|
||||
if (!(out_grouping_U(z, g_v, 1072, 1103)))
|
||||
goto lab2;
|
||||
break;
|
||||
lab2:
|
||||
{ int c = skip_utf8(z->p, z->c, 0, z->l, 1);
|
||||
if (c < 0) goto lab0;
|
||||
{
|
||||
int c = skip_utf8(z->p, z->c, 0, z->l, 1);
|
||||
|
||||
if (c < 0)
|
||||
goto lab0;
|
||||
z->c = c; /* gopast, line 62 */
|
||||
}
|
||||
}
|
||||
while(1) { /* gopast, line 63 */
|
||||
if (!(in_grouping_U(z, g_v, 1072, 1103))) goto lab3;
|
||||
while (1)
|
||||
{ /* gopast, line 63 */
|
||||
if (!(in_grouping_U(z, g_v, 1072, 1103)))
|
||||
goto lab3;
|
||||
break;
|
||||
lab3:
|
||||
{ int c = skip_utf8(z->p, z->c, 0, z->l, 1);
|
||||
if (c < 0) goto lab0;
|
||||
{
|
||||
int c = skip_utf8(z->p, z->c, 0, z->l, 1);
|
||||
|
||||
if (c < 0)
|
||||
goto lab0;
|
||||
z->c = c; /* gopast, line 63 */
|
||||
}
|
||||
}
|
||||
while(1) { /* gopast, line 63 */
|
||||
if (!(out_grouping_U(z, g_v, 1072, 1103))) goto lab4;
|
||||
while (1)
|
||||
{ /* gopast, line 63 */
|
||||
if (!(out_grouping_U(z, g_v, 1072, 1103)))
|
||||
goto lab4;
|
||||
break;
|
||||
lab4:
|
||||
{ int c = skip_utf8(z->p, z->c, 0, z->l, 1);
|
||||
if (c < 0) goto lab0;
|
||||
{
|
||||
int c = skip_utf8(z->p, z->c, 0, z->l, 1);
|
||||
|
||||
if (c < 0)
|
||||
goto lab0;
|
||||
z->c = c; /* gopast, line 63 */
|
||||
}
|
||||
}
|
||||
|
@ -385,92 +409,154 @@ static int r_mark_regions(struct SN_env * z) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int r_R2(struct SN_env * z) {
|
||||
if (!(z->I[1] <= z->c)) return 0;
|
||||
static int
|
||||
r_R2(struct SN_env * z)
|
||||
{
|
||||
if (!(z->I[1] <= z->c))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int r_perfective_gerund(struct SN_env * z) {
|
||||
static int
|
||||
r_perfective_gerund(struct SN_env * z)
|
||||
{
|
||||
int among_var;
|
||||
|
||||
z->ket = z->c; /* [, line 72 */
|
||||
among_var = find_among_b(z, a_0, 9); /* substring, line 72 */
|
||||
if (!(among_var)) return 0;
|
||||
if (!(among_var))
|
||||
return 0;
|
||||
z->bra = z->c; /* ], line 72 */
|
||||
switch(among_var) {
|
||||
case 0: return 0;
|
||||
switch (among_var)
|
||||
{
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
{ int m = z->l - z->c; (void) m; /* or, line 76 */
|
||||
if (!(eq_s_b(z, 2, s_0))) goto lab1;
|
||||
{
|
||||
int m = z->l - z->c;
|
||||
|
||||
(void) m; /* or, line 76 */
|
||||
if (!(eq_s_b(z, 2, s_0)))
|
||||
goto lab1;
|
||||
goto lab0;
|
||||
lab1:
|
||||
z->c = z->l - m;
|
||||
if (!(eq_s_b(z, 2, s_1))) return 0;
|
||||
if (!(eq_s_b(z, 2, s_1)))
|
||||
return 0;
|
||||
}
|
||||
lab0:
|
||||
{ int ret;
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = slice_del(z); /* delete, line 76 */
|
||||
if (ret < 0) return ret;
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{ int ret;
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = slice_del(z); /* delete, line 83 */
|
||||
if (ret < 0) return ret;
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int r_adjective(struct SN_env * z) {
|
||||
static int
|
||||
r_adjective(struct SN_env * z)
|
||||
{
|
||||
int among_var;
|
||||
|
||||
z->ket = z->c; /* [, line 88 */
|
||||
among_var = find_among_b(z, a_1, 26); /* substring, line 88 */
|
||||
if (!(among_var)) return 0;
|
||||
if (!(among_var))
|
||||
return 0;
|
||||
z->bra = z->c; /* ], line 88 */
|
||||
switch(among_var) {
|
||||
case 0: return 0;
|
||||
switch (among_var)
|
||||
{
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
{ int ret;
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = slice_del(z); /* delete, line 97 */
|
||||
if (ret < 0) return ret;
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int r_adjectival(struct SN_env * z) {
|
||||
static int
|
||||
r_adjectival(struct SN_env * z)
|
||||
{
|
||||
int among_var;
|
||||
{ int ret = r_adjective(z);
|
||||
if (ret == 0) return 0; /* call adjective, line 102 */
|
||||
if (ret < 0) return ret;
|
||||
|
||||
{
|
||||
int ret = r_adjective(z);
|
||||
|
||||
if (ret == 0)
|
||||
return 0; /* call adjective, line 102 */
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
{ int m = z->l - z->c; (void) m; /* try, line 109 */
|
||||
{
|
||||
int m = z->l - z->c;
|
||||
|
||||
(void) m; /* try, line 109 */
|
||||
z->ket = z->c; /* [, line 110 */
|
||||
among_var = find_among_b(z, a_2, 8); /* substring, line 110 */
|
||||
if (!(among_var)) { z->c = z->l - m; goto lab0; }
|
||||
if (!(among_var))
|
||||
{
|
||||
z->c = z->l - m;
|
||||
goto lab0;
|
||||
}
|
||||
z->bra = z->c; /* ], line 110 */
|
||||
switch(among_var) {
|
||||
case 0: { z->c = z->l - m; goto lab0; }
|
||||
switch (among_var)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
z->c = z->l - m;
|
||||
goto lab0;
|
||||
}
|
||||
case 1:
|
||||
{ int m = z->l - z->c; (void) m; /* or, line 115 */
|
||||
if (!(eq_s_b(z, 2, s_2))) goto lab2;
|
||||
{
|
||||
int m = z->l - z->c;
|
||||
|
||||
(void) m; /* or, line 115 */
|
||||
if (!(eq_s_b(z, 2, s_2)))
|
||||
goto lab2;
|
||||
goto lab1;
|
||||
lab2:
|
||||
z->c = z->l - m;
|
||||
if (!(eq_s_b(z, 2, s_3))) { z->c = z->l - m; goto lab0; }
|
||||
if (!(eq_s_b(z, 2, s_3)))
|
||||
{
|
||||
z->c = z->l - m;
|
||||
goto lab0;
|
||||
}
|
||||
}
|
||||
lab1:
|
||||
{ int ret;
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = slice_del(z); /* delete, line 115 */
|
||||
if (ret < 0) return ret;
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{ int ret;
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = slice_del(z); /* delete, line 122 */
|
||||
if (ret < 0) return ret;
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -480,187 +566,305 @@ static int r_adjectival(struct SN_env * z) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int r_reflexive(struct SN_env * z) {
|
||||
static int
|
||||
r_reflexive(struct SN_env * z)
|
||||
{
|
||||
int among_var;
|
||||
|
||||
z->ket = z->c; /* [, line 129 */
|
||||
among_var = find_among_b(z, a_3, 2); /* substring, line 129 */
|
||||
if (!(among_var)) return 0;
|
||||
if (!(among_var))
|
||||
return 0;
|
||||
z->bra = z->c; /* ], line 129 */
|
||||
switch(among_var) {
|
||||
case 0: return 0;
|
||||
switch (among_var)
|
||||
{
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
{ int ret;
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = slice_del(z); /* delete, line 132 */
|
||||
if (ret < 0) return ret;
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int r_verb(struct SN_env * z) {
|
||||
static int
|
||||
r_verb(struct SN_env * z)
|
||||
{
|
||||
int among_var;
|
||||
|
||||
z->ket = z->c; /* [, line 137 */
|
||||
among_var = find_among_b(z, a_4, 46); /* substring, line 137 */
|
||||
if (!(among_var)) return 0;
|
||||
if (!(among_var))
|
||||
return 0;
|
||||
z->bra = z->c; /* ], line 137 */
|
||||
switch(among_var) {
|
||||
case 0: return 0;
|
||||
switch (among_var)
|
||||
{
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
{ int m = z->l - z->c; (void) m; /* or, line 143 */
|
||||
if (!(eq_s_b(z, 2, s_4))) goto lab1;
|
||||
{
|
||||
int m = z->l - z->c;
|
||||
|
||||
(void) m; /* or, line 143 */
|
||||
if (!(eq_s_b(z, 2, s_4)))
|
||||
goto lab1;
|
||||
goto lab0;
|
||||
lab1:
|
||||
z->c = z->l - m;
|
||||
if (!(eq_s_b(z, 2, s_5))) return 0;
|
||||
if (!(eq_s_b(z, 2, s_5)))
|
||||
return 0;
|
||||
}
|
||||
lab0:
|
||||
{ int ret;
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = slice_del(z); /* delete, line 143 */
|
||||
if (ret < 0) return ret;
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{ int ret;
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = slice_del(z); /* delete, line 151 */
|
||||
if (ret < 0) return ret;
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int r_noun(struct SN_env * z) {
|
||||
static int
|
||||
r_noun(struct SN_env * z)
|
||||
{
|
||||
int among_var;
|
||||
|
||||
z->ket = z->c; /* [, line 160 */
|
||||
among_var = find_among_b(z, a_5, 36); /* substring, line 160 */
|
||||
if (!(among_var)) return 0;
|
||||
if (!(among_var))
|
||||
return 0;
|
||||
z->bra = z->c; /* ], line 160 */
|
||||
switch(among_var) {
|
||||
case 0: return 0;
|
||||
switch (among_var)
|
||||
{
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
{ int ret;
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = slice_del(z); /* delete, line 167 */
|
||||
if (ret < 0) return ret;
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int r_derivational(struct SN_env * z) {
|
||||
static int
|
||||
r_derivational(struct SN_env * z)
|
||||
{
|
||||
int among_var;
|
||||
|
||||
z->ket = z->c; /* [, line 176 */
|
||||
among_var = find_among_b(z, a_6, 2); /* substring, line 176 */
|
||||
if (!(among_var)) return 0;
|
||||
if (!(among_var))
|
||||
return 0;
|
||||
z->bra = z->c; /* ], line 176 */
|
||||
{ int ret = r_R2(z);
|
||||
if (ret == 0) return 0; /* call R2, line 176 */
|
||||
if (ret < 0) return ret;
|
||||
{
|
||||
int ret = r_R2(z);
|
||||
|
||||
if (ret == 0)
|
||||
return 0; /* call R2, line 176 */
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
switch(among_var) {
|
||||
case 0: return 0;
|
||||
switch (among_var)
|
||||
{
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
{ int ret;
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = slice_del(z); /* delete, line 179 */
|
||||
if (ret < 0) return ret;
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int r_tidy_up(struct SN_env * z) {
|
||||
static int
|
||||
r_tidy_up(struct SN_env * z)
|
||||
{
|
||||
int among_var;
|
||||
|
||||
z->ket = z->c; /* [, line 184 */
|
||||
among_var = find_among_b(z, a_7, 4); /* substring, line 184 */
|
||||
if (!(among_var)) return 0;
|
||||
if (!(among_var))
|
||||
return 0;
|
||||
z->bra = z->c; /* ], line 184 */
|
||||
switch(among_var) {
|
||||
case 0: return 0;
|
||||
switch (among_var)
|
||||
{
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
{ int ret;
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = slice_del(z); /* delete, line 188 */
|
||||
if (ret < 0) return ret;
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
z->ket = z->c; /* [, line 189 */
|
||||
if (!(eq_s_b(z, 2, s_6))) return 0;
|
||||
if (!(eq_s_b(z, 2, s_6)))
|
||||
return 0;
|
||||
z->bra = z->c; /* ], line 189 */
|
||||
if (!(eq_s_b(z, 2, s_7))) return 0;
|
||||
{ int ret;
|
||||
if (!(eq_s_b(z, 2, s_7)))
|
||||
return 0;
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = slice_del(z); /* delete, line 189 */
|
||||
if (ret < 0) return ret;
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (!(eq_s_b(z, 2, s_8))) return 0;
|
||||
{ int ret;
|
||||
if (!(eq_s_b(z, 2, s_8)))
|
||||
return 0;
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = slice_del(z); /* delete, line 192 */
|
||||
if (ret < 0) return ret;
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
{ int ret;
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = slice_del(z); /* delete, line 194 */
|
||||
if (ret < 0) return ret;
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
extern int russian_UTF_8_stem(struct SN_env * z) {
|
||||
{ int c = z->c; /* do, line 201 */
|
||||
{ int ret = r_mark_regions(z);
|
||||
if (ret == 0) goto lab0; /* call mark_regions, line 201 */
|
||||
if (ret < 0) return ret;
|
||||
extern int
|
||||
russian_UTF_8_stem(struct SN_env * z)
|
||||
{
|
||||
{
|
||||
int c = z->c; /* do, line 201 */
|
||||
|
||||
{
|
||||
int ret = r_mark_regions(z);
|
||||
|
||||
if (ret == 0)
|
||||
goto lab0; /* call mark_regions, line 201 */
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
lab0:
|
||||
z->c = c;
|
||||
}
|
||||
z->lb = z->c; z->c = z->l; /* backwards, line 202 */
|
||||
z->lb = z->c;
|
||||
z->c = z->l; /* backwards, line 202 */
|
||||
|
||||
{ int m3; /* setlimit, line 202 */
|
||||
int m = z->l - z->c; (void) m;
|
||||
if (z->c < z->I[0]) return 0;
|
||||
{
|
||||
int m3; /* setlimit, line 202 */
|
||||
int m = z->l - z->c;
|
||||
|
||||
(void) m;
|
||||
if (z->c < z->I[0])
|
||||
return 0;
|
||||
z->c = z->I[0]; /* tomark, line 202 */
|
||||
m3 = z->lb; z->lb = z->c;
|
||||
m3 = z->lb;
|
||||
z->lb = z->c;
|
||||
z->c = z->l - m;
|
||||
{ int m = z->l - z->c; (void) m; /* do, line 203 */
|
||||
{ int m = z->l - z->c; (void) m; /* or, line 204 */
|
||||
{ int ret = r_perfective_gerund(z);
|
||||
if (ret == 0) goto lab3; /* call perfective_gerund, line 204 */
|
||||
if (ret < 0) return ret;
|
||||
{
|
||||
int m = z->l - z->c;
|
||||
|
||||
(void) m; /* do, line 203 */
|
||||
{
|
||||
int m = z->l - z->c;
|
||||
|
||||
(void) m; /* or, line 204 */
|
||||
{
|
||||
int ret = r_perfective_gerund(z);
|
||||
|
||||
if (ret == 0)
|
||||
goto lab3; /* call perfective_gerund, line 204 */
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
goto lab2;
|
||||
lab3:
|
||||
z->c = z->l - m;
|
||||
{ int m = z->l - z->c; (void) m; /* try, line 205 */
|
||||
{ int ret = r_reflexive(z);
|
||||
if (ret == 0) { z->c = z->l - m; goto lab4; } /* call reflexive, line 205 */
|
||||
if (ret < 0) return ret;
|
||||
{
|
||||
int m = z->l - z->c;
|
||||
|
||||
(void) m; /* try, line 205 */
|
||||
{
|
||||
int ret = r_reflexive(z);
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
z->c = z->l - m;
|
||||
goto lab4;
|
||||
} /* call reflexive, line 205 */
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
lab4:
|
||||
;
|
||||
}
|
||||
{ int m = z->l - z->c; (void) m; /* or, line 206 */
|
||||
{ int ret = r_adjectival(z);
|
||||
if (ret == 0) goto lab6; /* call adjectival, line 206 */
|
||||
if (ret < 0) return ret;
|
||||
{
|
||||
int m = z->l - z->c;
|
||||
|
||||
(void) m; /* or, line 206 */
|
||||
{
|
||||
int ret = r_adjectival(z);
|
||||
|
||||
if (ret == 0)
|
||||
goto lab6; /* call adjectival, line 206 */
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
goto lab5;
|
||||
lab6:
|
||||
z->c = z->l - m;
|
||||
{ int ret = r_verb(z);
|
||||
if (ret == 0) goto lab7; /* call verb, line 206 */
|
||||
if (ret < 0) return ret;
|
||||
{
|
||||
int ret = r_verb(z);
|
||||
|
||||
if (ret == 0)
|
||||
goto lab7; /* call verb, line 206 */
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
goto lab5;
|
||||
lab7:
|
||||
z->c = z->l - m;
|
||||
{ int ret = r_noun(z);
|
||||
if (ret == 0) goto lab1; /* call noun, line 206 */
|
||||
if (ret < 0) return ret;
|
||||
{
|
||||
int ret = r_noun(z);
|
||||
|
||||
if (ret == 0)
|
||||
goto lab1; /* call noun, line 206 */
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
lab5:
|
||||
|
@ -670,29 +874,53 @@ extern int russian_UTF_8_stem(struct SN_env * z) {
|
|||
lab1:
|
||||
z->c = z->l - m;
|
||||
}
|
||||
{ int m = z->l - z->c; (void) m; /* try, line 209 */
|
||||
{
|
||||
int m = z->l - z->c;
|
||||
|
||||
(void) m; /* try, line 209 */
|
||||
z->ket = z->c; /* [, line 209 */
|
||||
if (!(eq_s_b(z, 2, s_9))) { z->c = z->l - m; goto lab8; }
|
||||
if (!(eq_s_b(z, 2, s_9)))
|
||||
{
|
||||
z->c = z->l - m;
|
||||
goto lab8;
|
||||
}
|
||||
z->bra = z->c; /* ], line 209 */
|
||||
{ int ret;
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = slice_del(z); /* delete, line 209 */
|
||||
if (ret < 0) return ret;
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
lab8:
|
||||
;
|
||||
}
|
||||
{ int m = z->l - z->c; (void) m; /* do, line 212 */
|
||||
{ int ret = r_derivational(z);
|
||||
if (ret == 0) goto lab9; /* call derivational, line 212 */
|
||||
if (ret < 0) return ret;
|
||||
{
|
||||
int m = z->l - z->c;
|
||||
|
||||
(void) m; /* do, line 212 */
|
||||
{
|
||||
int ret = r_derivational(z);
|
||||
|
||||
if (ret == 0)
|
||||
goto lab9; /* call derivational, line 212 */
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
lab9:
|
||||
z->c = z->l - m;
|
||||
}
|
||||
{ int m = z->l - z->c; (void) m; /* do, line 213 */
|
||||
{ int ret = r_tidy_up(z);
|
||||
if (ret == 0) goto lab10; /* call tidy_up, line 213 */
|
||||
if (ret < 0) return ret;
|
||||
{
|
||||
int m = z->l - z->c;
|
||||
|
||||
(void) m; /* do, line 213 */
|
||||
{
|
||||
int ret = r_tidy_up(z);
|
||||
|
||||
if (ret == 0)
|
||||
goto lab10; /* call tidy_up, line 213 */
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
lab10:
|
||||
z->c = z->l - m;
|
||||
|
@ -703,7 +931,12 @@ extern int russian_UTF_8_stem(struct SN_env * z) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
extern struct SN_env * russian_UTF_8_create_env(void) { return SN_create_env(0, 2, 0); }
|
||||
|
||||
extern void russian_UTF_8_close_env(struct SN_env * z) { SN_close_env(z); }
|
||||
extern struct SN_env *russian_UTF_8_create_env(void)
|
||||
{
|
||||
return SN_create_env(0, 2, 0);
|
||||
}
|
||||
|
||||
extern void russian_UTF_8_close_env(struct SN_env * z)
|
||||
{
|
||||
SN_close_env(z);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
/* This file was generated automatically by the Snowball to ANSI C compiler */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
extern struct SN_env *russian_UTF_8_create_env(void);
|
||||
|
@ -12,5 +13,5 @@ extern int russian_UTF_8_stem(struct SN_env * z);
|
|||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -301,7 +301,8 @@ parsetext_v2(TSCfgInfo * cfg, PRSTEXT * prs, char *buf, int4 buflen)
|
|||
|
||||
LexizeInit(&ldata, cfg);
|
||||
|
||||
do {
|
||||
do
|
||||
{
|
||||
type = DatumGetInt32(FunctionCall3(
|
||||
&(prsobj->getlexeme_info),
|
||||
PointerGetDatum(prsobj->prs),
|
||||
|
@ -407,17 +408,20 @@ hlfinditem(HLPRSTEXT * prs, QUERYTYPE * query, char *buf, int buflen)
|
|||
}
|
||||
|
||||
static void
|
||||
addHLParsedLex(HLPRSTEXT *prs, QUERYTYPE * query, ParsedLex *lexs, TSLexeme *norms) {
|
||||
addHLParsedLex(HLPRSTEXT * prs, QUERYTYPE * query, ParsedLex * lexs, TSLexeme * norms)
|
||||
{
|
||||
ParsedLex *tmplexs;
|
||||
TSLexeme *ptr;
|
||||
|
||||
while( lexs ) {
|
||||
while (lexs)
|
||||
{
|
||||
|
||||
if (lexs->type > 0)
|
||||
hladdword(prs, lexs->lemm, lexs->lenlemm, lexs->type);
|
||||
|
||||
ptr = norms;
|
||||
while( ptr && ptr->lexeme ) {
|
||||
while (ptr && ptr->lexeme)
|
||||
{
|
||||
hlfinditem(prs, query, ptr->lexeme, strlen(ptr->lexeme));
|
||||
ptr++;
|
||||
}
|
||||
|
@ -427,9 +431,11 @@ addHLParsedLex(HLPRSTEXT *prs, QUERYTYPE * query, ParsedLex *lexs, TSLexeme *nor
|
|||
lexs = tmplexs;
|
||||
}
|
||||
|
||||
if ( norms ) {
|
||||
if (norms)
|
||||
{
|
||||
ptr = norms;
|
||||
while( ptr->lexeme ) {
|
||||
while (ptr->lexeme)
|
||||
{
|
||||
pfree(ptr->lexeme);
|
||||
ptr++;
|
||||
}
|
||||
|
@ -458,7 +464,8 @@ hlparsetext(TSCfgInfo * cfg, HLPRSTEXT * prs, QUERYTYPE * query, char *buf, int4
|
|||
|
||||
LexizeInit(&ldata, cfg);
|
||||
|
||||
do {
|
||||
do
|
||||
{
|
||||
type = DatumGetInt32(FunctionCall3(
|
||||
&(prsobj->getlexeme_info),
|
||||
PointerGetDatum(prsobj->prs),
|
||||
|
@ -481,7 +488,8 @@ hlparsetext(TSCfgInfo * cfg, HLPRSTEXT * prs, QUERYTYPE * query, char *buf, int4
|
|||
|
||||
LexizeAddLemm(&ldata, type, lemm, lenlemm);
|
||||
|
||||
do {
|
||||
do
|
||||
{
|
||||
if ((norms = LexizeExec(&ldata, &lexs)) != NULL)
|
||||
addHLParsedLex(prs, query, lexs, norms);
|
||||
else
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
#include "dict.h"
|
||||
|
||||
void
|
||||
LexizeInit(LexizeData *ld, TSCfgInfo *cfg) {
|
||||
LexizeInit(LexizeData * ld, TSCfgInfo * cfg)
|
||||
{
|
||||
ld->cfg = cfg;
|
||||
ld->curDictId = InvalidOid;
|
||||
ld->posDict = 0;
|
||||
|
@ -22,17 +23,21 @@ LexizeInit(LexizeData *ld, TSCfgInfo *cfg) {
|
|||
}
|
||||
|
||||
static void
|
||||
LPLAddTail(ListParsedLex *list, ParsedLex *newpl) {
|
||||
if ( list->tail ) {
|
||||
LPLAddTail(ListParsedLex * list, ParsedLex * newpl)
|
||||
{
|
||||
if (list->tail)
|
||||
{
|
||||
list->tail->next = newpl;
|
||||
list->tail = newpl;
|
||||
} else
|
||||
}
|
||||
else
|
||||
list->head = list->tail = newpl;
|
||||
newpl->next = NULL;
|
||||
}
|
||||
|
||||
static ParsedLex *
|
||||
LPLRemoveHead(ListParsedLex *list) {
|
||||
LPLRemoveHead(ListParsedLex * list)
|
||||
{
|
||||
ParsedLex *res = list->head;
|
||||
|
||||
if (list->head)
|
||||
|
@ -46,7 +51,8 @@ LPLRemoveHead(ListParsedLex *list) {
|
|||
|
||||
|
||||
void
|
||||
LexizeAddLemm(LexizeData *ld, int type, char *lemm, int lenlemm) {
|
||||
LexizeAddLemm(LexizeData * ld, int type, char *lemm, int lenlemm)
|
||||
{
|
||||
ParsedLex *newpl = (ParsedLex *) palloc(sizeof(ParsedLex));
|
||||
|
||||
newpl = (ParsedLex *) palloc(sizeof(ParsedLex));
|
||||
|
@ -58,20 +64,27 @@ LexizeAddLemm(LexizeData *ld, int type, char *lemm, int lenlemm) {
|
|||
}
|
||||
|
||||
static void
|
||||
RemoveHead(LexizeData *ld) {
|
||||
RemoveHead(LexizeData * ld)
|
||||
{
|
||||
LPLAddTail(&ld->waste, LPLRemoveHead(&ld->towork));
|
||||
|
||||
ld->posDict = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
setCorrLex(LexizeData *ld, ParsedLex **correspondLexem) {
|
||||
if ( correspondLexem ) {
|
||||
setCorrLex(LexizeData * ld, ParsedLex ** correspondLexem)
|
||||
{
|
||||
if (correspondLexem)
|
||||
{
|
||||
*correspondLexem = ld->waste.head;
|
||||
} else {
|
||||
ParsedLex *tmp, *ptr = ld->waste.head;
|
||||
}
|
||||
else
|
||||
{
|
||||
ParsedLex *tmp,
|
||||
*ptr = ld->waste.head;
|
||||
|
||||
while(ptr) {
|
||||
while (ptr)
|
||||
{
|
||||
tmp = ptr->next;
|
||||
pfree(ptr);
|
||||
ptr = tmp;
|
||||
|
@ -81,11 +94,14 @@ setCorrLex(LexizeData *ld, ParsedLex **correspondLexem) {
|
|||
}
|
||||
|
||||
static void
|
||||
moveToWaste(LexizeData *ld, ParsedLex *stop) {
|
||||
moveToWaste(LexizeData * ld, ParsedLex * stop)
|
||||
{
|
||||
bool go = true;
|
||||
|
||||
while( ld->towork.head && go) {
|
||||
if (ld->towork.head == stop) {
|
||||
while (ld->towork.head && go)
|
||||
{
|
||||
if (ld->towork.head == stop)
|
||||
{
|
||||
ld->curSub = stop->next;
|
||||
go = false;
|
||||
}
|
||||
|
@ -94,9 +110,12 @@ moveToWaste(LexizeData *ld, ParsedLex *stop) {
|
|||
}
|
||||
|
||||
static void
|
||||
setNewTmpRes(LexizeData *ld, ParsedLex *lex, TSLexeme *res) {
|
||||
if ( ld->tmpRes ) {
|
||||
setNewTmpRes(LexizeData * ld, ParsedLex * lex, TSLexeme * res)
|
||||
{
|
||||
if (ld->tmpRes)
|
||||
{
|
||||
TSLexeme *ptr;
|
||||
|
||||
for (ptr = ld->tmpRes; ptr->lexeme; ptr++)
|
||||
pfree(ptr->lexeme);
|
||||
pfree(ld->tmpRes);
|
||||
|
@ -106,31 +125,35 @@ setNewTmpRes(LexizeData *ld, ParsedLex *lex, TSLexeme *res) {
|
|||
}
|
||||
|
||||
TSLexeme *
|
||||
LexizeExec(LexizeData *ld, ParsedLex **correspondLexem) {
|
||||
LexizeExec(LexizeData * ld, ParsedLex ** correspondLexem)
|
||||
{
|
||||
int i;
|
||||
ListDictionary *map;
|
||||
DictInfo *dict;
|
||||
TSLexeme *res;
|
||||
|
||||
if ( ld->curDictId == InvalidOid ) {
|
||||
if (ld->curDictId == InvalidOid)
|
||||
{
|
||||
/*
|
||||
* usial mode: dictionary wants only one word,
|
||||
* but we should keep in mind that we should go through
|
||||
* all stack
|
||||
* usial mode: dictionary wants only one word, but we should keep in
|
||||
* mind that we should go through all stack
|
||||
*/
|
||||
|
||||
while( ld->towork.head ) {
|
||||
while (ld->towork.head)
|
||||
{
|
||||
ParsedLex *curVal = ld->towork.head;
|
||||
|
||||
map = ld->cfg->map + curVal->type;
|
||||
|
||||
if (curVal->type == 0 || curVal->type >= ld->cfg->len || map->len == 0 ) {
|
||||
if (curVal->type == 0 || curVal->type >= ld->cfg->len || map->len == 0)
|
||||
{
|
||||
/* skip this type of lexeme */
|
||||
RemoveHead(ld);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = ld->posDict; i < map->len; i++) {
|
||||
for (i = ld->posDict; i < map->len; i++)
|
||||
{
|
||||
dict = finddict(DatumGetObjectId(map->dict_id[i]));
|
||||
|
||||
ld->dictState.isend = ld->dictState.getnext = false;
|
||||
|
@ -143,10 +166,11 @@ LexizeExec(LexizeData *ld, ParsedLex **correspondLexem) {
|
|||
PointerGetDatum(&ld->dictState)
|
||||
));
|
||||
|
||||
if ( ld->dictState.getnext ) {
|
||||
if (ld->dictState.getnext)
|
||||
{
|
||||
/*
|
||||
* dictinary wants next word, so setup and store
|
||||
* current position and go to multiword mode
|
||||
* dictinary wants next word, so setup and store current
|
||||
* position and go to multiword mode
|
||||
*/
|
||||
|
||||
ld->curDictId = DatumGetObjectId(map->dict_id[i]);
|
||||
|
@ -167,37 +191,43 @@ LexizeExec(LexizeData *ld, ParsedLex **correspondLexem) {
|
|||
|
||||
RemoveHead(ld);
|
||||
}
|
||||
} else { /* curDictId is valid */
|
||||
}
|
||||
else
|
||||
{ /* curDictId is valid */
|
||||
dict = finddict(ld->curDictId);
|
||||
|
||||
/*
|
||||
* Dictionary ld->curDictId asks us about following words
|
||||
*/
|
||||
|
||||
while( ld->curSub ) {
|
||||
while (ld->curSub)
|
||||
{
|
||||
ParsedLex *curVal = ld->curSub;
|
||||
|
||||
map = ld->cfg->map + curVal->type;
|
||||
|
||||
if (curVal->type != 0) {
|
||||
if (curVal->type != 0)
|
||||
{
|
||||
bool dictExists = false;
|
||||
|
||||
if (curVal->type >= ld->cfg->len || map->len == 0 ) {
|
||||
if (curVal->type >= ld->cfg->len || map->len == 0)
|
||||
{
|
||||
/* skip this type of lexeme */
|
||||
ld->curSub = curVal->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* We should be sure that current type of lexeme is recognized by
|
||||
* our dictinonary: we just check is it exist in
|
||||
* list of dictionaries ?
|
||||
* We should be sure that current type of lexeme is recognized
|
||||
* by our dictinonary: we just check is it exist in list of
|
||||
* dictionaries ?
|
||||
*/
|
||||
for (i = 0; i < map->len && !dictExists; i++)
|
||||
if (ld->curDictId == DatumGetObjectId(map->dict_id[i]))
|
||||
dictExists = true;
|
||||
|
||||
if ( !dictExists ) {
|
||||
if (!dictExists)
|
||||
{
|
||||
/*
|
||||
* Dictionary can't work with current tpe of lexeme,
|
||||
* return to basic mode and redo all stored lexemes
|
||||
|
@ -218,7 +248,8 @@ LexizeExec(LexizeData *ld, ParsedLex **correspondLexem) {
|
|||
PointerGetDatum(&ld->dictState)
|
||||
));
|
||||
|
||||
if ( ld->dictState.getnext ) {
|
||||
if (ld->dictState.getnext)
|
||||
{
|
||||
/* Dictionary wants one more */
|
||||
ld->curSub = curVal->next;
|
||||
if (res)
|
||||
|
@ -226,15 +257,19 @@ LexizeExec(LexizeData *ld, ParsedLex **correspondLexem) {
|
|||
continue;
|
||||
}
|
||||
|
||||
if ( res || ld->tmpRes ) {
|
||||
if (res || ld->tmpRes)
|
||||
{
|
||||
/*
|
||||
* Dictionary normalizes lexemes,
|
||||
* so we remove from stack all used lexemes ,
|
||||
* return to basic mode and redo end of stack (if it exists)
|
||||
* Dictionary normalizes lexemes, so we remove from stack all
|
||||
* used lexemes , return to basic mode and redo end of stack
|
||||
* (if it exists)
|
||||
*/
|
||||
if ( res ) {
|
||||
if (res)
|
||||
{
|
||||
moveToWaste(ld, ld->curSub);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
res = ld->tmpRes;
|
||||
moveToWaste(ld, ld->lastRes);
|
||||
}
|
||||
|
@ -248,8 +283,10 @@ LexizeExec(LexizeData *ld, ParsedLex **correspondLexem) {
|
|||
return res;
|
||||
}
|
||||
|
||||
/* Dict don't want next lexem and didn't recognize anything,
|
||||
redo from ld->towork.head */
|
||||
/*
|
||||
* Dict don't want next lexem and didn't recognize anything, redo
|
||||
* from ld->towork.head
|
||||
*/
|
||||
ld->curDictId = InvalidOid;
|
||||
return LexizeExec(ld, correspondLexem);
|
||||
}
|
||||
|
@ -258,4 +295,3 @@ LexizeExec(LexizeData *ld, ParsedLex **correspondLexem) {
|
|||
setCorrLex(ld, correspondLexem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -70,11 +70,11 @@ char2wchar(wchar_t *to, const char *from, size_t len)
|
|||
|
||||
return mbstowcs(to, from, len);
|
||||
}
|
||||
|
||||
#endif /* WIN32 */
|
||||
|
||||
int
|
||||
_t_isalpha( const char *ptr ) {
|
||||
_t_isalpha(const char *ptr)
|
||||
{
|
||||
wchar_t character;
|
||||
|
||||
char2wchar(&character, ptr, 1);
|
||||
|
@ -83,14 +83,14 @@ _t_isalpha( const char *ptr ) {
|
|||
}
|
||||
|
||||
int
|
||||
_t_isprint( const char *ptr ) {
|
||||
_t_isprint(const char *ptr)
|
||||
{
|
||||
wchar_t character;
|
||||
|
||||
char2wchar(&character, ptr, 1);
|
||||
|
||||
return iswprint((wint_t) character);
|
||||
}
|
||||
|
||||
#endif /* TS_USE_WIDE */
|
||||
|
||||
char *
|
||||
|
@ -99,25 +99,30 @@ lowerstr(char *str)
|
|||
char *ptr = str;
|
||||
|
||||
#ifdef TS_USE_WIDE
|
||||
|
||||
/*
|
||||
* Use wide char code only when max encoding length > 1 and ctype != C.
|
||||
* Some operating systems fail with multi-byte encodings and a C locale.
|
||||
* Also, for a C locale there is no need to process as multibyte. From
|
||||
* backend/utils/adt/oracle_compat.c Teodor
|
||||
*/
|
||||
if (pg_database_encoding_max_length() > 1 && !lc_ctype_is_c()) {
|
||||
wchar_t *wstr, *wptr;
|
||||
if (pg_database_encoding_max_length() > 1 && !lc_ctype_is_c())
|
||||
{
|
||||
wchar_t *wstr,
|
||||
*wptr;
|
||||
int len = strlen(str);
|
||||
|
||||
wptr = wstr = (wchar_t *) palloc(sizeof(wchar_t) * (len + 1));
|
||||
char2wchar(wstr, str, len + 1);
|
||||
while (*wptr) {
|
||||
while (*wptr)
|
||||
{
|
||||
*wptr = towlower((wint_t) *wptr);
|
||||
wptr++;
|
||||
}
|
||||
wchar2char(str, wstr, len);
|
||||
pfree(wstr);
|
||||
} else
|
||||
}
|
||||
else
|
||||
#endif
|
||||
while (*ptr)
|
||||
{
|
||||
|
@ -126,4 +131,3 @@ lowerstr(char *str)
|
|||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,8 +45,10 @@ size_t char2wchar(wchar_t *to, const char *from, size_t len);
|
|||
#define t_isdigit(x) ( pg_mblen(x)==1 && isdigit( TOUCHAR(x) ) )
|
||||
#define t_isspace(x) ( pg_mblen(x)==1 && isspace( TOUCHAR(x) ) )
|
||||
extern int _t_isalpha(const char *ptr);
|
||||
|
||||
#define t_isalpha(x) ( (pg_mblen(x)==1) ? isalpha( TOUCHAR(x) ) : _t_isalpha(x) )
|
||||
extern int _t_isprint(const char *ptr);
|
||||
|
||||
#define t_isprint(x) ( (pg_mblen(x)==1) ? isprint( TOUCHAR(x) ) : _t_isprint(x) )
|
||||
/*
|
||||
* t_iseq() should be called only for ASCII symbols
|
||||
|
@ -60,7 +62,6 @@ extern int _t_isprint( const char *ptr );
|
|||
TOUCHAR((d)+lll) = TOUCHAR((s)+lll); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#else /* not def TS_USE_WIDE */
|
||||
|
||||
#define t_isdigit(x) isdigit( TOUCHAR(x) )
|
||||
|
@ -70,7 +71,6 @@ extern int _t_isprint( const char *ptr );
|
|||
#define t_iseq(x,c) ( TOUCHAR(x) == ((unsigned char)(c)) )
|
||||
|
||||
#define COPYCHAR(d,s) TOUCHAR(d) = TOUCHAR(s)
|
||||
|
||||
#endif
|
||||
|
||||
char *lowerstr(char *str);
|
||||
|
|
|
@ -477,7 +477,8 @@ ts_stat_sql(text *txt, text *ws)
|
|||
buf = VARDATA(ws);
|
||||
while (buf - VARDATA(ws) < VARSIZE(ws) - VARHDRSZ)
|
||||
{
|
||||
if ( pg_mblen(buf) == 1 ) {
|
||||
if (pg_mblen(buf) == 1)
|
||||
{
|
||||
switch (*buf)
|
||||
{
|
||||
case 'A':
|
||||
|
|
|
@ -271,7 +271,8 @@ gettoken_tsvector(TI_IN_STATE * state)
|
|||
}
|
||||
else if (state->state == WAITENDCMPLX)
|
||||
{
|
||||
if ( t_iseq(state->prsbuf, '\'') ) {
|
||||
if (t_iseq(state->prsbuf, '\''))
|
||||
{
|
||||
state->state = WAITCHARCMPLX;
|
||||
}
|
||||
else if (t_iseq(state->prsbuf, '\\'))
|
||||
|
@ -298,7 +299,9 @@ gettoken_tsvector(TI_IN_STATE * state)
|
|||
COPYCHAR(state->curpos, state->prsbuf);
|
||||
state->curpos += pg_mblen(state->prsbuf);
|
||||
state->state = WAITENDCMPLX;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
RESIZEPRSBUF;
|
||||
*(state->curpos) = '\0';
|
||||
if (state->curpos == state->word)
|
||||
|
@ -517,7 +520,8 @@ tsvector_out(PG_FUNCTION_ARGS)
|
|||
lenbuf = 0,
|
||||
pp;
|
||||
WordEntry *ptr = ARRPTR(out);
|
||||
char *curbegin, *curin,
|
||||
char *curbegin,
|
||||
*curin,
|
||||
*curout;
|
||||
|
||||
lenbuf = out->size * 2 /* '' */ + out->size - 1 /* space */ + 2 /* \0 */ ;
|
||||
|
@ -538,6 +542,7 @@ tsvector_out(PG_FUNCTION_ARGS)
|
|||
while (curin - curbegin < ptr->len)
|
||||
{
|
||||
int len = pg_mblen(curin);
|
||||
|
||||
if (t_iseq(curin, '\''))
|
||||
{
|
||||
int4 pos = curout - outbuf;
|
||||
|
@ -987,14 +992,22 @@ silly_cmp_tsvector(const tsvector * a, const tsvector * b)
|
|||
int res;
|
||||
|
||||
|
||||
for(i=0;i<a->size;i++) {
|
||||
if ( aptr->haspos != bptr->haspos ) {
|
||||
for (i = 0; i < a->size; i++)
|
||||
{
|
||||
if (aptr->haspos != bptr->haspos)
|
||||
{
|
||||
return (aptr->haspos > bptr->haspos) ? -1 : 1;
|
||||
} else if ( aptr->len != bptr->len ) {
|
||||
}
|
||||
else if (aptr->len != bptr->len)
|
||||
{
|
||||
return (aptr->len > bptr->len) ? -1 : 1;
|
||||
} else if ( (res=strncmp(STRPTR(a) + aptr->pos, STRPTR(b) + bptr->pos, bptr->len))!= 0 ) {
|
||||
}
|
||||
else if ((res = strncmp(STRPTR(a) + aptr->pos, STRPTR(b) + bptr->pos, bptr->len)) != 0)
|
||||
{
|
||||
return res;
|
||||
} else if ( aptr->haspos ) {
|
||||
}
|
||||
else if (aptr->haspos)
|
||||
{
|
||||
WordEntryPos *ap = POSDATAPTR(a, aptr);
|
||||
WordEntryPos *bp = POSDATAPTR(b, bptr);
|
||||
int j;
|
||||
|
@ -1002,17 +1015,22 @@ silly_cmp_tsvector(const tsvector * a, const tsvector * b)
|
|||
if (POSDATALEN(a, aptr) != POSDATALEN(b, bptr))
|
||||
return (POSDATALEN(a, aptr) > POSDATALEN(b, bptr)) ? -1 : 1;
|
||||
|
||||
for(j=0;j<POSDATALEN(a, aptr);j++) {
|
||||
if ( WEP_GETPOS(*ap) != WEP_GETPOS(*bp) ) {
|
||||
for (j = 0; j < POSDATALEN(a, aptr); j++)
|
||||
{
|
||||
if (WEP_GETPOS(*ap) != WEP_GETPOS(*bp))
|
||||
{
|
||||
return (WEP_GETPOS(*ap) > WEP_GETPOS(*bp)) ? -1 : 1;
|
||||
} else if ( WEP_GETWEIGHT(*ap) != WEP_GETWEIGHT(*bp) ) {
|
||||
}
|
||||
else if (WEP_GETWEIGHT(*ap) != WEP_GETWEIGHT(*bp))
|
||||
{
|
||||
return (WEP_GETWEIGHT(*ap) > WEP_GETWEIGHT(*bp)) ? -1 : 1;
|
||||
}
|
||||
ap++, bp++;
|
||||
}
|
||||
}
|
||||
|
||||
aptr++; bptr++;
|
||||
aptr++;
|
||||
bptr++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $PostgreSQL: pgsql/contrib/tsearch2/wordparser/parser.c,v 1.10 2006/03/11 04:38:30 momjian Exp $ */
|
||||
/* $PostgreSQL: pgsql/contrib/tsearch2/wordparser/parser.c,v 1.11 2006/10/04 00:29:47 momjian Exp $ */
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.110 2006/07/14 14:52:16 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.111 2006/10/04 00:29:47 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.98 2006/08/12 02:52:03 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/common/printtup.c,v 1.99 2006/10/04 00:29:47 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -127,8 +127,8 @@ printtup_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
|
|||
}
|
||||
|
||||
/*
|
||||
* If we are supposed to emit row descriptions,
|
||||
* then send the tuple descriptor of the tuples.
|
||||
* If we are supposed to emit row descriptions, then send the tuple
|
||||
* descriptor of the tuples.
|
||||
*/
|
||||
if (myState->sendDescrip)
|
||||
SendRowDescriptionMessage(typeinfo,
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/common/reloptions.c,v 1.1 2006/07/03 22:45:36 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/common/reloptions.c,v 1.2 2006/10/04 00:29:47 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -96,9 +96,9 @@ transformRelOptions(Datum oldOptions, List *defList,
|
|||
}
|
||||
|
||||
/*
|
||||
* If CREATE/SET, add new options to array; if RESET, just check that
|
||||
* the user didn't say RESET (option=val). (Must do this because the
|
||||
* grammar doesn't enforce it.)
|
||||
* If CREATE/SET, add new options to array; if RESET, just check that the
|
||||
* user didn't say RESET (option=val). (Must do this because the grammar
|
||||
* doesn't enforce it.)
|
||||
*/
|
||||
foreach(cell, defList)
|
||||
{
|
||||
|
@ -121,8 +121,8 @@ transformRelOptions(Datum oldOptions, List *defList,
|
|||
continue;
|
||||
|
||||
/*
|
||||
* Flatten the DefElem into a text string like "name=arg".
|
||||
* If we have just "name", assume "name=true" is meant.
|
||||
* Flatten the DefElem into a text string like "name=arg". If we
|
||||
* have just "name", assume "name=true" is meant.
|
||||
*/
|
||||
if (def->arg != NULL)
|
||||
value = defGetString(def);
|
||||
|
@ -249,8 +249,8 @@ default_reloptions(Datum reloptions, bool validate,
|
|||
|
||||
/*
|
||||
* If no options, we can just return NULL rather than doing anything.
|
||||
* (defaultFillfactor is thus not used, but we require callers to pass
|
||||
* it anyway since we would need it if more options were added.)
|
||||
* (defaultFillfactor is thus not used, but we require callers to pass it
|
||||
* anyway since we would need it if more options were added.)
|
||||
*/
|
||||
if (values[0] == NULL)
|
||||
return NULL;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/ginarrayproc.c,v 1.5 2006/09/10 20:14:20 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/ginarrayproc.c,v 1.6 2006/10/04 00:29:47 momjian Exp $
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
@ -35,7 +35,8 @@
|
|||
* Function used as extractValue and extractQuery both
|
||||
*/
|
||||
Datum
|
||||
ginarrayextract(PG_FUNCTION_ARGS) {
|
||||
ginarrayextract(PG_FUNCTION_ARGS)
|
||||
{
|
||||
ArrayType *array;
|
||||
uint32 *nentries = (uint32 *) PG_GETARG_POINTER(1);
|
||||
Datum *entries = NULL;
|
||||
|
@ -43,7 +44,10 @@ ginarrayextract(PG_FUNCTION_ARGS) {
|
|||
bool elmbyval;
|
||||
char elmalign;
|
||||
|
||||
/* we should guarantee that array will not be destroyed during all operation */
|
||||
/*
|
||||
* we should guarantee that array will not be destroyed during all
|
||||
* operation
|
||||
*/
|
||||
array = PG_GETARG_ARRAYTYPE_P_COPY(0);
|
||||
|
||||
ARRAYCHECK(array);
|
||||
|
@ -61,15 +65,19 @@ ginarrayextract(PG_FUNCTION_ARGS) {
|
|||
}
|
||||
|
||||
Datum
|
||||
ginarrayconsistent(PG_FUNCTION_ARGS) {
|
||||
ginarrayconsistent(PG_FUNCTION_ARGS)
|
||||
{
|
||||
bool *check = (bool *) PG_GETARG_POINTER(0);
|
||||
StrategyNumber strategy = PG_GETARG_UINT16(1);
|
||||
ArrayType *query = PG_GETARG_ARRAYTYPE_P(2);
|
||||
int res, i, nentries;
|
||||
int res,
|
||||
i,
|
||||
nentries;
|
||||
|
||||
/* ARRAYCHECK was already done by previous ginarrayextract call */
|
||||
|
||||
switch( strategy ) {
|
||||
switch (strategy)
|
||||
{
|
||||
case GinOverlapStrategy:
|
||||
case GinContainedStrategy:
|
||||
/* at least one element in check[] is true, so result = true */
|
||||
|
@ -80,7 +88,8 @@ ginarrayconsistent(PG_FUNCTION_ARGS) {
|
|||
nentries = ArrayGetNItems(ARR_NDIM(query), ARR_DIMS(query));
|
||||
res = TRUE;
|
||||
for (i = 0; i < nentries; i++)
|
||||
if ( !check[i] ) {
|
||||
if (!check[i])
|
||||
{
|
||||
res = FALSE;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/ginbtree.c,v 1.4 2006/07/14 14:52:16 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/ginbtree.c,v 1.5 2006/10/04 00:29:47 momjian Exp $
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
@ -20,24 +20,29 @@
|
|||
* Locks buffer by needed method for search.
|
||||
*/
|
||||
static int
|
||||
ginTraverseLock(Buffer buffer, bool searchMode) {
|
||||
ginTraverseLock(Buffer buffer, bool searchMode)
|
||||
{
|
||||
Page page;
|
||||
int access = GIN_SHARE;
|
||||
|
||||
LockBuffer(buffer, GIN_SHARE);
|
||||
page = BufferGetPage(buffer);
|
||||
if ( GinPageIsLeaf(page) ) {
|
||||
if ( searchMode == FALSE ) {
|
||||
if (GinPageIsLeaf(page))
|
||||
{
|
||||
if (searchMode == FALSE)
|
||||
{
|
||||
/* we should relock our page */
|
||||
LockBuffer(buffer, GIN_UNLOCK);
|
||||
LockBuffer(buffer, GIN_EXCLUSIVE);
|
||||
|
||||
/* But root can become non-leaf during relock */
|
||||
if ( !GinPageIsLeaf(page) ) {
|
||||
if (!GinPageIsLeaf(page))
|
||||
{
|
||||
/* resore old lock type (very rare) */
|
||||
LockBuffer(buffer, GIN_UNLOCK);
|
||||
LockBuffer(buffer, GIN_SHARE);
|
||||
} else
|
||||
}
|
||||
else
|
||||
access = GIN_EXCLUSIVE;
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +51,8 @@ ginTraverseLock(Buffer buffer, bool searchMode) {
|
|||
}
|
||||
|
||||
GinBtreeStack *
|
||||
ginPrepareFindLeafPage(GinBtree btree, BlockNumber blkno) {
|
||||
ginPrepareFindLeafPage(GinBtree btree, BlockNumber blkno)
|
||||
{
|
||||
GinBtreeStack *stack = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
|
||||
|
||||
stack->blkno = blkno;
|
||||
|
@ -63,7 +69,8 @@ ginPrepareFindLeafPage(GinBtree btree, BlockNumber blkno) {
|
|||
* Locates leaf page contained tuple
|
||||
*/
|
||||
GinBtreeStack *
|
||||
ginFindLeafPage(GinBtree btree, GinBtreeStack *stack) {
|
||||
ginFindLeafPage(GinBtree btree, GinBtreeStack *stack)
|
||||
{
|
||||
bool isfirst = TRUE;
|
||||
BlockNumber rootBlkno;
|
||||
|
||||
|
@ -71,7 +78,8 @@ ginFindLeafPage(GinBtree btree, GinBtreeStack *stack) {
|
|||
stack = ginPrepareFindLeafPage(btree, GIN_ROOT_BLKNO);
|
||||
rootBlkno = stack->blkno;
|
||||
|
||||
for(;;) {
|
||||
for (;;)
|
||||
{
|
||||
Page page;
|
||||
BlockNumber child;
|
||||
int access = GIN_SHARE;
|
||||
|
@ -80,16 +88,21 @@ ginFindLeafPage(GinBtree btree, GinBtreeStack *stack) {
|
|||
|
||||
page = BufferGetPage(stack->buffer);
|
||||
|
||||
if ( isfirst ) {
|
||||
if (isfirst)
|
||||
{
|
||||
if (GinPageIsLeaf(page) && !btree->searchMode)
|
||||
access = GIN_EXCLUSIVE;
|
||||
isfirst = FALSE;
|
||||
} else
|
||||
}
|
||||
else
|
||||
access = ginTraverseLock(stack->buffer, btree->searchMode);
|
||||
|
||||
/* ok, page is correctly locked, we should check to move right ..,
|
||||
root never has a right link, so small optimization */
|
||||
while( btree->fullScan==FALSE && stack->blkno != rootBlkno && btree->isMoveRight(btree, page) ) {
|
||||
/*
|
||||
* ok, page is correctly locked, we should check to move right ..,
|
||||
* root never has a right link, so small optimization
|
||||
*/
|
||||
while (btree->fullScan == FALSE && stack->blkno != rootBlkno && btree->isMoveRight(btree, page))
|
||||
{
|
||||
BlockNumber rightlink = GinPageGetOpaque(page)->rightlink;
|
||||
|
||||
if (rightlink == InvalidBlockNumber)
|
||||
|
@ -113,11 +126,14 @@ ginFindLeafPage(GinBtree btree, GinBtreeStack *stack) {
|
|||
Assert(child != InvalidBlockNumber);
|
||||
Assert(stack->blkno != child);
|
||||
|
||||
if ( btree->searchMode ) {
|
||||
if (btree->searchMode)
|
||||
{
|
||||
/* in search mode we may forget path to leaf */
|
||||
stack->blkno = child;
|
||||
stack->buffer = ReleaseAndReadBuffer(stack->buffer, btree->index, stack->blkno);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
GinBtreeStack *ptr = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
|
||||
|
||||
ptr->parent = stack;
|
||||
|
@ -133,9 +149,12 @@ ginFindLeafPage(GinBtree btree, GinBtreeStack *stack) {
|
|||
}
|
||||
|
||||
void
|
||||
freeGinBtreeStack( GinBtreeStack *stack ) {
|
||||
while(stack) {
|
||||
freeGinBtreeStack(GinBtreeStack *stack)
|
||||
{
|
||||
while (stack)
|
||||
{
|
||||
GinBtreeStack *tmp = stack->parent;
|
||||
|
||||
if (stack->buffer != InvalidBuffer)
|
||||
ReleaseBuffer(stack->buffer);
|
||||
|
||||
|
@ -152,25 +171,34 @@ freeGinBtreeStack( GinBtreeStack *stack ) {
|
|||
*/
|
||||
void
|
||||
findParents(GinBtree btree, GinBtreeStack *stack,
|
||||
BlockNumber rootBlkno) {
|
||||
BlockNumber rootBlkno)
|
||||
{
|
||||
|
||||
Page page;
|
||||
Buffer buffer;
|
||||
BlockNumber blkno, leftmostBlkno;
|
||||
BlockNumber blkno,
|
||||
leftmostBlkno;
|
||||
OffsetNumber offset;
|
||||
GinBtreeStack *root = stack->parent;
|
||||
GinBtreeStack *ptr;
|
||||
|
||||
if ( !root ) {
|
||||
if (!root)
|
||||
{
|
||||
/* XLog mode... */
|
||||
root = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
|
||||
root->blkno = rootBlkno;
|
||||
root->buffer = ReadBuffer(btree->index, rootBlkno);
|
||||
LockBuffer(root->buffer, GIN_EXCLUSIVE);
|
||||
root->parent = NULL;
|
||||
} else {
|
||||
/* find root, we should not release root page until update is finished!! */
|
||||
while( root->parent ) {
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* find root, we should not release root page until update is
|
||||
* finished!!
|
||||
*/
|
||||
while (root->parent)
|
||||
{
|
||||
ReleaseBuffer(root->buffer);
|
||||
root = root->parent;
|
||||
}
|
||||
|
@ -185,7 +213,8 @@ findParents( GinBtree btree, GinBtreeStack *stack,
|
|||
Assert(!GinPageIsLeaf(page));
|
||||
|
||||
/* check trivial case */
|
||||
if ( (root->off = btree->findChildPtr(btree, page, stack->blkno, InvalidOffsetNumber)) != InvalidOffsetNumber ) {
|
||||
if ((root->off = btree->findChildPtr(btree, page, stack->blkno, InvalidOffsetNumber)) != InvalidOffsetNumber)
|
||||
{
|
||||
stack->parent = root;
|
||||
return;
|
||||
}
|
||||
|
@ -195,7 +224,8 @@ findParents( GinBtree btree, GinBtreeStack *stack,
|
|||
Assert(blkno != InvalidBlockNumber);
|
||||
|
||||
|
||||
for(;;) {
|
||||
for (;;)
|
||||
{
|
||||
buffer = ReadBuffer(btree->index, blkno);
|
||||
LockBuffer(buffer, GIN_EXCLUSIVE);
|
||||
page = BufferGetPage(buffer);
|
||||
|
@ -204,7 +234,8 @@ findParents( GinBtree btree, GinBtreeStack *stack,
|
|||
|
||||
leftmostBlkno = btree->getLeftMostPage(btree, page);
|
||||
|
||||
while( (offset = btree->findChildPtr(btree, page, stack->blkno, InvalidOffsetNumber))==InvalidOffsetNumber ) {
|
||||
while ((offset = btree->findChildPtr(btree, page, stack->blkno, InvalidOffsetNumber)) == InvalidOffsetNumber)
|
||||
{
|
||||
blkno = GinPageGetOpaque(page)->rightlink;
|
||||
LockBuffer(buffer, GIN_UNLOCK);
|
||||
ReleaseBuffer(buffer);
|
||||
|
@ -215,11 +246,13 @@ findParents( GinBtree btree, GinBtreeStack *stack,
|
|||
page = BufferGetPage(buffer);
|
||||
}
|
||||
|
||||
if ( blkno != InvalidBlockNumber ) {
|
||||
if (blkno != InvalidBlockNumber)
|
||||
{
|
||||
ptr = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
|
||||
ptr->blkno = blkno;
|
||||
ptr->buffer = buffer;
|
||||
ptr->parent = root; /* it's may be wrong, but in next call we will correct */
|
||||
ptr->parent = root; /* it's may be wrong, but in next call we will
|
||||
* correct */
|
||||
ptr->off = offset;
|
||||
stack->parent = ptr;
|
||||
return;
|
||||
|
@ -233,29 +266,36 @@ findParents( GinBtree btree, GinBtreeStack *stack,
|
|||
* Insert value (stored in GinBtree) to tree descibed by stack
|
||||
*/
|
||||
void
|
||||
ginInsertValue(GinBtree btree, GinBtreeStack *stack) {
|
||||
ginInsertValue(GinBtree btree, GinBtreeStack *stack)
|
||||
{
|
||||
GinBtreeStack *parent = stack;
|
||||
BlockNumber rootBlkno = InvalidBuffer;
|
||||
Page page, rpage, lpage;
|
||||
Page page,
|
||||
rpage,
|
||||
lpage;
|
||||
|
||||
/* remember root BlockNumber */
|
||||
while( parent ) {
|
||||
while (parent)
|
||||
{
|
||||
rootBlkno = parent->blkno;
|
||||
parent = parent->parent;
|
||||
}
|
||||
|
||||
while( stack ) {
|
||||
while (stack)
|
||||
{
|
||||
XLogRecData *rdata;
|
||||
BlockNumber savedRightLink;
|
||||
|
||||
page = BufferGetPage(stack->buffer);
|
||||
savedRightLink = GinPageGetOpaque(page)->rightlink;
|
||||
|
||||
if ( btree->isEnoughSpace( btree, stack->buffer, stack->off ) ) {
|
||||
if (btree->isEnoughSpace(btree, stack->buffer, stack->off))
|
||||
{
|
||||
START_CRIT_SECTION();
|
||||
btree->placeToPage(btree, stack->buffer, stack->off, &rdata);
|
||||
|
||||
if (!btree->index->rd_istemp) {
|
||||
if (!btree->index->rd_istemp)
|
||||
{
|
||||
XLogRecPtr recptr;
|
||||
|
||||
recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_INSERT, rdata);
|
||||
|
@ -269,12 +309,16 @@ ginInsertValue(GinBtree btree, GinBtreeStack *stack) {
|
|||
|
||||
freeGinBtreeStack(stack->parent);
|
||||
return;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer rbuffer = GinNewBuffer(btree->index);
|
||||
Page newlpage;
|
||||
|
||||
/* newlpage is a pointer to memory page, it does'nt assosiates with buffer,
|
||||
stack->buffer shoud be untouched */
|
||||
/*
|
||||
* newlpage is a pointer to memory page, it does'nt assosiates
|
||||
* with buffer, stack->buffer shoud be untouched
|
||||
*/
|
||||
newlpage = btree->splitPage(btree, stack->buffer, rbuffer, stack->off, &rdata);
|
||||
|
||||
|
||||
|
@ -282,9 +326,12 @@ ginInsertValue(GinBtree btree, GinBtreeStack *stack) {
|
|||
|
||||
parent = stack->parent;
|
||||
|
||||
if ( parent == NULL ) {
|
||||
/* split root, so we need to allocate new left page and
|
||||
place pointer on root to left and right page */
|
||||
if (parent == NULL)
|
||||
{
|
||||
/*
|
||||
* split root, so we need to allocate new left page and place
|
||||
* pointer on root to left and right page
|
||||
*/
|
||||
Buffer lbuffer = GinNewBuffer(btree->index);
|
||||
|
||||
((ginxlogSplit *) (rdata->data))->isRootSplit = TRUE;
|
||||
|
@ -304,7 +351,8 @@ ginInsertValue(GinBtree btree, GinBtreeStack *stack) {
|
|||
GinInitBuffer(stack->buffer, GinPageGetOpaque(newlpage)->flags & ~GIN_LEAF);
|
||||
PageRestoreTempPage(newlpage, lpage);
|
||||
btree->fillRoot(btree, stack->buffer, lbuffer, rbuffer);
|
||||
if (!btree->index->rd_istemp) {
|
||||
if (!btree->index->rd_istemp)
|
||||
{
|
||||
XLogRecPtr recptr;
|
||||
|
||||
recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_SPLIT, rdata);
|
||||
|
@ -326,7 +374,9 @@ ginInsertValue(GinBtree btree, GinBtreeStack *stack) {
|
|||
END_CRIT_SECTION();
|
||||
|
||||
return;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* split non-root page */
|
||||
((ginxlogSplit *) (rdata->data))->isRootSplit = FALSE;
|
||||
((ginxlogSplit *) (rdata->data))->rrlink = savedRightLink;
|
||||
|
@ -339,7 +389,8 @@ ginInsertValue(GinBtree btree, GinBtreeStack *stack) {
|
|||
|
||||
START_CRIT_SECTION();
|
||||
PageRestoreTempPage(newlpage, lpage);
|
||||
if (!btree->index->rd_istemp) {
|
||||
if (!btree->index->rd_istemp)
|
||||
{
|
||||
XLogRecPtr recptr;
|
||||
|
||||
recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_SPLIT, rdata);
|
||||
|
@ -362,14 +413,18 @@ ginInsertValue(GinBtree btree, GinBtreeStack *stack) {
|
|||
|
||||
/* move right if it's needed */
|
||||
page = BufferGetPage(parent->buffer);
|
||||
while( (parent->off=btree->findChildPtr(btree, page, stack->blkno, parent->off)) == InvalidOffsetNumber ) {
|
||||
while ((parent->off = btree->findChildPtr(btree, page, stack->blkno, parent->off)) == InvalidOffsetNumber)
|
||||
{
|
||||
BlockNumber rightlink = GinPageGetOpaque(page)->rightlink;
|
||||
|
||||
LockBuffer(parent->buffer, GIN_UNLOCK);
|
||||
|
||||
if ( rightlink==InvalidBlockNumber ) {
|
||||
/* rightmost page, but we don't find parent, we should
|
||||
use plain search... */
|
||||
if (rightlink == InvalidBlockNumber)
|
||||
{
|
||||
/*
|
||||
* rightmost page, but we don't find parent, we should use
|
||||
* plain search...
|
||||
*/
|
||||
findParents(btree, stack, rootBlkno);
|
||||
parent = stack->parent;
|
||||
page = BufferGetPage(parent->buffer);
|
||||
|
@ -387,5 +442,3 @@ ginInsertValue(GinBtree btree, GinBtreeStack *stack) {
|
|||
stack = parent;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/ginbulk.c,v 1.5 2006/08/29 14:05:44 teodor Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/ginbulk.c,v 1.6 2006/10/04 00:29:47 momjian Exp $
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
@ -22,7 +22,8 @@
|
|||
#define DEF_NPTR 4
|
||||
|
||||
void
|
||||
ginInitBA(BuildAccumulator *accum) {
|
||||
ginInitBA(BuildAccumulator *accum)
|
||||
{
|
||||
accum->maxdepth = 1;
|
||||
accum->stackpos = 0;
|
||||
accum->entries = NULL;
|
||||
|
@ -32,8 +33,10 @@ ginInitBA(BuildAccumulator *accum) {
|
|||
}
|
||||
|
||||
static EntryAccumulator *
|
||||
EAAllocate( BuildAccumulator *accum ) {
|
||||
if ( accum->entryallocator == NULL || accum->length>=DEF_NENTRY ) {
|
||||
EAAllocate(BuildAccumulator *accum)
|
||||
{
|
||||
if (accum->entryallocator == NULL || accum->length >= DEF_NENTRY)
|
||||
{
|
||||
accum->entryallocator = palloc(sizeof(EntryAccumulator) * DEF_NENTRY);
|
||||
accum->allocatedMemory += sizeof(EntryAccumulator) * DEF_NENTRY;
|
||||
accum->length = 0;
|
||||
|
@ -48,15 +51,18 @@ EAAllocate( BuildAccumulator *accum ) {
|
|||
* item pointer are ordered
|
||||
*/
|
||||
static void
|
||||
ginInsertData(BuildAccumulator *accum, EntryAccumulator *entry, ItemPointer heapptr) {
|
||||
if ( entry->number >= entry->length ) {
|
||||
ginInsertData(BuildAccumulator *accum, EntryAccumulator *entry, ItemPointer heapptr)
|
||||
{
|
||||
if (entry->number >= entry->length)
|
||||
{
|
||||
accum->allocatedMemory += sizeof(ItemPointerData) * entry->length;
|
||||
entry->length *= 2;
|
||||
entry->list = (ItemPointerData *) repalloc(entry->list,
|
||||
sizeof(ItemPointerData) * entry->length);
|
||||
}
|
||||
|
||||
if ( entry->shouldSort==FALSE ) {
|
||||
if (entry->shouldSort == FALSE)
|
||||
{
|
||||
int res = compareItemPointers(entry->list + entry->number - 1, heapptr);
|
||||
|
||||
Assert(res != 0);
|
||||
|
@ -74,7 +80,8 @@ ginInsertData(BuildAccumulator *accum, EntryAccumulator *entry, ItemPointer heap
|
|||
* to avoid computing the datum size twice.
|
||||
*/
|
||||
static Datum
|
||||
getDatumCopy(BuildAccumulator *accum, Datum value) {
|
||||
getDatumCopy(BuildAccumulator *accum, Datum value)
|
||||
{
|
||||
Form_pg_attribute *att = accum->ginstate->tupdesc->attrs;
|
||||
Datum res;
|
||||
|
||||
|
@ -100,16 +107,20 @@ getDatumCopy(BuildAccumulator *accum, Datum value) {
|
|||
* Find/store one entry from indexed value.
|
||||
*/
|
||||
static void
|
||||
ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr, Datum entry) {
|
||||
EntryAccumulator *ea = accum->entries, *pea = NULL;
|
||||
ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr, Datum entry)
|
||||
{
|
||||
EntryAccumulator *ea = accum->entries,
|
||||
*pea = NULL;
|
||||
int res = 0;
|
||||
uint32 depth = 1;
|
||||
|
||||
while( ea ) {
|
||||
while (ea)
|
||||
{
|
||||
res = compareEntries(accum->ginstate, entry, ea->value);
|
||||
if (res == 0)
|
||||
break; /* found */
|
||||
else {
|
||||
else
|
||||
{
|
||||
pea = ea;
|
||||
if (res < 0)
|
||||
ea = ea->left;
|
||||
|
@ -122,7 +133,8 @@ ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr, Datum entry) {
|
|||
if (depth > accum->maxdepth)
|
||||
accum->maxdepth = depth;
|
||||
|
||||
if ( ea == NULL ) {
|
||||
if (ea == NULL)
|
||||
{
|
||||
ea = EAAllocate(accum);
|
||||
|
||||
ea->left = ea->right = NULL;
|
||||
|
@ -136,14 +148,16 @@ ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr, Datum entry) {
|
|||
|
||||
if (pea == NULL)
|
||||
accum->entries = ea;
|
||||
else {
|
||||
else
|
||||
{
|
||||
Assert(res != 0);
|
||||
if (res < 0)
|
||||
pea->left = ea;
|
||||
else
|
||||
pea->right = ea;
|
||||
}
|
||||
} else
|
||||
}
|
||||
else
|
||||
ginInsertData(accum, ea, heapptr);
|
||||
}
|
||||
|
||||
|
@ -153,7 +167,8 @@ ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr, Datum entry) {
|
|||
*/
|
||||
static void
|
||||
ginChooseElem(BuildAccumulator *accum, ItemPointer heapptr, Datum *entries, uint32 nentry,
|
||||
uint32 low, uint32 high, uint32 offset) {
|
||||
uint32 low, uint32 high, uint32 offset)
|
||||
{
|
||||
uint32 pos;
|
||||
uint32 middle = (low + high) >> 1;
|
||||
|
||||
|
@ -176,14 +191,18 @@ ginChooseElem(BuildAccumulator *accum, ItemPointer heapptr, Datum *entries, uint
|
|||
* next middle on left part and middle of right part.
|
||||
*/
|
||||
void
|
||||
ginInsertRecordBA( BuildAccumulator *accum, ItemPointer heapptr, Datum *entries, uint32 nentry ) {
|
||||
uint32 i, nbit=0, offset;
|
||||
ginInsertRecordBA(BuildAccumulator *accum, ItemPointer heapptr, Datum *entries, uint32 nentry)
|
||||
{
|
||||
uint32 i,
|
||||
nbit = 0,
|
||||
offset;
|
||||
|
||||
if (nentry == 0)
|
||||
return;
|
||||
|
||||
i = nentry - 1;
|
||||
for(;i>0;i>>=1) nbit++;
|
||||
for (; i > 0; i >>= 1)
|
||||
nbit++;
|
||||
|
||||
nbit = 1 << nbit;
|
||||
offset = (nbit - nentry) / 2;
|
||||
|
@ -193,8 +212,10 @@ ginInsertRecordBA( BuildAccumulator *accum, ItemPointer heapptr, Datum *entries,
|
|||
}
|
||||
|
||||
static int
|
||||
qsortCompareItemPointers( const void *a, const void *b ) {
|
||||
qsortCompareItemPointers(const void *a, const void *b)
|
||||
{
|
||||
int res = compareItemPointers((ItemPointer) a, (ItemPointer) b);
|
||||
|
||||
Assert(res != 0);
|
||||
return res;
|
||||
}
|
||||
|
@ -203,27 +224,36 @@ qsortCompareItemPointers( const void *a, const void *b ) {
|
|||
* walk on binary tree and returns ordered nodes
|
||||
*/
|
||||
static EntryAccumulator *
|
||||
walkTree( BuildAccumulator *accum ) {
|
||||
walkTree(BuildAccumulator *accum)
|
||||
{
|
||||
EntryAccumulator *entry = accum->stack[accum->stackpos];
|
||||
|
||||
if ( entry->list != NULL ) {
|
||||
if (entry->list != NULL)
|
||||
{
|
||||
/* return entry itself: we already was at left sublink */
|
||||
return entry;
|
||||
} else if ( entry->right && entry->right != accum->stack[ accum->stackpos+1 ] ) {
|
||||
}
|
||||
else if (entry->right && entry->right != accum->stack[accum->stackpos + 1])
|
||||
{
|
||||
/* go on right sublink */
|
||||
accum->stackpos++;
|
||||
entry = entry->right;
|
||||
|
||||
/* find most-left value */
|
||||
for(;;) {
|
||||
for (;;)
|
||||
{
|
||||
accum->stack[accum->stackpos] = entry;
|
||||
if ( entry->left ) {
|
||||
if (entry->left)
|
||||
{
|
||||
accum->stackpos++;
|
||||
entry = entry->left;
|
||||
} else
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* we already return all left subtree, itself and right subtree */
|
||||
if (accum->stackpos == 0)
|
||||
return 0;
|
||||
|
@ -235,12 +265,14 @@ walkTree( BuildAccumulator *accum ) {
|
|||
}
|
||||
|
||||
ItemPointerData *
|
||||
ginGetEntry(BuildAccumulator *accum, Datum *value, uint32 *n) {
|
||||
ginGetEntry(BuildAccumulator *accum, Datum *value, uint32 *n)
|
||||
{
|
||||
EntryAccumulator *entry;
|
||||
ItemPointerData *list;
|
||||
|
||||
|
||||
if ( accum->stack == NULL ) {
|
||||
if (accum->stack == NULL)
|
||||
{
|
||||
/* first call */
|
||||
accum->stack = palloc0(sizeof(EntryAccumulator *) * (accum->maxdepth + 1));
|
||||
entry = accum->entries;
|
||||
|
@ -249,15 +281,20 @@ ginGetEntry(BuildAccumulator *accum, Datum *value, uint32 *n) {
|
|||
return NULL;
|
||||
|
||||
/* find most-left value */
|
||||
for(;;) {
|
||||
for (;;)
|
||||
{
|
||||
accum->stack[accum->stackpos] = entry;
|
||||
if ( entry->left ) {
|
||||
if (entry->left)
|
||||
{
|
||||
accum->stackpos++;
|
||||
entry = entry->left;
|
||||
} else
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
pfree(accum->stack[accum->stackpos]->list);
|
||||
accum->stack[accum->stackpos]->list = NULL;
|
||||
entry = walkTree(accum);
|
||||
|
@ -277,4 +314,3 @@ ginGetEntry(BuildAccumulator *accum, Datum *value, uint32 *n) {
|
|||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/gindatapage.c,v 1.3 2006/07/16 00:52:05 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/gindatapage.c,v 1.4 2006/10/04 00:29:47 momjian Exp $
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
@ -16,8 +16,10 @@
|
|||
#include "access/gin.h"
|
||||
|
||||
int
|
||||
compareItemPointers( ItemPointer a, ItemPointer b ) {
|
||||
if ( GinItemPointerGetBlockNumber(a) == GinItemPointerGetBlockNumber(b) ) {
|
||||
compareItemPointers(ItemPointer a, ItemPointer b)
|
||||
{
|
||||
if (GinItemPointerGetBlockNumber(a) == GinItemPointerGetBlockNumber(b))
|
||||
{
|
||||
if (GinItemPointerGetOffsetNumber(a) == GinItemPointerGetOffsetNumber(b))
|
||||
return 0;
|
||||
return (GinItemPointerGetOffsetNumber(a) > GinItemPointerGetOffsetNumber(b)) ? 1 : -1;
|
||||
|
@ -30,11 +32,14 @@ compareItemPointers( ItemPointer a, ItemPointer b ) {
|
|||
* Merge two ordered array of itempointer
|
||||
*/
|
||||
void
|
||||
MergeItemPointers(ItemPointerData *dst, ItemPointerData *a, uint32 na, ItemPointerData *b, uint32 nb) {
|
||||
MergeItemPointers(ItemPointerData *dst, ItemPointerData *a, uint32 na, ItemPointerData *b, uint32 nb)
|
||||
{
|
||||
ItemPointerData *dptr = dst;
|
||||
ItemPointerData *aptr = a, *bptr = b;
|
||||
ItemPointerData *aptr = a,
|
||||
*bptr = b;
|
||||
|
||||
while( aptr - a < na && bptr - b < nb ) {
|
||||
while (aptr - a < na && bptr - b < nb)
|
||||
{
|
||||
if (compareItemPointers(aptr, bptr) > 0)
|
||||
*dptr++ = *bptr++;
|
||||
else
|
||||
|
@ -53,7 +58,8 @@ MergeItemPointers(ItemPointerData *dst, ItemPointerData *a, uint32 na, ItemPoint
|
|||
* Compares inserting itemp pointer with right bound of current page
|
||||
*/
|
||||
static bool
|
||||
dataIsMoveRight(GinBtree btree, Page page) {
|
||||
dataIsMoveRight(GinBtree btree, Page page)
|
||||
{
|
||||
ItemPointer iptr = GinDataPageGetRightBound(page);
|
||||
|
||||
if (GinPageRightMost(page))
|
||||
|
@ -67,8 +73,11 @@ dataIsMoveRight(GinBtree btree, Page page) {
|
|||
* page correctly choosen and searching value SHOULD be on page
|
||||
*/
|
||||
static BlockNumber
|
||||
dataLocateItem(GinBtree btree, GinBtreeStack *stack) {
|
||||
OffsetNumber low, high, maxoff;
|
||||
dataLocateItem(GinBtree btree, GinBtreeStack *stack)
|
||||
{
|
||||
OffsetNumber low,
|
||||
high,
|
||||
maxoff;
|
||||
PostingItem *pitem = NULL;
|
||||
int result;
|
||||
Page page = BufferGetPage(stack->buffer);
|
||||
|
@ -76,7 +85,8 @@ dataLocateItem(GinBtree btree, GinBtreeStack *stack) {
|
|||
Assert(!GinPageIsLeaf(page));
|
||||
Assert(GinPageIsData(page));
|
||||
|
||||
if ( btree->fullScan ) {
|
||||
if (btree->fullScan)
|
||||
{
|
||||
stack->off = FirstOffsetNumber;
|
||||
stack->predictNumber *= GinPageGetOpaque(page)->maxoff;
|
||||
return btree->getLeftMostPage(btree, page);
|
||||
|
@ -88,23 +98,31 @@ dataLocateItem(GinBtree btree, GinBtreeStack *stack) {
|
|||
|
||||
high++;
|
||||
|
||||
while (high > low) {
|
||||
while (high > low)
|
||||
{
|
||||
OffsetNumber mid = low + ((high - low) / 2);
|
||||
|
||||
pitem = (PostingItem *) GinDataPageGetItem(page, mid);
|
||||
|
||||
if (mid == maxoff)
|
||||
/* Right infinity, page already correctly choosen
|
||||
with a help of dataIsMoveRight */
|
||||
|
||||
/*
|
||||
* Right infinity, page already correctly choosen with a help of
|
||||
* dataIsMoveRight
|
||||
*/
|
||||
result = -1;
|
||||
else {
|
||||
else
|
||||
{
|
||||
pitem = (PostingItem *) GinDataPageGetItem(page, mid);
|
||||
result = compareItemPointers(btree->items + btree->curitem, &(pitem->key));
|
||||
}
|
||||
|
||||
if ( result == 0 ) {
|
||||
if (result == 0)
|
||||
{
|
||||
stack->off = mid;
|
||||
return PostingItemGetBlockNumber(pitem);
|
||||
} else if ( result > 0 )
|
||||
}
|
||||
else if (result > 0)
|
||||
low = mid + 1;
|
||||
else
|
||||
high = mid;
|
||||
|
@ -123,15 +141,18 @@ dataLocateItem(GinBtree btree, GinBtreeStack *stack) {
|
|||
* Returns true if value found on page.
|
||||
*/
|
||||
static bool
|
||||
dataLocateLeafItem(GinBtree btree, GinBtreeStack *stack) {
|
||||
dataLocateLeafItem(GinBtree btree, GinBtreeStack *stack)
|
||||
{
|
||||
Page page = BufferGetPage(stack->buffer);
|
||||
OffsetNumber low, high;
|
||||
OffsetNumber low,
|
||||
high;
|
||||
int result;
|
||||
|
||||
Assert(GinPageIsLeaf(page));
|
||||
Assert(GinPageIsData(page));
|
||||
|
||||
if ( btree->fullScan ) {
|
||||
if (btree->fullScan)
|
||||
{
|
||||
stack->off = FirstOffsetNumber;
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -139,22 +160,26 @@ dataLocateLeafItem(GinBtree btree, GinBtreeStack *stack) {
|
|||
low = FirstOffsetNumber;
|
||||
high = GinPageGetOpaque(page)->maxoff;
|
||||
|
||||
if ( high < low ) {
|
||||
if (high < low)
|
||||
{
|
||||
stack->off = FirstOffsetNumber;
|
||||
return false;
|
||||
}
|
||||
|
||||
high++;
|
||||
|
||||
while (high > low) {
|
||||
while (high > low)
|
||||
{
|
||||
OffsetNumber mid = low + ((high - low) / 2);
|
||||
|
||||
result = compareItemPointers(btree->items + btree->curitem, (ItemPointer) GinDataPageGetItem(page, mid));
|
||||
|
||||
if ( result == 0 ) {
|
||||
if (result == 0)
|
||||
{
|
||||
stack->off = mid;
|
||||
return true;
|
||||
} else if ( result > 0 )
|
||||
}
|
||||
else if (result > 0)
|
||||
low = mid + 1;
|
||||
else
|
||||
high = mid;
|
||||
|
@ -169,22 +194,28 @@ dataLocateLeafItem(GinBtree btree, GinBtreeStack *stack) {
|
|||
* offset of PostingItem
|
||||
*/
|
||||
static OffsetNumber
|
||||
dataFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber storedOff) {
|
||||
OffsetNumber i, maxoff = GinPageGetOpaque(page)->maxoff;
|
||||
dataFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber storedOff)
|
||||
{
|
||||
OffsetNumber i,
|
||||
maxoff = GinPageGetOpaque(page)->maxoff;
|
||||
PostingItem *pitem;
|
||||
|
||||
Assert(!GinPageIsLeaf(page));
|
||||
Assert(GinPageIsData(page));
|
||||
|
||||
/* if page isn't changed, we returns storedOff */
|
||||
if ( storedOff>= FirstOffsetNumber && storedOff<=maxoff) {
|
||||
if (storedOff >= FirstOffsetNumber && storedOff <= maxoff)
|
||||
{
|
||||
pitem = (PostingItem *) GinDataPageGetItem(page, storedOff);
|
||||
if (PostingItemGetBlockNumber(pitem) == blkno)
|
||||
return storedOff;
|
||||
|
||||
/* we hope, that needed pointer goes to right. It's true
|
||||
if there wasn't a deletion */
|
||||
for( i=storedOff+1 ; i <= maxoff ; i++ ) {
|
||||
/*
|
||||
* we hope, that needed pointer goes to right. It's true if there
|
||||
* wasn't a deletion
|
||||
*/
|
||||
for (i = storedOff + 1; i <= maxoff; i++)
|
||||
{
|
||||
pitem = (PostingItem *) GinDataPageGetItem(page, i);
|
||||
if (PostingItemGetBlockNumber(pitem) == blkno)
|
||||
return i;
|
||||
|
@ -194,7 +225,8 @@ dataFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber stor
|
|||
}
|
||||
|
||||
/* last chance */
|
||||
for( i=FirstOffsetNumber; i <= maxoff ; i++ ) {
|
||||
for (i = FirstOffsetNumber; i <= maxoff; i++)
|
||||
{
|
||||
pitem = (PostingItem *) GinDataPageGetItem(page, i);
|
||||
if (PostingItemGetBlockNumber(pitem) == blkno)
|
||||
return i;
|
||||
|
@ -207,7 +239,8 @@ dataFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber stor
|
|||
* retunrs blkno of lefmost child
|
||||
*/
|
||||
static BlockNumber
|
||||
dataGetLeftMostPage(GinBtree btree, Page page) {
|
||||
dataGetLeftMostPage(GinBtree btree, Page page)
|
||||
{
|
||||
PostingItem *pitem;
|
||||
|
||||
Assert(!GinPageIsLeaf(page));
|
||||
|
@ -223,13 +256,17 @@ dataGetLeftMostPage(GinBtree btree, Page page) {
|
|||
* correct value! depending on leaf or non-leaf page
|
||||
*/
|
||||
void
|
||||
GinDataPageAddItem( Page page, void *data, OffsetNumber offset ) {
|
||||
GinDataPageAddItem(Page page, void *data, OffsetNumber offset)
|
||||
{
|
||||
OffsetNumber maxoff = GinPageGetOpaque(page)->maxoff;
|
||||
char *ptr;
|
||||
|
||||
if ( offset == InvalidOffsetNumber ) {
|
||||
if (offset == InvalidOffsetNumber)
|
||||
{
|
||||
ptr = GinDataPageGetItem(page, maxoff + 1);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = GinDataPageGetItem(page, offset);
|
||||
if (maxoff + 1 - offset != 0)
|
||||
memmove(ptr + GinSizeOfItem(page), ptr, (maxoff - offset + 1) * GinSizeOfItem(page));
|
||||
|
@ -243,7 +280,8 @@ GinDataPageAddItem( Page page, void *data, OffsetNumber offset ) {
|
|||
* Deletes posting item from non-leaf page
|
||||
*/
|
||||
void
|
||||
PageDeletePostingItem(Page page, OffsetNumber offset) {
|
||||
PageDeletePostingItem(Page page, OffsetNumber offset)
|
||||
{
|
||||
OffsetNumber maxoff = GinPageGetOpaque(page)->maxoff;
|
||||
|
||||
Assert(!GinPageIsLeaf(page));
|
||||
|
@ -261,19 +299,24 @@ PageDeletePostingItem(Page page, OffsetNumber offset) {
|
|||
* item pointer never deletes!
|
||||
*/
|
||||
static bool
|
||||
dataIsEnoughSpace( GinBtree btree, Buffer buf, OffsetNumber off ) {
|
||||
dataIsEnoughSpace(GinBtree btree, Buffer buf, OffsetNumber off)
|
||||
{
|
||||
Page page = BufferGetPage(buf);
|
||||
|
||||
Assert(GinPageIsData(page));
|
||||
Assert(!btree->isDelete);
|
||||
|
||||
if ( GinPageIsLeaf(page) ) {
|
||||
if ( GinPageRightMost(page) && off > GinPageGetOpaque(page)->maxoff ) {
|
||||
if (GinPageIsLeaf(page))
|
||||
{
|
||||
if (GinPageRightMost(page) && off > GinPageGetOpaque(page)->maxoff)
|
||||
{
|
||||
if ((btree->nitem - btree->curitem) * sizeof(ItemPointerData) <= GinDataPageGetFreeSpace(page))
|
||||
return true;
|
||||
} else if ( sizeof(ItemPointerData) <= GinDataPageGetFreeSpace(page) )
|
||||
}
|
||||
else if (sizeof(ItemPointerData) <= GinDataPageGetFreeSpace(page))
|
||||
return true;
|
||||
} else if ( sizeof(PostingItem) <= GinDataPageGetFreeSpace(page) )
|
||||
}
|
||||
else if (sizeof(PostingItem) <= GinDataPageGetFreeSpace(page))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
@ -285,13 +328,16 @@ dataIsEnoughSpace( GinBtree btree, Buffer buf, OffsetNumber off ) {
|
|||
* item pointer never deletes!
|
||||
*/
|
||||
static BlockNumber
|
||||
dataPrepareData( GinBtree btree, Page page, OffsetNumber off) {
|
||||
dataPrepareData(GinBtree btree, Page page, OffsetNumber off)
|
||||
{
|
||||
BlockNumber ret = InvalidBlockNumber;
|
||||
|
||||
Assert(GinPageIsData(page));
|
||||
|
||||
if ( !GinPageIsLeaf(page) && btree->rightblkno != InvalidBlockNumber ) {
|
||||
if (!GinPageIsLeaf(page) && btree->rightblkno != InvalidBlockNumber)
|
||||
{
|
||||
PostingItem *pitem = (PostingItem *) GinDataPageGetItem(page, off);
|
||||
|
||||
PostingItemSetBlockNumber(pitem, btree->rightblkno);
|
||||
ret = btree->rightblkno;
|
||||
}
|
||||
|
@ -306,7 +352,8 @@ dataPrepareData( GinBtree btree, Page page, OffsetNumber off) {
|
|||
* build mode puts all ItemPointers to page.
|
||||
*/
|
||||
static void
|
||||
dataPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prdata) {
|
||||
dataPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prdata)
|
||||
{
|
||||
Page page = BufferGetPage(buf);
|
||||
static XLogRecData rdata[3];
|
||||
int sizeofitem = GinSizeOfItem(page);
|
||||
|
@ -341,23 +388,29 @@ dataPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prda
|
|||
rdata[2].len = sizeofitem;
|
||||
rdata[2].next = NULL;
|
||||
|
||||
if ( GinPageIsLeaf(page) ) {
|
||||
if ( GinPageRightMost(page) && off > GinPageGetOpaque(page)->maxoff ) {
|
||||
if (GinPageIsLeaf(page))
|
||||
{
|
||||
if (GinPageRightMost(page) && off > GinPageGetOpaque(page)->maxoff)
|
||||
{
|
||||
/* usually, create index... */
|
||||
uint32 savedPos = btree->curitem;
|
||||
|
||||
while( btree->curitem < btree->nitem ) {
|
||||
while (btree->curitem < btree->nitem)
|
||||
{
|
||||
GinDataPageAddItem(page, btree->items + btree->curitem, off);
|
||||
off++;
|
||||
btree->curitem++;
|
||||
}
|
||||
data.nitem = btree->curitem - savedPos;
|
||||
rdata[2].len = sizeofitem * data.nitem;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
GinDataPageAddItem(page, btree->items + btree->curitem, off);
|
||||
btree->curitem++;
|
||||
}
|
||||
} else
|
||||
}
|
||||
else
|
||||
GinDataPageAddItem(page, &(btree->pitem), off);
|
||||
}
|
||||
|
||||
|
@ -368,7 +421,8 @@ dataPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prda
|
|||
* left page
|
||||
*/
|
||||
static Page
|
||||
dataSplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogRecData **prdata) {
|
||||
dataSplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogRecData **prdata)
|
||||
{
|
||||
static ginxlogSplit data;
|
||||
static XLogRecData rdata[4];
|
||||
static char vector[2 * BLCKSZ];
|
||||
|
@ -395,30 +449,38 @@ dataSplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogRe
|
|||
memcpy(vector, GinDataPageGetItem(lpage, FirstOffsetNumber),
|
||||
maxoff * sizeofitem);
|
||||
|
||||
if ( GinPageIsLeaf(lpage) && GinPageRightMost(lpage) && off > GinPageGetOpaque(lpage)->maxoff ) {
|
||||
if (GinPageIsLeaf(lpage) && GinPageRightMost(lpage) && off > GinPageGetOpaque(lpage)->maxoff)
|
||||
{
|
||||
nCopied = 0;
|
||||
while( btree->curitem < btree->nitem && maxoff*sizeof(ItemPointerData) < 2*(freeSpace - sizeof(ItemPointerData)) ) {
|
||||
while (btree->curitem < btree->nitem && maxoff * sizeof(ItemPointerData) < 2 * (freeSpace - sizeof(ItemPointerData)))
|
||||
{
|
||||
memcpy(vector + maxoff * sizeof(ItemPointerData), btree->items + btree->curitem,
|
||||
sizeof(ItemPointerData));
|
||||
maxoff++;
|
||||
nCopied++;
|
||||
btree->curitem++;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = vector + (off - 1) * sizeofitem;
|
||||
if (maxoff + 1 - off != 0)
|
||||
memmove(ptr + sizeofitem, ptr, (maxoff - off + 1) * sizeofitem);
|
||||
if ( GinPageIsLeaf(lpage) ) {
|
||||
if (GinPageIsLeaf(lpage))
|
||||
{
|
||||
memcpy(ptr, btree->items + btree->curitem, sizeofitem);
|
||||
btree->curitem++;
|
||||
} else
|
||||
}
|
||||
else
|
||||
memcpy(ptr, &(btree->pitem), sizeofitem);
|
||||
|
||||
maxoff++;
|
||||
}
|
||||
|
||||
/* we suppose that during index creation table scaned from
|
||||
begin to end, so ItemPointers are monotonically increased.. */
|
||||
/*
|
||||
* we suppose that during index creation table scaned from begin to end,
|
||||
* so ItemPointers are monotonically increased..
|
||||
*/
|
||||
if (btree->isBuild && GinPageRightMost(lpage))
|
||||
separator = freeSpace / sizeofitem;
|
||||
else
|
||||
|
@ -479,11 +541,13 @@ dataSplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogRe
|
|||
* Also called from ginxlog, should not use btree
|
||||
*/
|
||||
void
|
||||
dataFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf) {
|
||||
dataFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf)
|
||||
{
|
||||
Page page = BufferGetPage(root),
|
||||
lpage = BufferGetPage(lbuf),
|
||||
rpage = BufferGetPage(rbuf);
|
||||
PostingItem li, ri;
|
||||
PostingItem li,
|
||||
ri;
|
||||
|
||||
li.key = *GinDataPageGetRightBound(lpage);
|
||||
PostingItemSetBlockNumber(&li, BufferGetBlockNumber(lbuf));
|
||||
|
@ -495,7 +559,8 @@ dataFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf) {
|
|||
}
|
||||
|
||||
void
|
||||
prepareDataScan( GinBtree btree, Relation index) {
|
||||
prepareDataScan(GinBtree btree, Relation index)
|
||||
{
|
||||
memset(btree, 0, sizeof(GinBtreeData));
|
||||
btree->index = index;
|
||||
btree->isMoveRight = dataIsMoveRight;
|
||||
|
@ -515,7 +580,8 @@ prepareDataScan( GinBtree btree, Relation index) {
|
|||
}
|
||||
|
||||
GinPostingTreeScan *
|
||||
prepareScanPostingTree( Relation index, BlockNumber rootBlkno, bool searchMode) {
|
||||
prepareScanPostingTree(Relation index, BlockNumber rootBlkno, bool searchMode)
|
||||
{
|
||||
GinPostingTreeScan *gdi = (GinPostingTreeScan *) palloc0(sizeof(GinPostingTreeScan));
|
||||
|
||||
prepareDataScan(&gdi->btree, index);
|
||||
|
@ -532,14 +598,16 @@ prepareScanPostingTree( Relation index, BlockNumber rootBlkno, bool searchMode)
|
|||
* Inserts array of item pointers, may execute several tree scan (very rare)
|
||||
*/
|
||||
void
|
||||
insertItemPointer(GinPostingTreeScan *gdi, ItemPointerData *items, uint32 nitem) {
|
||||
insertItemPointer(GinPostingTreeScan *gdi, ItemPointerData *items, uint32 nitem)
|
||||
{
|
||||
BlockNumber rootBlkno = gdi->stack->blkno;
|
||||
|
||||
gdi->btree.items = items;
|
||||
gdi->btree.nitem = nitem;
|
||||
gdi->btree.curitem = 0;
|
||||
|
||||
while( gdi->btree.curitem < gdi->btree.nitem ) {
|
||||
while (gdi->btree.curitem < gdi->btree.nitem)
|
||||
{
|
||||
if (!gdi->stack)
|
||||
gdi->stack = ginPrepareFindLeafPage(&gdi->btree, rootBlkno);
|
||||
|
||||
|
@ -557,8 +625,8 @@ insertItemPointer(GinPostingTreeScan *gdi, ItemPointerData *items, uint32 nitem)
|
|||
}
|
||||
|
||||
Buffer
|
||||
scanBeginPostingTree( GinPostingTreeScan *gdi ) {
|
||||
scanBeginPostingTree(GinPostingTreeScan *gdi)
|
||||
{
|
||||
gdi->stack = ginFindLeafPage(&gdi->btree, gdi->stack);
|
||||
return gdi->stack->buffer;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/ginentrypage.c,v 1.3 2006/07/14 14:52:16 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/ginentrypage.c,v 1.4 2006/10/04 00:29:47 momjian Exp $
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
@ -37,7 +37,8 @@
|
|||
* - ItemPointerGetOffsetNumber(&itup->t_tid) contains magick number GIN_TREE_POSTING
|
||||
*/
|
||||
IndexTuple
|
||||
GinFormTuple(GinState *ginstate, Datum key, ItemPointerData *ipd, uint32 nipd) {
|
||||
GinFormTuple(GinState *ginstate, Datum key, ItemPointerData *ipd, uint32 nipd)
|
||||
{
|
||||
bool isnull = FALSE;
|
||||
IndexTuple itup;
|
||||
|
||||
|
@ -45,7 +46,8 @@ GinFormTuple(GinState *ginstate, Datum key, ItemPointerData *ipd, uint32 nipd) {
|
|||
|
||||
GinSetOrigSizePosting(itup, IndexTupleSize(itup));
|
||||
|
||||
if ( nipd > 0 ) {
|
||||
if (nipd > 0)
|
||||
{
|
||||
uint32 newsize = MAXALIGN(SHORTALIGN(IndexTupleSize(itup)) + sizeof(ItemPointerData) * nipd);
|
||||
|
||||
if (newsize >= INDEX_SIZE_MASK)
|
||||
|
@ -63,7 +65,9 @@ GinFormTuple(GinState *ginstate, Datum key, ItemPointerData *ipd, uint32 nipd) {
|
|||
if (ipd)
|
||||
memcpy(GinGetPosting(itup), ipd, sizeof(ItemPointerData) * nipd);
|
||||
GinSetNPosting(itup, nipd);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
GinSetNPosting(itup, 0);
|
||||
}
|
||||
return itup;
|
||||
|
@ -74,13 +78,16 @@ GinFormTuple(GinState *ginstate, Datum key, ItemPointerData *ipd, uint32 nipd) {
|
|||
* so we don't use right bound, we use rightest key instead.
|
||||
*/
|
||||
static IndexTuple
|
||||
getRightMostTuple(Page page) {
|
||||
getRightMostTuple(Page page)
|
||||
{
|
||||
OffsetNumber maxoff = PageGetMaxOffsetNumber(page);
|
||||
|
||||
return (IndexTuple) PageGetItem(page, PageGetItemId(page, maxoff));
|
||||
}
|
||||
|
||||
Datum
|
||||
ginGetHighKey(GinState *ginstate, Page page) {
|
||||
ginGetHighKey(GinState *ginstate, Page page)
|
||||
{
|
||||
IndexTuple itup;
|
||||
bool isnull;
|
||||
|
||||
|
@ -90,7 +97,8 @@ ginGetHighKey(GinState *ginstate, Page page) {
|
|||
}
|
||||
|
||||
static bool
|
||||
entryIsMoveRight(GinBtree btree, Page page) {
|
||||
entryIsMoveRight(GinBtree btree, Page page)
|
||||
{
|
||||
Datum highkey;
|
||||
|
||||
if (GinPageRightMost(page))
|
||||
|
@ -109,8 +117,11 @@ entryIsMoveRight(GinBtree btree, Page page) {
|
|||
* page correctly choosen and searching value SHOULD be on page
|
||||
*/
|
||||
static BlockNumber
|
||||
entryLocateEntry(GinBtree btree, GinBtreeStack *stack) {
|
||||
OffsetNumber low, high, maxoff;
|
||||
entryLocateEntry(GinBtree btree, GinBtreeStack *stack)
|
||||
{
|
||||
OffsetNumber low,
|
||||
high,
|
||||
maxoff;
|
||||
IndexTuple itup = NULL;
|
||||
int result;
|
||||
Page page = BufferGetPage(stack->buffer);
|
||||
|
@ -118,7 +129,8 @@ entryLocateEntry(GinBtree btree, GinBtreeStack *stack) {
|
|||
Assert(!GinPageIsLeaf(page));
|
||||
Assert(!GinPageIsData(page));
|
||||
|
||||
if ( btree->fullScan ) {
|
||||
if (btree->fullScan)
|
||||
{
|
||||
stack->off = FirstOffsetNumber;
|
||||
stack->predictNumber *= PageGetMaxOffsetNumber(page);
|
||||
return btree->getLeftMostPage(btree, page);
|
||||
|
@ -130,13 +142,15 @@ entryLocateEntry(GinBtree btree, GinBtreeStack *stack) {
|
|||
|
||||
high++;
|
||||
|
||||
while (high > low) {
|
||||
while (high > low)
|
||||
{
|
||||
OffsetNumber mid = low + ((high - low) / 2);
|
||||
|
||||
if (mid == maxoff && GinPageRightMost(page))
|
||||
/* Right infinity */
|
||||
result = -1;
|
||||
else {
|
||||
else
|
||||
{
|
||||
bool isnull;
|
||||
|
||||
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, mid));
|
||||
|
@ -144,11 +158,13 @@ entryLocateEntry(GinBtree btree, GinBtreeStack *stack) {
|
|||
index_getattr(itup, FirstOffsetNumber, btree->ginstate->tupdesc, &isnull));
|
||||
}
|
||||
|
||||
if ( result == 0 ) {
|
||||
if (result == 0)
|
||||
{
|
||||
stack->off = mid;
|
||||
Assert(GinItemPointerGetBlockNumber(&(itup)->t_tid) != GIN_ROOT_BLKNO);
|
||||
return GinItemPointerGetBlockNumber(&(itup)->t_tid);
|
||||
} else if ( result > 0 )
|
||||
}
|
||||
else if (result > 0)
|
||||
low = mid + 1;
|
||||
else
|
||||
high = mid;
|
||||
|
@ -168,15 +184,18 @@ entryLocateEntry(GinBtree btree, GinBtreeStack *stack) {
|
|||
* Returns true if value found on page.
|
||||
*/
|
||||
static bool
|
||||
entryLocateLeafEntry(GinBtree btree, GinBtreeStack *stack) {
|
||||
entryLocateLeafEntry(GinBtree btree, GinBtreeStack *stack)
|
||||
{
|
||||
Page page = BufferGetPage(stack->buffer);
|
||||
OffsetNumber low, high;
|
||||
OffsetNumber low,
|
||||
high;
|
||||
IndexTuple itup;
|
||||
|
||||
Assert(GinPageIsLeaf(page));
|
||||
Assert(!GinPageIsData(page));
|
||||
|
||||
if ( btree->fullScan ) {
|
||||
if (btree->fullScan)
|
||||
{
|
||||
stack->off = FirstOffsetNumber;
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -184,14 +203,16 @@ entryLocateLeafEntry(GinBtree btree, GinBtreeStack *stack) {
|
|||
low = FirstOffsetNumber;
|
||||
high = PageGetMaxOffsetNumber(page);
|
||||
|
||||
if ( high < low ) {
|
||||
if (high < low)
|
||||
{
|
||||
stack->off = FirstOffsetNumber;
|
||||
return false;
|
||||
}
|
||||
|
||||
high++;
|
||||
|
||||
while (high > low) {
|
||||
while (high > low)
|
||||
{
|
||||
OffsetNumber mid = low + ((high - low) / 2);
|
||||
bool isnull;
|
||||
int result;
|
||||
|
@ -200,10 +221,12 @@ entryLocateLeafEntry(GinBtree btree, GinBtreeStack *stack) {
|
|||
result = compareEntries(btree->ginstate, btree->entryValue,
|
||||
index_getattr(itup, FirstOffsetNumber, btree->ginstate->tupdesc, &isnull));
|
||||
|
||||
if ( result == 0 ) {
|
||||
if (result == 0)
|
||||
{
|
||||
stack->off = mid;
|
||||
return true;
|
||||
} else if ( result > 0 )
|
||||
}
|
||||
else if (result > 0)
|
||||
low = mid + 1;
|
||||
else
|
||||
high = mid;
|
||||
|
@ -214,22 +237,28 @@ entryLocateLeafEntry(GinBtree btree, GinBtreeStack *stack) {
|
|||
}
|
||||
|
||||
static OffsetNumber
|
||||
entryFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber storedOff) {
|
||||
OffsetNumber i, maxoff = PageGetMaxOffsetNumber(page);
|
||||
entryFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber storedOff)
|
||||
{
|
||||
OffsetNumber i,
|
||||
maxoff = PageGetMaxOffsetNumber(page);
|
||||
IndexTuple itup;
|
||||
|
||||
Assert(!GinPageIsLeaf(page));
|
||||
Assert(!GinPageIsData(page));
|
||||
|
||||
/* if page isn't changed, we returns storedOff */
|
||||
if ( storedOff>= FirstOffsetNumber && storedOff<=maxoff) {
|
||||
if (storedOff >= FirstOffsetNumber && storedOff <= maxoff)
|
||||
{
|
||||
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, storedOff));
|
||||
if (GinItemPointerGetBlockNumber(&(itup)->t_tid) == blkno)
|
||||
return storedOff;
|
||||
|
||||
/* we hope, that needed pointer goes to right. It's true
|
||||
if there wasn't a deletion */
|
||||
for( i=storedOff+1 ; i <= maxoff ; i++ ) {
|
||||
/*
|
||||
* we hope, that needed pointer goes to right. It's true if there
|
||||
* wasn't a deletion
|
||||
*/
|
||||
for (i = storedOff + 1; i <= maxoff; i++)
|
||||
{
|
||||
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
|
||||
if (GinItemPointerGetBlockNumber(&(itup)->t_tid) == blkno)
|
||||
return i;
|
||||
|
@ -238,7 +267,8 @@ entryFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber sto
|
|||
}
|
||||
|
||||
/* last chance */
|
||||
for( i=FirstOffsetNumber; i <= maxoff ; i++ ) {
|
||||
for (i = FirstOffsetNumber; i <= maxoff; i++)
|
||||
{
|
||||
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
|
||||
if (GinItemPointerGetBlockNumber(&(itup)->t_tid) == blkno)
|
||||
return i;
|
||||
|
@ -248,7 +278,8 @@ entryFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber sto
|
|||
}
|
||||
|
||||
static BlockNumber
|
||||
entryGetLeftMostPage(GinBtree btree, Page page) {
|
||||
entryGetLeftMostPage(GinBtree btree, Page page)
|
||||
{
|
||||
IndexTuple itup;
|
||||
|
||||
Assert(!GinPageIsLeaf(page));
|
||||
|
@ -260,15 +291,18 @@ entryGetLeftMostPage(GinBtree btree, Page page) {
|
|||
}
|
||||
|
||||
static bool
|
||||
entryIsEnoughSpace( GinBtree btree, Buffer buf, OffsetNumber off ) {
|
||||
entryIsEnoughSpace(GinBtree btree, Buffer buf, OffsetNumber off)
|
||||
{
|
||||
Size itupsz = 0;
|
||||
Page page = BufferGetPage(buf);
|
||||
|
||||
Assert(btree->entry);
|
||||
Assert(!GinPageIsData(page));
|
||||
|
||||
if ( btree->isDelete ) {
|
||||
if (btree->isDelete)
|
||||
{
|
||||
IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, off));
|
||||
|
||||
itupsz = MAXALIGN(IndexTupleSize(itup)) + sizeof(ItemIdData);
|
||||
}
|
||||
|
||||
|
@ -284,19 +318,23 @@ entryIsEnoughSpace( GinBtree btree, Buffer buf, OffsetNumber off ) {
|
|||
* if child split is occured
|
||||
*/
|
||||
static BlockNumber
|
||||
entryPreparePage( GinBtree btree, Page page, OffsetNumber off) {
|
||||
entryPreparePage(GinBtree btree, Page page, OffsetNumber off)
|
||||
{
|
||||
BlockNumber ret = InvalidBlockNumber;
|
||||
|
||||
Assert(btree->entry);
|
||||
Assert(!GinPageIsData(page));
|
||||
|
||||
if ( btree->isDelete ) {
|
||||
if (btree->isDelete)
|
||||
{
|
||||
Assert(GinPageIsLeaf(page));
|
||||
PageIndexTupleDelete(page, off);
|
||||
}
|
||||
|
||||
if ( !GinPageIsLeaf(page) && btree->rightblkno != InvalidBlockNumber ) {
|
||||
if (!GinPageIsLeaf(page) && btree->rightblkno != InvalidBlockNumber)
|
||||
{
|
||||
IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, off));
|
||||
|
||||
ItemPointerSet(&itup->t_tid, btree->rightblkno, InvalidOffsetNumber);
|
||||
ret = btree->rightblkno;
|
||||
}
|
||||
|
@ -310,7 +348,8 @@ entryPreparePage( GinBtree btree, Page page, OffsetNumber off) {
|
|||
* Place tuple on page and fills WAL record
|
||||
*/
|
||||
static void
|
||||
entryPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prdata) {
|
||||
entryPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prdata)
|
||||
{
|
||||
Page page = BufferGetPage(buf);
|
||||
static XLogRecData rdata[3];
|
||||
OffsetNumber placed;
|
||||
|
@ -358,14 +397,19 @@ entryPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prd
|
|||
* an equal number!
|
||||
*/
|
||||
static Page
|
||||
entrySplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogRecData **prdata) {
|
||||
entrySplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogRecData **prdata)
|
||||
{
|
||||
static XLogRecData rdata[2];
|
||||
OffsetNumber i, maxoff, separator=InvalidOffsetNumber;
|
||||
OffsetNumber i,
|
||||
maxoff,
|
||||
separator = InvalidOffsetNumber;
|
||||
Size totalsize = 0;
|
||||
Size lsize = 0, size;
|
||||
Size lsize = 0,
|
||||
size;
|
||||
static char tupstore[2 * BLCKSZ];
|
||||
char *ptr;
|
||||
IndexTuple itup, leftrightmost=NULL;
|
||||
IndexTuple itup,
|
||||
leftrightmost = NULL;
|
||||
static ginxlogSplit data;
|
||||
Datum value;
|
||||
bool isnull;
|
||||
|
@ -382,8 +426,10 @@ entrySplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogR
|
|||
maxoff = PageGetMaxOffsetNumber(lpage);
|
||||
ptr = tupstore;
|
||||
|
||||
for(i=FirstOffsetNumber; i<=maxoff; i++) {
|
||||
if ( i==off ) {
|
||||
for (i = FirstOffsetNumber; i <= maxoff; i++)
|
||||
{
|
||||
if (i == off)
|
||||
{
|
||||
size = MAXALIGN(IndexTupleSize(btree->entry));
|
||||
memcpy(ptr, btree->entry, size);
|
||||
ptr += size;
|
||||
|
@ -397,7 +443,8 @@ entrySplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogR
|
|||
totalsize += size + sizeof(ItemIdData);
|
||||
}
|
||||
|
||||
if ( off==maxoff+1 ) {
|
||||
if (off == maxoff + 1)
|
||||
{
|
||||
size = MAXALIGN(IndexTupleSize(btree->entry));
|
||||
memcpy(ptr, btree->entry, size);
|
||||
ptr += size;
|
||||
|
@ -412,14 +459,18 @@ entrySplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogR
|
|||
lsize = 0;
|
||||
|
||||
page = lpage;
|
||||
for(i=FirstOffsetNumber; i<=maxoff; i++) {
|
||||
for (i = FirstOffsetNumber; i <= maxoff; i++)
|
||||
{
|
||||
itup = (IndexTuple) ptr;
|
||||
|
||||
if ( lsize > totalsize/2 ) {
|
||||
if (lsize > totalsize / 2)
|
||||
{
|
||||
if (separator == InvalidOffsetNumber)
|
||||
separator = i - 1;
|
||||
page = rpage;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
leftrightmost = itup;
|
||||
lsize += MAXALIGN(IndexTupleSize(itup)) + sizeof(ItemIdData);
|
||||
}
|
||||
|
@ -462,17 +513,22 @@ entrySplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogR
|
|||
* return newly allocate rightmost tuple
|
||||
*/
|
||||
IndexTuple
|
||||
ginPageGetLinkItup(Buffer buf) {
|
||||
IndexTuple itup, nitup;
|
||||
ginPageGetLinkItup(Buffer buf)
|
||||
{
|
||||
IndexTuple itup,
|
||||
nitup;
|
||||
Page page = BufferGetPage(buf);
|
||||
|
||||
itup = getRightMostTuple(page);
|
||||
if ( GinPageIsLeaf(page) && !GinIsPostingTree(itup) ) {
|
||||
if (GinPageIsLeaf(page) && !GinIsPostingTree(itup))
|
||||
{
|
||||
nitup = (IndexTuple) palloc(MAXALIGN(GinGetOrigSizePosting(itup)));
|
||||
memcpy(nitup, itup, GinGetOrigSizePosting(itup));
|
||||
nitup->t_info &= ~INDEX_SIZE_MASK;
|
||||
nitup->t_info |= GinGetOrigSizePosting(itup);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
nitup = (IndexTuple) palloc(MAXALIGN(IndexTupleSize(itup)));
|
||||
memcpy(nitup, itup, IndexTupleSize(itup));
|
||||
}
|
||||
|
@ -486,7 +542,8 @@ ginPageGetLinkItup(Buffer buf) {
|
|||
* Also called from ginxlog, should not use btree
|
||||
*/
|
||||
void
|
||||
entryFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf) {
|
||||
entryFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf)
|
||||
{
|
||||
Page page;
|
||||
IndexTuple itup;
|
||||
|
||||
|
@ -502,7 +559,8 @@ entryFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf) {
|
|||
}
|
||||
|
||||
void
|
||||
prepareEntryScan( GinBtree btree, Relation index, Datum value, GinState *ginstate) {
|
||||
prepareEntryScan(GinBtree btree, Relation index, Datum value, GinState *ginstate)
|
||||
{
|
||||
memset(btree, 0, sizeof(GinBtreeData));
|
||||
|
||||
btree->isMoveRight = entryIsMoveRight;
|
||||
|
@ -524,4 +582,3 @@ prepareEntryScan( GinBtree btree, Relation index, Datum value, GinState *ginstat
|
|||
btree->fullScan = FALSE;
|
||||
btree->isBuild = FALSE;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/ginget.c,v 1.2 2006/07/14 14:52:16 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/ginget.c,v 1.3 2006/10/04 00:29:47 momjian Exp $
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
@ -18,11 +18,13 @@
|
|||
#include "utils/memutils.h"
|
||||
|
||||
static OffsetNumber
|
||||
findItemInPage( Page page, ItemPointer item, OffsetNumber off ) {
|
||||
findItemInPage(Page page, ItemPointer item, OffsetNumber off)
|
||||
{
|
||||
OffsetNumber maxoff = GinPageGetOpaque(page)->maxoff;
|
||||
int res;
|
||||
|
||||
for(; off<=maxoff; off++) {
|
||||
for (; off <= maxoff; off++)
|
||||
{
|
||||
res = compareItemPointers(item, (ItemPointer) GinDataPageGetItem(page, off));
|
||||
Assert(res >= 0);
|
||||
|
||||
|
@ -38,15 +40,20 @@ findItemInPage( Page page, ItemPointer item, OffsetNumber off ) {
|
|||
* Stop* functions unlock buffer (but don't release!)
|
||||
*/
|
||||
static void
|
||||
startScanEntry( Relation index, GinState *ginstate, GinScanEntry entry, bool firstCall ) {
|
||||
if ( entry->master != NULL ) {
|
||||
startScanEntry(Relation index, GinState *ginstate, GinScanEntry entry, bool firstCall)
|
||||
{
|
||||
if (entry->master != NULL)
|
||||
{
|
||||
entry->isFinished = entry->master->isFinished;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( firstCall ) {
|
||||
/* at first call we should find entry, and
|
||||
begin scan of posting tree or just store posting list in memory */
|
||||
if (firstCall)
|
||||
{
|
||||
/*
|
||||
* at first call we should find entry, and begin scan of posting tree
|
||||
* or just store posting list in memory
|
||||
*/
|
||||
GinBtreeData btreeEntry;
|
||||
GinBtreeStack *stackEntry;
|
||||
Page page;
|
||||
|
@ -65,10 +72,12 @@ startScanEntry( Relation index, GinState *ginstate, GinScanEntry entry, bool fir
|
|||
entry->reduceResult = FALSE;
|
||||
entry->predictNumberResult = 0;
|
||||
|
||||
if ( btreeEntry.findItem( &btreeEntry, stackEntry ) ) {
|
||||
if (btreeEntry.findItem(&btreeEntry, stackEntry))
|
||||
{
|
||||
IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, stackEntry->off));
|
||||
|
||||
if ( GinIsPostingTree(itup) ) {
|
||||
if (GinIsPostingTree(itup))
|
||||
{
|
||||
BlockNumber rootPostingTree = GinGetPostingTree(itup);
|
||||
GinPostingTreeScan *gdi;
|
||||
Page page;
|
||||
|
@ -86,7 +95,9 @@ startScanEntry( Relation index, GinState *ginstate, GinScanEntry entry, bool fir
|
|||
freeGinBtreeStack(gdi->stack);
|
||||
pfree(gdi);
|
||||
entry->isFinished = FALSE;
|
||||
} else if ( GinGetNPosting(itup) > 0 ) {
|
||||
}
|
||||
else if (GinGetNPosting(itup) > 0)
|
||||
{
|
||||
entry->nlist = GinGetNPosting(itup);
|
||||
entry->list = (ItemPointerData *) palloc(sizeof(ItemPointerData) * entry->nlist);
|
||||
memcpy(entry->list, GinGetPosting(itup), sizeof(ItemPointerData) * entry->nlist);
|
||||
|
@ -97,7 +108,9 @@ startScanEntry( Relation index, GinState *ginstate, GinScanEntry entry, bool fir
|
|||
if (needUnlock)
|
||||
LockBuffer(stackEntry->buffer, GIN_UNLOCK);
|
||||
freeGinBtreeStack(stackEntry);
|
||||
} else if ( entry->buffer != InvalidBuffer ) {
|
||||
}
|
||||
else if (entry->buffer != InvalidBuffer)
|
||||
{
|
||||
/* we should find place were we was stopped */
|
||||
BlockNumber blkno;
|
||||
Page page;
|
||||
|
@ -116,7 +129,8 @@ startScanEntry( Relation index, GinState *ginstate, GinScanEntry entry, bool fir
|
|||
return;
|
||||
|
||||
/* walk to right */
|
||||
while( (blkno = GinPageGetOpaque( page )->rightlink)!=InvalidBlockNumber ) {
|
||||
while ((blkno = GinPageGetOpaque(page)->rightlink) != InvalidBlockNumber)
|
||||
{
|
||||
LockBuffer(entry->buffer, GIN_UNLOCK);
|
||||
entry->buffer = ReleaseAndReadBuffer(entry->buffer, index, blkno);
|
||||
LockBuffer(entry->buffer, GIN_SHARE);
|
||||
|
@ -131,29 +145,33 @@ startScanEntry( Relation index, GinState *ginstate, GinScanEntry entry, bool fir
|
|||
}
|
||||
|
||||
static void
|
||||
stopScanEntry( GinScanEntry entry ) {
|
||||
stopScanEntry(GinScanEntry entry)
|
||||
{
|
||||
if (entry->buffer != InvalidBuffer)
|
||||
LockBuffer(entry->buffer, GIN_UNLOCK);
|
||||
}
|
||||
|
||||
static void
|
||||
startScanKey( Relation index, GinState *ginstate, GinScanKey key ) {
|
||||
startScanKey(Relation index, GinState *ginstate, GinScanKey key)
|
||||
{
|
||||
uint32 i;
|
||||
|
||||
for (i = 0; i < key->nentries; i++)
|
||||
startScanEntry(index, ginstate, key->scanEntry + i, key->firstCall);
|
||||
|
||||
if ( key->firstCall ) {
|
||||
if (key->firstCall)
|
||||
{
|
||||
memset(key->entryRes, TRUE, sizeof(bool) * key->nentries);
|
||||
key->isFinished = FALSE;
|
||||
key->firstCall = FALSE;
|
||||
|
||||
if ( GinFuzzySearchLimit > 0 ) {
|
||||
if (GinFuzzySearchLimit > 0)
|
||||
{
|
||||
/*
|
||||
* If all of keys more than treshold we will try to reduce
|
||||
* result, we hope (and only hope, for intersection operation of array
|
||||
* our supposition isn't true), that total result will not more
|
||||
* than minimal predictNumberResult.
|
||||
* If all of keys more than treshold we will try to reduce result,
|
||||
* we hope (and only hope, for intersection operation of array our
|
||||
* supposition isn't true), that total result will not more than
|
||||
* minimal predictNumberResult.
|
||||
*/
|
||||
|
||||
for (i = 0; i < key->nentries; i++)
|
||||
|
@ -161,7 +179,8 @@ startScanKey( Relation index, GinState *ginstate, GinScanKey key ) {
|
|||
return;
|
||||
|
||||
for (i = 0; i < key->nentries; i++)
|
||||
if ( key->scanEntry[i].predictNumberResult > key->nentries * GinFuzzySearchLimit ) {
|
||||
if (key->scanEntry[i].predictNumberResult > key->nentries * GinFuzzySearchLimit)
|
||||
{
|
||||
key->scanEntry[i].predictNumberResult /= key->nentries;
|
||||
key->scanEntry[i].reduceResult = TRUE;
|
||||
}
|
||||
|
@ -170,7 +189,8 @@ startScanKey( Relation index, GinState *ginstate, GinScanKey key ) {
|
|||
}
|
||||
|
||||
static void
|
||||
stopScanKey( GinScanKey key ) {
|
||||
stopScanKey(GinScanKey key)
|
||||
{
|
||||
uint32 i;
|
||||
|
||||
for (i = 0; i < key->nentries; i++)
|
||||
|
@ -178,7 +198,8 @@ stopScanKey( GinScanKey key ) {
|
|||
}
|
||||
|
||||
static void
|
||||
startScan( IndexScanDesc scan ) {
|
||||
startScan(IndexScanDesc scan)
|
||||
{
|
||||
uint32 i;
|
||||
GinScanOpaque so = (GinScanOpaque) scan->opaque;
|
||||
|
||||
|
@ -187,7 +208,8 @@ startScan( IndexScanDesc scan ) {
|
|||
}
|
||||
|
||||
static void
|
||||
stopScan( IndexScanDesc scan ) {
|
||||
stopScan(IndexScanDesc scan)
|
||||
{
|
||||
uint32 i;
|
||||
GinScanOpaque so = (GinScanOpaque) scan->opaque;
|
||||
|
||||
|
@ -197,21 +219,28 @@ stopScan( IndexScanDesc scan ) {
|
|||
|
||||
|
||||
static void
|
||||
entryGetNextItem( Relation index, GinScanEntry entry ) {
|
||||
entryGetNextItem(Relation index, GinScanEntry entry)
|
||||
{
|
||||
Page page = BufferGetPage(entry->buffer);
|
||||
|
||||
entry->offset++;
|
||||
if ( entry->offset <= GinPageGetOpaque( page )->maxoff && GinPageGetOpaque( page )->maxoff >= FirstOffsetNumber ) {
|
||||
if (entry->offset <= GinPageGetOpaque(page)->maxoff && GinPageGetOpaque(page)->maxoff >= FirstOffsetNumber)
|
||||
{
|
||||
entry->curItem = *(ItemPointerData *) GinDataPageGetItem(page, entry->offset);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
BlockNumber blkno = GinPageGetOpaque(page)->rightlink;
|
||||
|
||||
LockBuffer(entry->buffer, GIN_UNLOCK);
|
||||
if ( blkno == InvalidBlockNumber ) {
|
||||
if (blkno == InvalidBlockNumber)
|
||||
{
|
||||
ReleaseBuffer(entry->buffer);
|
||||
entry->buffer = InvalidBuffer;
|
||||
entry->isFinished = TRUE;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
entry->buffer = ReleaseAndReadBuffer(entry->buffer, index, blkno);
|
||||
LockBuffer(entry->buffer, GIN_SHARE);
|
||||
entry->offset = InvalidOffsetNumber;
|
||||
|
@ -228,20 +257,28 @@ entryGetNextItem( Relation index, GinScanEntry entry ) {
|
|||
* entry of one scan key
|
||||
*/
|
||||
static bool
|
||||
entryGetItem( Relation index, GinScanEntry entry ) {
|
||||
if ( entry->master ) {
|
||||
entryGetItem(Relation index, GinScanEntry entry)
|
||||
{
|
||||
if (entry->master)
|
||||
{
|
||||
entry->isFinished = entry->master->isFinished;
|
||||
entry->curItem = entry->master->curItem;
|
||||
} else if ( entry->list ) {
|
||||
}
|
||||
else if (entry->list)
|
||||
{
|
||||
entry->offset++;
|
||||
if (entry->offset <= entry->nlist)
|
||||
entry->curItem = entry->list[entry->offset - 1];
|
||||
else {
|
||||
else
|
||||
{
|
||||
ItemPointerSet(&entry->curItem, InvalidBlockNumber, InvalidOffsetNumber);
|
||||
entry->isFinished = TRUE;
|
||||
}
|
||||
} else {
|
||||
do {
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
entryGetNextItem(index, entry);
|
||||
} while (entry->isFinished == FALSE && entry->reduceResult == TRUE && dropItem(entry));
|
||||
}
|
||||
|
@ -254,7 +291,8 @@ entryGetItem( Relation index, GinScanEntry entry ) {
|
|||
* returns isFinished!
|
||||
*/
|
||||
static bool
|
||||
keyGetItem( Relation index, GinState *ginstate, MemoryContext tempCtx, GinScanKey key ) {
|
||||
keyGetItem(Relation index, GinState *ginstate, MemoryContext tempCtx, GinScanKey key)
|
||||
{
|
||||
uint32 i;
|
||||
GinScanEntry entry;
|
||||
bool res;
|
||||
|
@ -263,39 +301,51 @@ keyGetItem( Relation index, GinState *ginstate, MemoryContext tempCtx, GinScanKe
|
|||
if (key->isFinished)
|
||||
return TRUE;
|
||||
|
||||
do {
|
||||
/* move forward from previously value and set new curItem,
|
||||
which is minimal from entries->curItems */
|
||||
do
|
||||
{
|
||||
/*
|
||||
* move forward from previously value and set new curItem, which is
|
||||
* minimal from entries->curItems
|
||||
*/
|
||||
ItemPointerSetMax(&key->curItem);
|
||||
for(i=0;i<key->nentries;i++) {
|
||||
for (i = 0; i < key->nentries; i++)
|
||||
{
|
||||
entry = key->scanEntry + i;
|
||||
|
||||
if ( key->entryRes[i] ) {
|
||||
if ( entry->isFinished == FALSE && entryGetItem(index, entry) == FALSE ) {
|
||||
if (key->entryRes[i])
|
||||
{
|
||||
if (entry->isFinished == FALSE && entryGetItem(index, entry) == FALSE)
|
||||
{
|
||||
if (compareItemPointers(&entry->curItem, &key->curItem) < 0)
|
||||
key->curItem = entry->curItem;
|
||||
} else
|
||||
}
|
||||
else
|
||||
key->entryRes[i] = FALSE;
|
||||
} else if ( entry->isFinished == FALSE ) {
|
||||
}
|
||||
else if (entry->isFinished == FALSE)
|
||||
{
|
||||
if (compareItemPointers(&entry->curItem, &key->curItem) < 0)
|
||||
key->curItem = entry->curItem;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ItemPointerIsMax( &key->curItem ) ) {
|
||||
if (ItemPointerIsMax(&key->curItem))
|
||||
{
|
||||
/* all entries are finished */
|
||||
key->isFinished = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if ( key->nentries == 1 ) {
|
||||
if (key->nentries == 1)
|
||||
{
|
||||
/* we can do not call consistentFn !! */
|
||||
key->entryRes[0] = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* setting up array for consistentFn */
|
||||
for(i=0;i<key->nentries;i++) {
|
||||
for (i = 0; i < key->nentries; i++)
|
||||
{
|
||||
entry = key->scanEntry + i;
|
||||
|
||||
if (entry->isFinished == FALSE && compareItemPointers(&entry->curItem, &key->curItem) == 0)
|
||||
|
@ -323,33 +373,42 @@ keyGetItem( Relation index, GinState *ginstate, MemoryContext tempCtx, GinScanKe
|
|||
* returns true if found
|
||||
*/
|
||||
static bool
|
||||
scanGetItem( IndexScanDesc scan, ItemPointerData *item ) {
|
||||
scanGetItem(IndexScanDesc scan, ItemPointerData *item)
|
||||
{
|
||||
uint32 i;
|
||||
GinScanOpaque so = (GinScanOpaque) scan->opaque;
|
||||
|
||||
ItemPointerSetMin(item);
|
||||
for(i=0;i<so->nkeys;i++) {
|
||||
for (i = 0; i < so->nkeys; i++)
|
||||
{
|
||||
GinScanKey key = so->keys + i;
|
||||
|
||||
if ( keyGetItem( scan->indexRelation, &so->ginstate, so->tempCtx, key )==FALSE ) {
|
||||
if (keyGetItem(scan->indexRelation, &so->ginstate, so->tempCtx, key) == FALSE)
|
||||
{
|
||||
if (compareItemPointers(item, &key->curItem) < 0)
|
||||
*item = key->curItem;
|
||||
} else
|
||||
}
|
||||
else
|
||||
return FALSE; /* finshed one of keys */
|
||||
}
|
||||
|
||||
for(i=1;i<=so->nkeys;i++) {
|
||||
for (i = 1; i <= so->nkeys; i++)
|
||||
{
|
||||
GinScanKey key = so->keys + i - 1;
|
||||
|
||||
for(;;) {
|
||||
for (;;)
|
||||
{
|
||||
int cmp = compareItemPointers(item, &key->curItem);
|
||||
|
||||
if (cmp == 0)
|
||||
break;
|
||||
else if ( cmp > 0 ) {
|
||||
else if (cmp > 0)
|
||||
{
|
||||
if (keyGetItem(scan->indexRelation, &so->ginstate, so->tempCtx, key) == TRUE)
|
||||
return FALSE; /* finshed one of keys */
|
||||
} else { /* returns to begin */
|
||||
}
|
||||
else
|
||||
{ /* returns to begin */
|
||||
*item = key->curItem;
|
||||
i = 0;
|
||||
break;
|
||||
|
@ -363,7 +422,8 @@ scanGetItem( IndexScanDesc scan, ItemPointerData *item ) {
|
|||
#define GinIsNewKey(s) ( ((GinScanOpaque) scan->opaque)->keys == NULL )
|
||||
|
||||
Datum
|
||||
gingetmulti(PG_FUNCTION_ARGS) {
|
||||
gingetmulti(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
ItemPointer tids = (ItemPointer) PG_GETARG_POINTER(1);
|
||||
int32 max_tids = PG_GETARG_INT32(2);
|
||||
|
@ -376,7 +436,8 @@ gingetmulti(PG_FUNCTION_ARGS) {
|
|||
|
||||
*returned_tids = 0;
|
||||
|
||||
do {
|
||||
do
|
||||
{
|
||||
if (scanGetItem(scan, tids + *returned_tids))
|
||||
(*returned_tids)++;
|
||||
else
|
||||
|
@ -389,7 +450,8 @@ gingetmulti(PG_FUNCTION_ARGS) {
|
|||
}
|
||||
|
||||
Datum
|
||||
gingettuple(PG_FUNCTION_ARGS) {
|
||||
gingettuple(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1);
|
||||
bool res;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/gininsert.c,v 1.4 2006/07/14 14:52:16 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/gininsert.c,v 1.5 2006/10/04 00:29:47 momjian Exp $
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
@ -19,7 +19,8 @@
|
|||
#include "miscadmin.h"
|
||||
#include "utils/memutils.h"
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
GinState ginstate;
|
||||
double indtuples;
|
||||
MemoryContext tmpCtx;
|
||||
|
@ -32,7 +33,8 @@ typedef struct {
|
|||
* suppose that items[] fits to page
|
||||
*/
|
||||
static BlockNumber
|
||||
createPostingTree( Relation index, ItemPointerData *items, uint32 nitems ) {
|
||||
createPostingTree(Relation index, ItemPointerData *items, uint32 nitems)
|
||||
{
|
||||
BlockNumber blkno;
|
||||
Buffer buffer = GinNewBuffer(index);
|
||||
Page page;
|
||||
|
@ -46,7 +48,8 @@ createPostingTree( Relation index, ItemPointerData *items, uint32 nitems ) {
|
|||
memcpy(GinDataPageGetData(page), items, sizeof(ItemPointerData) * nitems);
|
||||
GinPageGetOpaque(page)->maxoff = nitems;
|
||||
|
||||
if (!index->rd_istemp) {
|
||||
if (!index->rd_istemp)
|
||||
{
|
||||
XLogRecPtr recptr;
|
||||
XLogRecData rdata[2];
|
||||
ginxlogCreatePostingTree data;
|
||||
|
@ -90,12 +93,14 @@ createPostingTree( Relation index, ItemPointerData *items, uint32 nitems ) {
|
|||
*/
|
||||
static IndexTuple
|
||||
addItemPointersToTuple(Relation index, GinState *ginstate, GinBtreeStack *stack,
|
||||
IndexTuple old, ItemPointerData *items, uint32 nitem, bool isBuild) {
|
||||
IndexTuple old, ItemPointerData *items, uint32 nitem, bool isBuild)
|
||||
{
|
||||
bool isnull;
|
||||
Datum key = index_getattr(old, FirstOffsetNumber, ginstate->tupdesc, &isnull);
|
||||
IndexTuple res = GinFormTuple(ginstate, key, NULL, nitem + GinGetNPosting(old));
|
||||
|
||||
if ( res ) {
|
||||
if (res)
|
||||
{
|
||||
/* good, small enough */
|
||||
MergeItemPointers(GinGetPosting(res),
|
||||
GinGetPosting(old), GinGetNPosting(old),
|
||||
|
@ -103,7 +108,9 @@ addItemPointersToTuple(Relation index, GinState *ginstate, GinBtreeStack *stack,
|
|||
);
|
||||
|
||||
GinSetNPosting(res, nitem + GinGetNPosting(old));
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
BlockNumber postingRoot;
|
||||
GinPostingTreeScan *gdi;
|
||||
|
||||
|
@ -128,7 +135,8 @@ addItemPointersToTuple(Relation index, GinState *ginstate, GinBtreeStack *stack,
|
|||
* ItemPointer.
|
||||
*/
|
||||
static void
|
||||
ginEntryInsert( Relation index, GinState *ginstate, Datum value, ItemPointerData *items, uint32 nitem, bool isBuild) {
|
||||
ginEntryInsert(Relation index, GinState *ginstate, Datum value, ItemPointerData *items, uint32 nitem, bool isBuild)
|
||||
{
|
||||
GinBtreeData btree;
|
||||
GinBtreeStack *stack;
|
||||
IndexTuple itup;
|
||||
|
@ -139,11 +147,13 @@ ginEntryInsert( Relation index, GinState *ginstate, Datum value, ItemPointerData
|
|||
stack = ginFindLeafPage(&btree, NULL);
|
||||
page = BufferGetPage(stack->buffer);
|
||||
|
||||
if ( btree.findItem( &btree, stack ) ) {
|
||||
if (btree.findItem(&btree, stack))
|
||||
{
|
||||
/* found entry */
|
||||
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, stack->off));
|
||||
|
||||
if ( GinIsPostingTree(itup) ) {
|
||||
if (GinIsPostingTree(itup))
|
||||
{
|
||||
/* lock root of posting tree */
|
||||
GinPostingTreeScan *gdi;
|
||||
BlockNumber rootPostingTree = GinGetPostingTree(itup);
|
||||
|
@ -163,13 +173,16 @@ ginEntryInsert( Relation index, GinState *ginstate, Datum value, ItemPointerData
|
|||
itup = addItemPointersToTuple(index, ginstate, stack, itup, items, nitem, isBuild);
|
||||
|
||||
btree.isDelete = TRUE;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We suppose, that tuple can store at list one itempointer */
|
||||
itup = GinFormTuple(ginstate, value, items, 1);
|
||||
if (itup == NULL || IndexTupleSize(itup) >= GinMaxItemSize)
|
||||
elog(ERROR, "huge tuple");
|
||||
|
||||
if ( nitem>1 ) {
|
||||
if (nitem > 1)
|
||||
{
|
||||
IndexTuple previtup = itup;
|
||||
|
||||
itup = addItemPointersToTuple(index, ginstate, stack, previtup, items + 1, nitem - 1, isBuild);
|
||||
|
@ -187,7 +200,8 @@ ginEntryInsert( Relation index, GinState *ginstate, Datum value, ItemPointerData
|
|||
* Function isnt use during normal insert
|
||||
*/
|
||||
static uint32
|
||||
ginHeapTupleBulkInsert(GinBuildState *buildstate, Datum value, ItemPointer heapptr) {
|
||||
ginHeapTupleBulkInsert(GinBuildState *buildstate, Datum value, ItemPointer heapptr)
|
||||
{
|
||||
Datum *entries;
|
||||
uint32 nentries;
|
||||
MemoryContext oldCtx;
|
||||
|
@ -209,7 +223,8 @@ ginHeapTupleBulkInsert(GinBuildState *buildstate, Datum value, ItemPointer heapp
|
|||
|
||||
static void
|
||||
ginBuildCallback(Relation index, HeapTuple htup, Datum *values,
|
||||
bool *isnull, bool tupleIsAlive, void *state) {
|
||||
bool *isnull, bool tupleIsAlive, void *state)
|
||||
{
|
||||
|
||||
GinBuildState *buildstate = (GinBuildState *) state;
|
||||
MemoryContext oldCtx;
|
||||
|
@ -221,9 +236,12 @@ ginBuildCallback(Relation index, HeapTuple htup, Datum *values,
|
|||
|
||||
buildstate->indtuples += ginHeapTupleBulkInsert(buildstate, *values, &htup->t_self);
|
||||
|
||||
/* we use only half maintenance_work_mem, because there is some leaks
|
||||
during insertion and extract values */
|
||||
if ( buildstate->accum.allocatedMemory >= maintenance_work_mem*1024L/2L ) {
|
||||
/*
|
||||
* we use only half maintenance_work_mem, because there is some leaks
|
||||
* during insertion and extract values
|
||||
*/
|
||||
if (buildstate->accum.allocatedMemory >= maintenance_work_mem * 1024L / 2L)
|
||||
{
|
||||
ItemPointerData *list;
|
||||
Datum entry;
|
||||
uint32 nlist;
|
||||
|
@ -239,7 +257,8 @@ ginBuildCallback(Relation index, HeapTuple htup, Datum *values,
|
|||
}
|
||||
|
||||
Datum
|
||||
ginbuild(PG_FUNCTION_ARGS) {
|
||||
ginbuild(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Relation heap = (Relation) PG_GETARG_POINTER(0);
|
||||
Relation index = (Relation) PG_GETARG_POINTER(1);
|
||||
IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
|
||||
|
@ -262,7 +281,8 @@ ginbuild(PG_FUNCTION_ARGS) {
|
|||
buffer = GinNewBuffer(index);
|
||||
START_CRIT_SECTION();
|
||||
GinInitBuffer(buffer, GIN_LEAF);
|
||||
if (!index->rd_istemp) {
|
||||
if (!index->rd_istemp)
|
||||
{
|
||||
XLogRecPtr recptr;
|
||||
XLogRecData rdata;
|
||||
Page page;
|
||||
|
@ -333,9 +353,11 @@ ginbuild(PG_FUNCTION_ARGS) {
|
|||
* Inserts value during normal insertion
|
||||
*/
|
||||
static uint32
|
||||
ginHeapTupleInsert( Relation index, GinState *ginstate, Datum value, ItemPointer item) {
|
||||
ginHeapTupleInsert(Relation index, GinState *ginstate, Datum value, ItemPointer item)
|
||||
{
|
||||
Datum *entries;
|
||||
uint32 i,nentries;
|
||||
uint32 i,
|
||||
nentries;
|
||||
|
||||
entries = extractEntriesSU(ginstate, value, &nentries);
|
||||
|
||||
|
@ -350,11 +372,13 @@ ginHeapTupleInsert( Relation index, GinState *ginstate, Datum value, ItemPointer
|
|||
}
|
||||
|
||||
Datum
|
||||
gininsert(PG_FUNCTION_ARGS) {
|
||||
gininsert(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Relation index = (Relation) PG_GETARG_POINTER(0);
|
||||
Datum *values = (Datum *) PG_GETARG_POINTER(1);
|
||||
bool *isnull = (bool *) PG_GETARG_POINTER(2);
|
||||
ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
|
||||
|
||||
#ifdef NOT_USED
|
||||
Relation heapRel = (Relation) PG_GETARG_POINTER(4);
|
||||
bool checkUnique = PG_GETARG_BOOL(5);
|
||||
|
@ -384,4 +408,3 @@ gininsert(PG_FUNCTION_ARGS) {
|
|||
|
||||
PG_RETURN_BOOL(res > 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/ginscan.c,v 1.5 2006/09/14 11:26:49 teodor Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/ginscan.c,v 1.6 2006/10/04 00:29:48 momjian Exp $
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
@ -20,7 +20,8 @@
|
|||
|
||||
|
||||
Datum
|
||||
ginbeginscan(PG_FUNCTION_ARGS) {
|
||||
ginbeginscan(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Relation rel = (Relation) PG_GETARG_POINTER(0);
|
||||
int keysz = PG_GETARG_INT32(1);
|
||||
ScanKey scankey = (ScanKey) PG_GETARG_POINTER(2);
|
||||
|
@ -33,8 +34,10 @@ ginbeginscan(PG_FUNCTION_ARGS) {
|
|||
|
||||
static void
|
||||
fillScanKey(GinState *ginstate, GinScanKey key, Datum query,
|
||||
Datum *entryValues, uint32 nEntryValues, StrategyNumber strategy ) {
|
||||
uint32 i,j;
|
||||
Datum *entryValues, uint32 nEntryValues, StrategyNumber strategy)
|
||||
{
|
||||
uint32 i,
|
||||
j;
|
||||
|
||||
key->nentries = nEntryValues;
|
||||
key->entryRes = (bool *) palloc0(sizeof(bool) * nEntryValues);
|
||||
|
@ -44,7 +47,8 @@ fillScanKey( GinState *ginstate, GinScanKey key, Datum query,
|
|||
key->firstCall = TRUE;
|
||||
ItemPointerSet(&(key->curItem), InvalidBlockNumber, InvalidOffsetNumber);
|
||||
|
||||
for(i=0; i<nEntryValues; i++) {
|
||||
for (i = 0; i < nEntryValues; i++)
|
||||
{
|
||||
key->scanEntry[i].pval = key->entryRes + i;
|
||||
key->scanEntry[i].entry = entryValues[i];
|
||||
ItemPointerSet(&(key->scanEntry[i].curItem), InvalidBlockNumber, InvalidOffsetNumber);
|
||||
|
@ -56,7 +60,8 @@ fillScanKey( GinState *ginstate, GinScanKey key, Datum query,
|
|||
/* link to the equals entry in current scan key */
|
||||
key->scanEntry[i].master = NULL;
|
||||
for (j = 0; j < i; j++)
|
||||
if ( compareEntries( ginstate, entryValues[i], entryValues[j] ) == 0 ) {
|
||||
if (compareEntries(ginstate, entryValues[i], entryValues[j]) == 0)
|
||||
{
|
||||
key->scanEntry[i].master = key->scanEntry + j;
|
||||
break;
|
||||
}
|
||||
|
@ -66,19 +71,23 @@ fillScanKey( GinState *ginstate, GinScanKey key, Datum query,
|
|||
#ifdef NOT_USED
|
||||
|
||||
static void
|
||||
resetScanKeys(GinScanKey keys, uint32 nkeys) {
|
||||
uint32 i, j;
|
||||
resetScanKeys(GinScanKey keys, uint32 nkeys)
|
||||
{
|
||||
uint32 i,
|
||||
j;
|
||||
|
||||
if (keys == NULL)
|
||||
return;
|
||||
|
||||
for(i=0;i<nkeys;i++) {
|
||||
for (i = 0; i < nkeys; i++)
|
||||
{
|
||||
GinScanKey key = keys + i;
|
||||
|
||||
key->firstCall = TRUE;
|
||||
ItemPointerSet(&(key->curItem), InvalidBlockNumber, InvalidOffsetNumber);
|
||||
|
||||
for(j=0;j<key->nentries;j++) {
|
||||
for (j = 0; j < key->nentries; j++)
|
||||
{
|
||||
if (key->scanEntry[j].buffer != InvalidBuffer)
|
||||
ReleaseBuffer(key->scanEntry[i].buffer);
|
||||
|
||||
|
@ -90,20 +99,23 @@ resetScanKeys(GinScanKey keys, uint32 nkeys) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void
|
||||
freeScanKeys(GinScanKey keys, uint32 nkeys, bool removeRes) {
|
||||
uint32 i, j;
|
||||
freeScanKeys(GinScanKey keys, uint32 nkeys, bool removeRes)
|
||||
{
|
||||
uint32 i,
|
||||
j;
|
||||
|
||||
if (keys == NULL)
|
||||
return;
|
||||
|
||||
for(i=0;i<nkeys;i++) {
|
||||
for (i = 0; i < nkeys; i++)
|
||||
{
|
||||
GinScanKey key = keys + i;
|
||||
|
||||
for(j=0;j<key->nentries;j++) {
|
||||
for (j = 0; j < key->nentries; j++)
|
||||
{
|
||||
if (key->scanEntry[j].buffer != InvalidBuffer)
|
||||
ReleaseBuffer(key->scanEntry[j].buffer);
|
||||
if (removeRes && key->scanEntry[j].list)
|
||||
|
@ -119,7 +131,8 @@ freeScanKeys(GinScanKey keys, uint32 nkeys, bool removeRes) {
|
|||
}
|
||||
|
||||
void
|
||||
newScanKey( IndexScanDesc scan ) {
|
||||
newScanKey(IndexScanDesc scan)
|
||||
{
|
||||
ScanKey scankey = scan->keyData;
|
||||
GinScanOpaque so = (GinScanOpaque) scan->opaque;
|
||||
int i;
|
||||
|
@ -132,7 +145,8 @@ newScanKey( IndexScanDesc scan ) {
|
|||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("GIN indexes do not support whole-index scans")));
|
||||
|
||||
for(i=0; i<scan->numberOfKeys; i++) {
|
||||
for (i = 0; i < scan->numberOfKeys; i++)
|
||||
{
|
||||
Datum *entryValues;
|
||||
uint32 nEntryValues;
|
||||
|
||||
|
@ -168,14 +182,16 @@ newScanKey( IndexScanDesc scan ) {
|
|||
}
|
||||
|
||||
Datum
|
||||
ginrescan(PG_FUNCTION_ARGS) {
|
||||
ginrescan(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
ScanKey scankey = (ScanKey) PG_GETARG_POINTER(1);
|
||||
GinScanOpaque so;
|
||||
|
||||
so = (GinScanOpaque) scan->opaque;
|
||||
|
||||
if ( so == NULL ) {
|
||||
if (so == NULL)
|
||||
{
|
||||
/* if called from ginbeginscan */
|
||||
so = (GinScanOpaque) palloc(sizeof(GinScanOpaqueData));
|
||||
so->tempCtx = AllocSetContextCreate(CurrentMemoryContext,
|
||||
|
@ -185,14 +201,17 @@ ginrescan(PG_FUNCTION_ARGS) {
|
|||
ALLOCSET_DEFAULT_MAXSIZE);
|
||||
initGinState(&so->ginstate, scan->indexRelation);
|
||||
scan->opaque = so;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
freeScanKeys(so->keys, so->nkeys, TRUE);
|
||||
freeScanKeys(so->markPos, so->nkeys, FALSE);
|
||||
}
|
||||
|
||||
so->markPos = so->keys = NULL;
|
||||
|
||||
if ( scankey && scan->numberOfKeys > 0 ) {
|
||||
if (scankey && scan->numberOfKeys > 0)
|
||||
{
|
||||
memmove(scan->keyData, scankey,
|
||||
scan->numberOfKeys * sizeof(ScanKeyData));
|
||||
}
|
||||
|
@ -202,11 +221,13 @@ ginrescan(PG_FUNCTION_ARGS) {
|
|||
|
||||
|
||||
Datum
|
||||
ginendscan(PG_FUNCTION_ARGS) {
|
||||
ginendscan(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
GinScanOpaque so = (GinScanOpaque) scan->opaque;
|
||||
|
||||
if ( so != NULL ) {
|
||||
if (so != NULL)
|
||||
{
|
||||
freeScanKeys(so->keys, so->nkeys, TRUE);
|
||||
freeScanKeys(so->markPos, so->nkeys, FALSE);
|
||||
|
||||
|
@ -219,22 +240,28 @@ ginendscan(PG_FUNCTION_ARGS) {
|
|||
}
|
||||
|
||||
static GinScanKey
|
||||
copyScanKeys( GinScanKey keys, uint32 nkeys ) {
|
||||
copyScanKeys(GinScanKey keys, uint32 nkeys)
|
||||
{
|
||||
GinScanKey newkeys;
|
||||
uint32 i, j;
|
||||
uint32 i,
|
||||
j;
|
||||
|
||||
newkeys = (GinScanKey) palloc(sizeof(GinScanKeyData) * nkeys);
|
||||
memcpy(newkeys, keys, sizeof(GinScanKeyData) * nkeys);
|
||||
|
||||
for(i=0;i<nkeys;i++) {
|
||||
for (i = 0; i < nkeys; i++)
|
||||
{
|
||||
newkeys[i].scanEntry = (GinScanEntry) palloc(sizeof(GinScanEntryData) * keys[i].nentries);
|
||||
memcpy(newkeys[i].scanEntry, keys[i].scanEntry, sizeof(GinScanEntryData) * keys[i].nentries);
|
||||
|
||||
for(j=0;j<keys[i].nentries; j++) {
|
||||
for (j = 0; j < keys[i].nentries; j++)
|
||||
{
|
||||
if (keys[i].scanEntry[j].buffer != InvalidBuffer)
|
||||
IncrBufferRefCount(keys[i].scanEntry[j].buffer);
|
||||
if ( keys[i].scanEntry[j].master ) {
|
||||
if (keys[i].scanEntry[j].master)
|
||||
{
|
||||
int masterN = keys[i].scanEntry[j].master - keys[i].scanEntry;
|
||||
|
||||
newkeys[i].scanEntry[j].master = newkeys[i].scanEntry + masterN;
|
||||
}
|
||||
}
|
||||
|
@ -244,7 +271,8 @@ copyScanKeys( GinScanKey keys, uint32 nkeys ) {
|
|||
}
|
||||
|
||||
Datum
|
||||
ginmarkpos(PG_FUNCTION_ARGS) {
|
||||
ginmarkpos(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
GinScanOpaque so = (GinScanOpaque) scan->opaque;
|
||||
|
||||
|
@ -255,7 +283,8 @@ ginmarkpos(PG_FUNCTION_ARGS) {
|
|||
}
|
||||
|
||||
Datum
|
||||
ginrestrpos(PG_FUNCTION_ARGS) {
|
||||
ginrestrpos(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
GinScanOpaque so = (GinScanOpaque) scan->opaque;
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/ginutil.c,v 1.6 2006/09/05 18:25:10 teodor Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/ginutil.c,v 1.7 2006/10/04 00:29:48 momjian Exp $
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
@ -20,7 +20,8 @@
|
|||
#include "storage/freespace.h"
|
||||
|
||||
void
|
||||
initGinState( GinState *state, Relation index ) {
|
||||
initGinState(GinState *state, Relation index)
|
||||
{
|
||||
if (index->rd_att->natts != 1)
|
||||
elog(ERROR, "numberOfAttributes %d != 1",
|
||||
index->rd_att->natts);
|
||||
|
@ -48,13 +49,16 @@ initGinState( GinState *state, Relation index ) {
|
|||
*/
|
||||
|
||||
Buffer
|
||||
GinNewBuffer(Relation index) {
|
||||
GinNewBuffer(Relation index)
|
||||
{
|
||||
Buffer buffer;
|
||||
bool needLock;
|
||||
|
||||
/* First, try to get a page from FSM */
|
||||
for(;;) {
|
||||
for (;;)
|
||||
{
|
||||
BlockNumber blkno = GetFreeIndexPage(&index->rd_node);
|
||||
|
||||
if (blkno == InvalidBlockNumber)
|
||||
break;
|
||||
|
||||
|
@ -64,7 +68,8 @@ GinNewBuffer(Relation index) {
|
|||
* We have to guard against the possibility that someone else already
|
||||
* recycled this page; the buffer may be locked if so.
|
||||
*/
|
||||
if (ConditionalLockBuffer(buffer)) {
|
||||
if (ConditionalLockBuffer(buffer))
|
||||
{
|
||||
Page page = BufferGetPage(buffer);
|
||||
|
||||
if (PageIsNew(page))
|
||||
|
@ -95,7 +100,8 @@ GinNewBuffer(Relation index) {
|
|||
}
|
||||
|
||||
void
|
||||
GinInitPage(Page page, uint32 f, Size pageSize) {
|
||||
GinInitPage(Page page, uint32 f, Size pageSize)
|
||||
{
|
||||
GinPageOpaque opaque;
|
||||
|
||||
PageInit(page, pageSize, sizeof(GinPageOpaqueData));
|
||||
|
@ -107,12 +113,14 @@ GinInitPage(Page page, uint32 f, Size pageSize) {
|
|||
}
|
||||
|
||||
void
|
||||
GinInitBuffer(Buffer b, uint32 f) {
|
||||
GinInitBuffer(Buffer b, uint32 f)
|
||||
{
|
||||
GinInitPage(BufferGetPage(b), f, BufferGetPageSize(b));
|
||||
}
|
||||
|
||||
int
|
||||
compareEntries(GinState *ginstate, Datum a, Datum b) {
|
||||
compareEntries(GinState *ginstate, Datum a, Datum b)
|
||||
{
|
||||
return DatumGetInt32(
|
||||
FunctionCall2(
|
||||
&ginstate->compareFn,
|
||||
|
@ -140,7 +148,8 @@ static FmgrInfo* cmpDatumPtr=NULL;
|
|||
static bool VOLATILE needUnique = FALSE;
|
||||
|
||||
static int
|
||||
cmpEntries(const void * a, const void * b) {
|
||||
cmpEntries(const void *a, const void *b)
|
||||
{
|
||||
int res = DatumGetInt32(
|
||||
FunctionCall2(
|
||||
cmpDatumPtr,
|
||||
|
@ -156,7 +165,8 @@ cmpEntries(const void * a, const void * b) {
|
|||
}
|
||||
|
||||
Datum *
|
||||
extractEntriesS(GinState *ginstate, Datum value, uint32 *nentries) {
|
||||
extractEntriesS(GinState *ginstate, Datum value, uint32 *nentries)
|
||||
{
|
||||
Datum *entries;
|
||||
|
||||
entries = (Datum *) DatumGetPointer(
|
||||
|
@ -170,7 +180,8 @@ extractEntriesS(GinState *ginstate, Datum value, uint32 *nentries) {
|
|||
if (entries == NULL)
|
||||
*nentries = 0;
|
||||
|
||||
if ( *nentries > 1 ) {
|
||||
if (*nentries > 1)
|
||||
{
|
||||
cmpDatumPtr = &ginstate->compareFn;
|
||||
needUnique = FALSE;
|
||||
qsort(entries, *nentries, sizeof(Datum), cmpEntries);
|
||||
|
@ -181,15 +192,19 @@ extractEntriesS(GinState *ginstate, Datum value, uint32 *nentries) {
|
|||
|
||||
|
||||
Datum *
|
||||
extractEntriesSU(GinState *ginstate, Datum value, uint32 *nentries) {
|
||||
extractEntriesSU(GinState *ginstate, Datum value, uint32 *nentries)
|
||||
{
|
||||
Datum *entries = extractEntriesS(ginstate, value, nentries);
|
||||
|
||||
if ( *nentries>1 && needUnique ) {
|
||||
Datum *ptr, *res;
|
||||
if (*nentries > 1 && needUnique)
|
||||
{
|
||||
Datum *ptr,
|
||||
*res;
|
||||
|
||||
ptr = res = entries;
|
||||
|
||||
while( ptr - entries < *nentries ) {
|
||||
while (ptr - entries < *nentries)
|
||||
{
|
||||
if (compareEntries(ginstate, *ptr, *res) != 0)
|
||||
*(++res) = *ptr++;
|
||||
else
|
||||
|
@ -206,7 +221,8 @@ extractEntriesSU(GinState *ginstate, Datum value, uint32 *nentries) {
|
|||
* It's analog of PageGetTempPage(), but copies whole page
|
||||
*/
|
||||
Page
|
||||
GinPageGetCopyPage( Page page ) {
|
||||
GinPageGetCopyPage(Page page)
|
||||
{
|
||||
Size pageSize = PageGetPageSize(page);
|
||||
Page tmppage;
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/ginvacuum.c,v 1.6 2006/09/21 20:31:21 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/ginvacuum.c,v 1.7 2006/10/04 00:29:48 momjian Exp $
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
@ -21,7 +21,8 @@
|
|||
#include "storage/freespace.h"
|
||||
#include "commands/vacuum.h"
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
Relation index;
|
||||
IndexBulkDeleteResult *result;
|
||||
IndexBulkDeleteCallback callback;
|
||||
|
@ -39,22 +40,29 @@ typedef struct {
|
|||
*/
|
||||
|
||||
static uint32
|
||||
ginVacuumPostingList( GinVacuumState *gvs, ItemPointerData *items, uint32 nitem, ItemPointerData **cleaned ) {
|
||||
uint32 i,j=0;
|
||||
ginVacuumPostingList(GinVacuumState *gvs, ItemPointerData *items, uint32 nitem, ItemPointerData **cleaned)
|
||||
{
|
||||
uint32 i,
|
||||
j = 0;
|
||||
|
||||
/*
|
||||
* just scan over ItemPointer array
|
||||
*/
|
||||
|
||||
for(i=0;i<nitem;i++) {
|
||||
if ( gvs->callback(items+i, gvs->callback_state) ) {
|
||||
for (i = 0; i < nitem; i++)
|
||||
{
|
||||
if (gvs->callback(items + i, gvs->callback_state))
|
||||
{
|
||||
gvs->result->tuples_removed += 1;
|
||||
if ( !*cleaned ) {
|
||||
if (!*cleaned)
|
||||
{
|
||||
*cleaned = (ItemPointerData *) palloc(sizeof(ItemPointerData) * nitem);
|
||||
if (i != 0)
|
||||
memcpy(*cleaned, items, sizeof(ItemPointerData) * i);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
gvs->result->num_index_tuples += 1;
|
||||
if (i != j)
|
||||
(*cleaned)[j] = items[i];
|
||||
|
@ -69,7 +77,8 @@ ginVacuumPostingList( GinVacuumState *gvs, ItemPointerData *items, uint32 nitem,
|
|||
* fills WAL record for vacuum leaf page
|
||||
*/
|
||||
static void
|
||||
xlogVacuumPage(Relation index, Buffer buffer) {
|
||||
xlogVacuumPage(Relation index, Buffer buffer)
|
||||
{
|
||||
Page page = BufferGetPage(buffer);
|
||||
XLogRecPtr recptr;
|
||||
XLogRecData rdata[3];
|
||||
|
@ -86,18 +95,23 @@ xlogVacuumPage(Relation index, Buffer buffer) {
|
|||
data.node = index->rd_node;
|
||||
data.blkno = BufferGetBlockNumber(buffer);
|
||||
|
||||
if ( GinPageIsData( page ) ) {
|
||||
if (GinPageIsData(page))
|
||||
{
|
||||
backup = GinDataPageGetData(page);
|
||||
data.nitem = GinPageGetOpaque(page)->maxoff;
|
||||
if (data.nitem)
|
||||
len = MAXALIGN(sizeof(ItemPointerData) * data.nitem);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
char *ptr;
|
||||
OffsetNumber i;
|
||||
|
||||
ptr = backup = itups;
|
||||
for(i=FirstOffsetNumber;i<=PageGetMaxOffsetNumber(page);i++) {
|
||||
for (i = FirstOffsetNumber; i <= PageGetMaxOffsetNumber(page); i++)
|
||||
{
|
||||
IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
|
||||
|
||||
memcpy(ptr, itup, IndexTupleSize(itup));
|
||||
ptr += MAXALIGN(IndexTupleSize(itup));
|
||||
}
|
||||
|
@ -116,9 +130,12 @@ xlogVacuumPage(Relation index, Buffer buffer) {
|
|||
rdata[1].len = sizeof(ginxlogVacuumPage);
|
||||
rdata[1].data = (char *) &data;
|
||||
|
||||
if ( len == 0 ) {
|
||||
if (len == 0)
|
||||
{
|
||||
rdata[1].next = NULL;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
rdata[1].next = rdata + 2;
|
||||
|
||||
rdata[2].buffer = InvalidBuffer;
|
||||
|
@ -133,34 +150,38 @@ xlogVacuumPage(Relation index, Buffer buffer) {
|
|||
}
|
||||
|
||||
static bool
|
||||
ginVacuumPostingTreeLeaves( GinVacuumState *gvs, BlockNumber blkno, bool isRoot, Buffer *rootBuffer ) {
|
||||
ginVacuumPostingTreeLeaves(GinVacuumState *gvs, BlockNumber blkno, bool isRoot, Buffer *rootBuffer)
|
||||
{
|
||||
Buffer buffer = ReadBuffer(gvs->index, blkno);
|
||||
Page page = BufferGetPage(buffer);
|
||||
bool hasVoidPage = FALSE;
|
||||
|
||||
/*
|
||||
* We should be sure that we don't concurrent with inserts, insert process
|
||||
* never release root page until end (but it can unlock it and lock again).
|
||||
* If we lock root with with LockBufferForCleanup, new scan process can't begin,
|
||||
* but previous may run.
|
||||
* ginmarkpos/start* keeps buffer pinned, so we will wait for it.
|
||||
* We lock only one posting tree in whole index, so, it's concurrent enough..
|
||||
* Side effect: after this is full complete, tree is unused by any other process
|
||||
* never release root page until end (but it can unlock it and lock
|
||||
* again). If we lock root with with LockBufferForCleanup, new scan
|
||||
* process can't begin, but previous may run. ginmarkpos/start* keeps
|
||||
* buffer pinned, so we will wait for it. We lock only one posting tree in
|
||||
* whole index, so, it's concurrent enough.. Side effect: after this is
|
||||
* full complete, tree is unused by any other process
|
||||
*/
|
||||
|
||||
LockBufferForCleanup(buffer);
|
||||
|
||||
Assert(GinPageIsData(page));
|
||||
|
||||
if ( GinPageIsLeaf(page) ) {
|
||||
OffsetNumber newMaxOff, oldMaxOff = GinPageGetOpaque(page)->maxoff;
|
||||
if (GinPageIsLeaf(page))
|
||||
{
|
||||
OffsetNumber newMaxOff,
|
||||
oldMaxOff = GinPageGetOpaque(page)->maxoff;
|
||||
ItemPointerData *cleaned = NULL;
|
||||
|
||||
newMaxOff = ginVacuumPostingList(gvs,
|
||||
(ItemPointer) GinDataPageGetData(page), oldMaxOff, &cleaned);
|
||||
|
||||
/* saves changes about deleted tuple ... */
|
||||
if ( oldMaxOff != newMaxOff ) {
|
||||
if (oldMaxOff != newMaxOff)
|
||||
{
|
||||
|
||||
START_CRIT_SECTION();
|
||||
|
||||
|
@ -178,12 +199,16 @@ ginVacuumPostingTreeLeaves( GinVacuumState *gvs, BlockNumber blkno, bool isRoot,
|
|||
if (!isRoot && GinPageGetOpaque(page)->maxoff < FirstOffsetNumber)
|
||||
hasVoidPage = TRUE;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
OffsetNumber i;
|
||||
bool isChildHasVoid = FALSE;
|
||||
|
||||
for( i=FirstOffsetNumber ; i <= GinPageGetOpaque(page)->maxoff ; i++ ) {
|
||||
for (i = FirstOffsetNumber; i <= GinPageGetOpaque(page)->maxoff; i++)
|
||||
{
|
||||
PostingItem *pitem = (PostingItem *) GinDataPageGetItem(page, i);
|
||||
|
||||
if (ginVacuumPostingTreeLeaves(gvs, PostingItemGetBlockNumber(pitem), FALSE, NULL))
|
||||
isChildHasVoid = TRUE;
|
||||
}
|
||||
|
@ -192,11 +217,16 @@ ginVacuumPostingTreeLeaves( GinVacuumState *gvs, BlockNumber blkno, bool isRoot,
|
|||
hasVoidPage = TRUE;
|
||||
}
|
||||
|
||||
/* if we have root and theres void pages in tree, then we don't release lock
|
||||
to go further processing and guarantee that tree is unused */
|
||||
if ( !(isRoot && hasVoidPage) ) {
|
||||
/*
|
||||
* if we have root and theres void pages in tree, then we don't release
|
||||
* lock to go further processing and guarantee that tree is unused
|
||||
*/
|
||||
if (!(isRoot && hasVoidPage))
|
||||
{
|
||||
UnlockReleaseBuffer(buffer);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert(rootBuffer);
|
||||
*rootBuffer = buffer;
|
||||
}
|
||||
|
@ -206,19 +236,23 @@ ginVacuumPostingTreeLeaves( GinVacuumState *gvs, BlockNumber blkno, bool isRoot,
|
|||
|
||||
static void
|
||||
ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkno,
|
||||
BlockNumber parentBlkno, OffsetNumber myoff, bool isParentRoot ) {
|
||||
BlockNumber parentBlkno, OffsetNumber myoff, bool isParentRoot)
|
||||
{
|
||||
Buffer dBuffer = ReadBuffer(gvs->index, deleteBlkno);
|
||||
Buffer lBuffer = (leftBlkno == InvalidBlockNumber) ? InvalidBuffer : ReadBuffer(gvs->index, leftBlkno);
|
||||
Buffer pBuffer = ReadBuffer(gvs->index, parentBlkno);
|
||||
Page page, parentPage;
|
||||
Page page,
|
||||
parentPage;
|
||||
|
||||
LockBuffer(dBuffer, GIN_EXCLUSIVE);
|
||||
if ( !isParentRoot ) /* parent is already locked by LockBufferForCleanup() */
|
||||
if (!isParentRoot) /* parent is already locked by
|
||||
* LockBufferForCleanup() */
|
||||
LockBuffer(pBuffer, GIN_EXCLUSIVE);
|
||||
|
||||
START_CRIT_SECTION();
|
||||
|
||||
if ( leftBlkno!= InvalidBlockNumber ) {
|
||||
if (leftBlkno != InvalidBlockNumber)
|
||||
{
|
||||
BlockNumber rightlink;
|
||||
|
||||
LockBuffer(lBuffer, GIN_EXCLUSIVE);
|
||||
|
@ -236,7 +270,8 @@ ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkn
|
|||
page = BufferGetPage(dBuffer);
|
||||
GinPageGetOpaque(page)->flags = GIN_DELETED;
|
||||
|
||||
if (!gvs->index->rd_istemp) {
|
||||
if (!gvs->index->rd_istemp)
|
||||
{
|
||||
XLogRecPtr recptr;
|
||||
XLogRecData rdata[4];
|
||||
ginxlogDeletePage data;
|
||||
|
@ -261,14 +296,16 @@ ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkn
|
|||
rdata[1].len = 0;
|
||||
rdata[1].next = rdata + 2;
|
||||
|
||||
if ( leftBlkno!= InvalidBlockNumber ) {
|
||||
if (leftBlkno != InvalidBlockNumber)
|
||||
{
|
||||
rdata[2].buffer = lBuffer;
|
||||
rdata[2].buffer_std = FALSE;
|
||||
rdata[2].data = NULL;
|
||||
rdata[2].len = 0;
|
||||
rdata[2].next = rdata + 3;
|
||||
n = 3;
|
||||
} else
|
||||
}
|
||||
else
|
||||
n = 2;
|
||||
|
||||
rdata[n].buffer = InvalidBuffer;
|
||||
|
@ -282,7 +319,8 @@ ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkn
|
|||
PageSetTLI(page, ThisTimeLineID);
|
||||
PageSetLSN(parentPage, recptr);
|
||||
PageSetTLI(parentPage, ThisTimeLineID);
|
||||
if ( leftBlkno!= InvalidBlockNumber ) {
|
||||
if (leftBlkno != InvalidBlockNumber)
|
||||
{
|
||||
page = BufferGetPage(lBuffer);
|
||||
PageSetLSN(page, recptr);
|
||||
PageSetTLI(page, ThisTimeLineID);
|
||||
|
@ -294,7 +332,8 @@ ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkn
|
|||
LockBuffer(pBuffer, GIN_UNLOCK);
|
||||
ReleaseBuffer(pBuffer);
|
||||
|
||||
if ( leftBlkno!= InvalidBlockNumber ) {
|
||||
if (leftBlkno != InvalidBlockNumber)
|
||||
{
|
||||
MarkBufferDirty(lBuffer);
|
||||
UnlockReleaseBuffer(lBuffer);
|
||||
}
|
||||
|
@ -307,7 +346,8 @@ ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkn
|
|||
gvs->result->pages_deleted++;
|
||||
}
|
||||
|
||||
typedef struct DataPageDeleteStack {
|
||||
typedef struct DataPageDeleteStack
|
||||
{
|
||||
struct DataPageDeleteStack *child;
|
||||
struct DataPageDeleteStack *parent;
|
||||
|
||||
|
@ -319,21 +359,27 @@ typedef struct DataPageDeleteStack {
|
|||
* scans posting tree and deletes empty pages
|
||||
*/
|
||||
static bool
|
||||
ginScanToDelete( GinVacuumState *gvs, BlockNumber blkno, bool isRoot, DataPageDeleteStack *parent, OffsetNumber myoff ) {
|
||||
ginScanToDelete(GinVacuumState *gvs, BlockNumber blkno, bool isRoot, DataPageDeleteStack *parent, OffsetNumber myoff)
|
||||
{
|
||||
DataPageDeleteStack *me;
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
bool meDelete = FALSE;
|
||||
|
||||
if ( isRoot ) {
|
||||
if (isRoot)
|
||||
{
|
||||
me = parent;
|
||||
} else {
|
||||
if ( ! parent->child ) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!parent->child)
|
||||
{
|
||||
me = (DataPageDeleteStack *) palloc0(sizeof(DataPageDeleteStack));
|
||||
me->parent = parent;
|
||||
parent->child = me;
|
||||
me->blkno = InvalidBlockNumber;
|
||||
} else
|
||||
}
|
||||
else
|
||||
me = parent->child;
|
||||
}
|
||||
|
||||
|
@ -342,10 +388,12 @@ ginScanToDelete( GinVacuumState *gvs, BlockNumber blkno, bool isRoot, DataPageDe
|
|||
|
||||
Assert(GinPageIsData(page));
|
||||
|
||||
if ( !GinPageIsLeaf(page) ) {
|
||||
if (!GinPageIsLeaf(page))
|
||||
{
|
||||
OffsetNumber i;
|
||||
|
||||
for(i=FirstOffsetNumber;i<=GinPageGetOpaque(page)->maxoff;i++) {
|
||||
for (i = FirstOffsetNumber; i <= GinPageGetOpaque(page)->maxoff; i++)
|
||||
{
|
||||
PostingItem *pitem = (PostingItem *) GinDataPageGetItem(page, i);
|
||||
|
||||
if (ginScanToDelete(gvs, PostingItemGetBlockNumber(pitem), FALSE, me, i))
|
||||
|
@ -353,11 +401,14 @@ ginScanToDelete( GinVacuumState *gvs, BlockNumber blkno, bool isRoot, DataPageDe
|
|||
}
|
||||
}
|
||||
|
||||
if ( GinPageGetOpaque(page)->maxoff < FirstOffsetNumber ) {
|
||||
if ( !( me->blkno == InvalidBlockNumber && GinPageRightMost(page) ) ) {
|
||||
if (GinPageGetOpaque(page)->maxoff < FirstOffsetNumber)
|
||||
{
|
||||
if (!(me->blkno == InvalidBlockNumber && GinPageRightMost(page)))
|
||||
{
|
||||
/* we never delete right most branch */
|
||||
Assert(!isRoot);
|
||||
if ( GinPageGetOpaque(page)->maxoff < FirstOffsetNumber ) {
|
||||
if (GinPageGetOpaque(page)->maxoff < FirstOffsetNumber)
|
||||
{
|
||||
ginDeletePage(gvs, blkno, me->blkno, me->parent->blkno, myoff, me->parent->isRoot);
|
||||
meDelete = TRUE;
|
||||
}
|
||||
|
@ -373,11 +424,15 @@ ginScanToDelete( GinVacuumState *gvs, BlockNumber blkno, bool isRoot, DataPageDe
|
|||
}
|
||||
|
||||
static void
|
||||
ginVacuumPostingTree( GinVacuumState *gvs, BlockNumber rootBlkno ) {
|
||||
ginVacuumPostingTree(GinVacuumState *gvs, BlockNumber rootBlkno)
|
||||
{
|
||||
Buffer rootBuffer = InvalidBuffer;
|
||||
DataPageDeleteStack root, *ptr, *tmp;
|
||||
DataPageDeleteStack root,
|
||||
*ptr,
|
||||
*tmp;
|
||||
|
||||
if ( ginVacuumPostingTreeLeaves(gvs, rootBlkno, TRUE, &rootBuffer)==FALSE ) {
|
||||
if (ginVacuumPostingTreeLeaves(gvs, rootBlkno, TRUE, &rootBuffer) == FALSE)
|
||||
{
|
||||
Assert(rootBuffer == InvalidBuffer);
|
||||
return;
|
||||
}
|
||||
|
@ -391,7 +446,8 @@ ginVacuumPostingTree( GinVacuumState *gvs, BlockNumber rootBlkno ) {
|
|||
ginScanToDelete(gvs, rootBlkno, TRUE, &root, InvalidOffsetNumber);
|
||||
|
||||
ptr = root.child;
|
||||
while( ptr ) {
|
||||
while (ptr)
|
||||
{
|
||||
tmp = ptr->child;
|
||||
pfree(ptr);
|
||||
ptr = tmp;
|
||||
|
@ -406,44 +462,61 @@ ginVacuumPostingTree( GinVacuumState *gvs, BlockNumber rootBlkno ) {
|
|||
* then page is copied into temprorary one.
|
||||
*/
|
||||
static Page
|
||||
ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint32 *nroot) {
|
||||
Page origpage = BufferGetPage( buffer ), tmppage;
|
||||
OffsetNumber i, maxoff = PageGetMaxOffsetNumber( origpage );
|
||||
ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint32 *nroot)
|
||||
{
|
||||
Page origpage = BufferGetPage(buffer),
|
||||
tmppage;
|
||||
OffsetNumber i,
|
||||
maxoff = PageGetMaxOffsetNumber(origpage);
|
||||
|
||||
tmppage = origpage;
|
||||
|
||||
*nroot = 0;
|
||||
|
||||
for(i=FirstOffsetNumber; i<= maxoff; i++) {
|
||||
for (i = FirstOffsetNumber; i <= maxoff; i++)
|
||||
{
|
||||
IndexTuple itup = (IndexTuple) PageGetItem(tmppage, PageGetItemId(tmppage, i));
|
||||
|
||||
if ( GinIsPostingTree(itup) ) {
|
||||
/* store posting tree's roots for further processing,
|
||||
we can't vacuum it just now due to risk of deadlocks with scans/inserts */
|
||||
if (GinIsPostingTree(itup))
|
||||
{
|
||||
/*
|
||||
* store posting tree's roots for further processing, we can't
|
||||
* vacuum it just now due to risk of deadlocks with scans/inserts
|
||||
*/
|
||||
roots[*nroot] = GinItemPointerGetBlockNumber(&itup->t_tid);
|
||||
(*nroot)++;
|
||||
} else if ( GinGetNPosting(itup) > 0 ) {
|
||||
/* if we already create temrorary page, we will make changes in place */
|
||||
}
|
||||
else if (GinGetNPosting(itup) > 0)
|
||||
{
|
||||
/*
|
||||
* if we already create temrorary page, we will make changes in
|
||||
* place
|
||||
*/
|
||||
ItemPointerData *cleaned = (tmppage == origpage) ? NULL : GinGetPosting(itup);
|
||||
uint32 newN = ginVacuumPostingList(gvs, GinGetPosting(itup), GinGetNPosting(itup), &cleaned);
|
||||
|
||||
if ( GinGetNPosting(itup) != newN ) {
|
||||
if (GinGetNPosting(itup) != newN)
|
||||
{
|
||||
bool isnull;
|
||||
Datum value;
|
||||
|
||||
/*
|
||||
* Some ItemPointers was deleted, so we should remake our tuple
|
||||
* Some ItemPointers was deleted, so we should remake our
|
||||
* tuple
|
||||
*/
|
||||
|
||||
if ( tmppage==origpage ) {
|
||||
if (tmppage == origpage)
|
||||
{
|
||||
/*
|
||||
* On first difference we create temprorary page in memory
|
||||
* and copies content in to it.
|
||||
*/
|
||||
tmppage = GinPageGetCopyPage(origpage);
|
||||
|
||||
if ( newN > 0 ) {
|
||||
if (newN > 0)
|
||||
{
|
||||
Size pos = ((char *) GinGetPosting(itup)) - ((char *) origpage);
|
||||
|
||||
memcpy(tmppage + pos, cleaned, sizeof(ItemPointerData) * newN);
|
||||
}
|
||||
|
||||
|
@ -470,7 +543,8 @@ ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint3
|
|||
}
|
||||
|
||||
Datum
|
||||
ginbulkdelete(PG_FUNCTION_ARGS) {
|
||||
ginbulkdelete(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
|
||||
IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
|
||||
IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(2);
|
||||
|
@ -497,7 +571,8 @@ ginbulkdelete(PG_FUNCTION_ARGS) {
|
|||
buffer = ReadBuffer(index, blkno);
|
||||
|
||||
/* find leaf page */
|
||||
for(;;) {
|
||||
for (;;)
|
||||
{
|
||||
Page page = BufferGetPage(buffer);
|
||||
IndexTuple itup;
|
||||
|
||||
|
@ -505,11 +580,13 @@ ginbulkdelete(PG_FUNCTION_ARGS) {
|
|||
|
||||
Assert(!GinPageIsData(page));
|
||||
|
||||
if ( GinPageIsLeaf(page) ) {
|
||||
if (GinPageIsLeaf(page))
|
||||
{
|
||||
LockBuffer(buffer, GIN_UNLOCK);
|
||||
LockBuffer(buffer, GIN_EXCLUSIVE);
|
||||
|
||||
if ( blkno==GIN_ROOT_BLKNO && !GinPageIsLeaf(page) ) {
|
||||
if (blkno == GIN_ROOT_BLKNO && !GinPageIsLeaf(page))
|
||||
{
|
||||
LockBuffer(buffer, GIN_UNLOCK);
|
||||
continue; /* check it one more */
|
||||
}
|
||||
|
@ -528,7 +605,8 @@ ginbulkdelete(PG_FUNCTION_ARGS) {
|
|||
|
||||
/* right now we found leftmost page in entry's BTree */
|
||||
|
||||
for(;;) {
|
||||
for (;;)
|
||||
{
|
||||
Page page = BufferGetPage(buffer);
|
||||
Page resPage;
|
||||
uint32 i;
|
||||
|
@ -539,20 +617,24 @@ ginbulkdelete(PG_FUNCTION_ARGS) {
|
|||
|
||||
blkno = GinPageGetOpaque(page)->rightlink;
|
||||
|
||||
if ( resPage ) {
|
||||
if (resPage)
|
||||
{
|
||||
START_CRIT_SECTION();
|
||||
PageRestoreTempPage(resPage, page);
|
||||
xlogVacuumPage(gvs.index, buffer);
|
||||
MarkBufferDirty(buffer);
|
||||
UnlockReleaseBuffer(buffer);
|
||||
END_CRIT_SECTION();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
UnlockReleaseBuffer(buffer);
|
||||
}
|
||||
|
||||
vacuum_delay_point();
|
||||
|
||||
for(i=0; i<nRoot; i++) {
|
||||
for (i = 0; i < nRoot; i++)
|
||||
{
|
||||
ginVacuumPostingTree(&gvs, rootOfPostingTree[i]);
|
||||
vacuum_delay_point();
|
||||
}
|
||||
|
@ -568,7 +650,8 @@ ginbulkdelete(PG_FUNCTION_ARGS) {
|
|||
}
|
||||
|
||||
Datum
|
||||
ginvacuumcleanup(PG_FUNCTION_ARGS) {
|
||||
ginvacuumcleanup(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
|
||||
IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
|
||||
Relation index = info->index;
|
||||
|
@ -585,16 +668,17 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) {
|
|||
/* Set up all-zero stats if ginbulkdelete wasn't called */
|
||||
if (stats == NULL)
|
||||
stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
|
||||
|
||||
/*
|
||||
* XXX we always report the heap tuple count as the number of index
|
||||
* entries. This is bogus if the index is partial, but it's real hard
|
||||
* to tell how many distinct heap entries are referenced by a GIN index.
|
||||
* entries. This is bogus if the index is partial, but it's real hard to
|
||||
* tell how many distinct heap entries are referenced by a GIN index.
|
||||
*/
|
||||
stats->num_index_tuples = info->num_heap_tuples;
|
||||
|
||||
/*
|
||||
* If vacuum full, we already have exclusive lock on the index.
|
||||
* Otherwise, need lock unless it's local to this backend.
|
||||
* If vacuum full, we already have exclusive lock on the index. Otherwise,
|
||||
* need lock unless it's local to this backend.
|
||||
*/
|
||||
if (info->vacuum_full)
|
||||
needLock = false;
|
||||
|
@ -614,7 +698,8 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) {
|
|||
totFreePages = nFreePages = 0;
|
||||
freePages = (BlockNumber *) palloc(sizeof(BlockNumber) * maxFreePages);
|
||||
|
||||
for (blkno = GIN_ROOT_BLKNO + 1; blkno < npages; blkno++) {
|
||||
for (blkno = GIN_ROOT_BLKNO + 1; blkno < npages; blkno++)
|
||||
{
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
|
||||
|
@ -624,22 +709,27 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) {
|
|||
LockBuffer(buffer, GIN_SHARE);
|
||||
page = (Page) BufferGetPage(buffer);
|
||||
|
||||
if ( GinPageIsDeleted(page) ) {
|
||||
if (GinPageIsDeleted(page))
|
||||
{
|
||||
if (nFreePages < maxFreePages)
|
||||
freePages[nFreePages++] = blkno;
|
||||
totFreePages++;
|
||||
} else
|
||||
}
|
||||
else
|
||||
lastFilledBlock = blkno;
|
||||
|
||||
UnlockReleaseBuffer(buffer);
|
||||
}
|
||||
lastBlock = npages - 1;
|
||||
|
||||
if (info->vacuum_full && nFreePages > 0) {
|
||||
if (info->vacuum_full && nFreePages > 0)
|
||||
{
|
||||
/* try to truncate index */
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nFreePages; i++)
|
||||
if (freePages[i] >= lastFilledBlock) {
|
||||
if (freePages[i] >= lastFilledBlock)
|
||||
{
|
||||
totFreePages = nFreePages = i;
|
||||
break;
|
||||
}
|
||||
|
@ -661,4 +751,3 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) {
|
|||
|
||||
PG_RETURN_POINTER(stats);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/ginxlog.c,v 1.4 2006/08/07 16:57:56 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/ginxlog.c,v 1.5 2006/10/04 00:29:48 momjian Exp $
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
@ -20,7 +20,8 @@
|
|||
static MemoryContext opCtx; /* working memory for operations */
|
||||
static MemoryContext topCtx;
|
||||
|
||||
typedef struct ginIncompleteSplit {
|
||||
typedef struct ginIncompleteSplit
|
||||
{
|
||||
RelFileNode node;
|
||||
BlockNumber leftBlkno;
|
||||
BlockNumber rightBlkno;
|
||||
|
@ -30,7 +31,8 @@ typedef struct ginIncompleteSplit {
|
|||
static List *incomplete_splits;
|
||||
|
||||
static void
|
||||
pushIncompleteSplit(RelFileNode node, BlockNumber leftBlkno, BlockNumber rightBlkno, BlockNumber rootBlkno) {
|
||||
pushIncompleteSplit(RelFileNode node, BlockNumber leftBlkno, BlockNumber rightBlkno, BlockNumber rootBlkno)
|
||||
{
|
||||
ginIncompleteSplit *split;
|
||||
|
||||
MemoryContextSwitchTo(topCtx);
|
||||
|
@ -48,13 +50,16 @@ pushIncompleteSplit(RelFileNode node, BlockNumber leftBlkno, BlockNumber rightBl
|
|||
}
|
||||
|
||||
static void
|
||||
forgetIncompleteSplit(RelFileNode node, BlockNumber leftBlkno, BlockNumber updateBlkno) {
|
||||
forgetIncompleteSplit(RelFileNode node, BlockNumber leftBlkno, BlockNumber updateBlkno)
|
||||
{
|
||||
ListCell *l;
|
||||
|
||||
foreach(l, incomplete_splits) {
|
||||
foreach(l, incomplete_splits)
|
||||
{
|
||||
ginIncompleteSplit *split = (ginIncompleteSplit *) lfirst(l);
|
||||
|
||||
if ( RelFileNodeEquals(node, split->node) && leftBlkno == split->leftBlkno && updateBlkno == split->rightBlkno ) {
|
||||
if (RelFileNodeEquals(node, split->node) && leftBlkno == split->leftBlkno && updateBlkno == split->rightBlkno)
|
||||
{
|
||||
incomplete_splits = list_delete_ptr(incomplete_splits, split);
|
||||
break;
|
||||
}
|
||||
|
@ -62,7 +67,8 @@ forgetIncompleteSplit(RelFileNode node, BlockNumber leftBlkno, BlockNumber updat
|
|||
}
|
||||
|
||||
static void
|
||||
ginRedoCreateIndex(XLogRecPtr lsn, XLogRecord *record) {
|
||||
ginRedoCreateIndex(XLogRecPtr lsn, XLogRecord *record)
|
||||
{
|
||||
RelFileNode *node = (RelFileNode *) XLogRecGetData(record);
|
||||
Relation reln;
|
||||
Buffer buffer;
|
||||
|
@ -83,7 +89,8 @@ ginRedoCreateIndex(XLogRecPtr lsn, XLogRecord *record) {
|
|||
}
|
||||
|
||||
static void
|
||||
ginRedoCreatePTree(XLogRecPtr lsn, XLogRecord *record) {
|
||||
ginRedoCreatePTree(XLogRecPtr lsn, XLogRecord *record)
|
||||
{
|
||||
ginxlogCreatePostingTree *data = (ginxlogCreatePostingTree *) XLogRecGetData(record);
|
||||
ItemPointerData *items = (ItemPointerData *) (XLogRecGetData(record) + sizeof(ginxlogCreatePostingTree));
|
||||
Relation reln;
|
||||
|
@ -107,7 +114,8 @@ ginRedoCreatePTree(XLogRecPtr lsn, XLogRecord *record) {
|
|||
}
|
||||
|
||||
static void
|
||||
ginRedoInsert(XLogRecPtr lsn, XLogRecord *record) {
|
||||
ginRedoInsert(XLogRecPtr lsn, XLogRecord *record)
|
||||
{
|
||||
ginxlogInsert *data = (ginxlogInsert *) XLogRecGetData(record);
|
||||
Relation reln;
|
||||
Buffer buffer;
|
||||
|
@ -122,11 +130,13 @@ ginRedoInsert(XLogRecPtr lsn, XLogRecord *record) {
|
|||
Assert(BufferIsValid(buffer));
|
||||
page = (Page) BufferGetPage(buffer);
|
||||
|
||||
if ( data->isData ) {
|
||||
if (data->isData)
|
||||
{
|
||||
Assert(data->isDelete == FALSE);
|
||||
Assert(GinPageIsData(page));
|
||||
|
||||
if ( data->isLeaf ) {
|
||||
if (data->isLeaf)
|
||||
{
|
||||
OffsetNumber i;
|
||||
ItemPointerData *items = (ItemPointerData *) (XLogRecGetData(record) + sizeof(ginxlogInsert));
|
||||
|
||||
|
@ -135,12 +145,15 @@ ginRedoInsert(XLogRecPtr lsn, XLogRecord *record) {
|
|||
|
||||
for (i = 0; i < data->nitem; i++)
|
||||
GinDataPageAddItem(page, items + i, data->offset + i);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
PostingItem *pitem;
|
||||
|
||||
Assert(!GinPageIsLeaf(page));
|
||||
|
||||
if ( data->updateBlkno != InvalidBlockNumber ) {
|
||||
if (data->updateBlkno != InvalidBlockNumber)
|
||||
{
|
||||
/* update link to right page after split */
|
||||
pitem = (PostingItem *) GinDataPageGetItem(page, data->offset);
|
||||
PostingItemSetBlockNumber(pitem, data->updateBlkno);
|
||||
|
@ -153,12 +166,15 @@ ginRedoInsert(XLogRecPtr lsn, XLogRecord *record) {
|
|||
if (data->updateBlkno != InvalidBlockNumber)
|
||||
forgetIncompleteSplit(data->node, PostingItemGetBlockNumber(pitem), data->updateBlkno);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
IndexTuple itup;
|
||||
|
||||
Assert(!GinPageIsData(page));
|
||||
|
||||
if ( data->updateBlkno != InvalidBlockNumber ) {
|
||||
if (data->updateBlkno != InvalidBlockNumber)
|
||||
{
|
||||
/* update link to right page after split */
|
||||
Assert(!GinPageIsLeaf(page));
|
||||
Assert(data->offset >= FirstOffsetNumber && data->offset <= PageGetMaxOffsetNumber(page));
|
||||
|
@ -166,7 +182,8 @@ ginRedoInsert(XLogRecPtr lsn, XLogRecord *record) {
|
|||
ItemPointerSet(&itup->t_tid, data->updateBlkno, InvalidOffsetNumber);
|
||||
}
|
||||
|
||||
if ( data->isDelete ) {
|
||||
if (data->isDelete)
|
||||
{
|
||||
Assert(GinPageIsLeaf(page));
|
||||
Assert(data->offset >= FirstOffsetNumber && data->offset <= PageGetMaxOffsetNumber(page));
|
||||
PageIndexTupleDelete(page, data->offset);
|
||||
|
@ -190,11 +207,14 @@ ginRedoInsert(XLogRecPtr lsn, XLogRecord *record) {
|
|||
}
|
||||
|
||||
static void
|
||||
ginRedoSplit(XLogRecPtr lsn, XLogRecord *record) {
|
||||
ginRedoSplit(XLogRecPtr lsn, XLogRecord *record)
|
||||
{
|
||||
ginxlogSplit *data = (ginxlogSplit *) XLogRecGetData(record);
|
||||
Relation reln;
|
||||
Buffer lbuffer, rbuffer;
|
||||
Page lpage, rpage;
|
||||
Buffer lbuffer,
|
||||
rbuffer;
|
||||
Page lpage,
|
||||
rpage;
|
||||
uint32 flags = 0;
|
||||
|
||||
reln = XLogOpenRelation(data->node);
|
||||
|
@ -217,18 +237,21 @@ ginRedoSplit(XLogRecPtr lsn, XLogRecord *record) {
|
|||
GinPageGetOpaque(lpage)->rightlink = BufferGetBlockNumber(rbuffer);
|
||||
GinPageGetOpaque(rpage)->rightlink = data->rrlink;
|
||||
|
||||
if ( data->isData ) {
|
||||
if (data->isData)
|
||||
{
|
||||
char *ptr = XLogRecGetData(record) + sizeof(ginxlogSplit);
|
||||
Size sizeofitem = GinSizeOfItem(lpage);
|
||||
OffsetNumber i;
|
||||
ItemPointer bound;
|
||||
|
||||
for(i=0;i<data->separator;i++) {
|
||||
for (i = 0; i < data->separator; i++)
|
||||
{
|
||||
GinDataPageAddItem(lpage, ptr, InvalidOffsetNumber);
|
||||
ptr += sizeofitem;
|
||||
}
|
||||
|
||||
for(i=data->separator;i<data->nitem;i++) {
|
||||
for (i = data->separator; i < data->nitem; i++)
|
||||
{
|
||||
GinDataPageAddItem(rpage, ptr, InvalidOffsetNumber);
|
||||
ptr += sizeofitem;
|
||||
}
|
||||
|
@ -242,18 +265,22 @@ ginRedoSplit(XLogRecPtr lsn, XLogRecord *record) {
|
|||
|
||||
bound = GinDataPageGetRightBound(rpage);
|
||||
*bound = data->rightbound;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
IndexTuple itup = (IndexTuple) (XLogRecGetData(record) + sizeof(ginxlogSplit));
|
||||
OffsetNumber i;
|
||||
|
||||
for(i=0;i<data->separator;i++) {
|
||||
for (i = 0; i < data->separator; i++)
|
||||
{
|
||||
if (PageAddItem(lpage, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber)
|
||||
elog(ERROR, "failed to add item to index page in %u/%u/%u",
|
||||
data->node.spcNode, data->node.dbNode, data->node.relNode);
|
||||
itup = (IndexTuple) (((char *) itup) + MAXALIGN(IndexTupleSize(itup)));
|
||||
}
|
||||
|
||||
for(i=data->separator;i<data->nitem;i++) {
|
||||
for (i = data->separator; i < data->nitem; i++)
|
||||
{
|
||||
if (PageAddItem(rpage, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber)
|
||||
elog(ERROR, "failed to add item to index page in %u/%u/%u",
|
||||
data->node.spcNode, data->node.dbNode, data->node.relNode);
|
||||
|
@ -272,16 +299,20 @@ ginRedoSplit(XLogRecPtr lsn, XLogRecord *record) {
|
|||
if (!data->isLeaf && data->updateBlkno != InvalidBlockNumber)
|
||||
forgetIncompleteSplit(data->node, data->leftChildBlkno, data->updateBlkno);
|
||||
|
||||
if ( data->isRootSplit ) {
|
||||
if (data->isRootSplit)
|
||||
{
|
||||
Buffer rootBuf = XLogReadBuffer(reln, data->rootBlkno, false);
|
||||
Page rootPage = BufferGetPage(rootBuf);
|
||||
|
||||
GinInitBuffer(rootBuf, flags & ~GIN_LEAF);
|
||||
|
||||
if ( data->isData ) {
|
||||
if (data->isData)
|
||||
{
|
||||
Assert(data->rootBlkno != GIN_ROOT_BLKNO);
|
||||
dataFillRoot(NULL, rootBuf, lbuffer, rbuffer);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert(data->rootBlkno == GIN_ROOT_BLKNO);
|
||||
entryFillRoot(NULL, rootBuf, lbuffer, rbuffer);
|
||||
}
|
||||
|
@ -291,7 +322,8 @@ ginRedoSplit(XLogRecPtr lsn, XLogRecord *record) {
|
|||
|
||||
MarkBufferDirty(rootBuf);
|
||||
UnlockReleaseBuffer(rootBuf);
|
||||
} else
|
||||
}
|
||||
else
|
||||
pushIncompleteSplit(data->node, data->lblkno, data->rblkno, data->rootBlkno);
|
||||
|
||||
UnlockReleaseBuffer(rbuffer);
|
||||
|
@ -299,7 +331,8 @@ ginRedoSplit(XLogRecPtr lsn, XLogRecord *record) {
|
|||
}
|
||||
|
||||
static void
|
||||
ginRedoVacuumPage(XLogRecPtr lsn, XLogRecord *record) {
|
||||
ginRedoVacuumPage(XLogRecPtr lsn, XLogRecord *record)
|
||||
{
|
||||
ginxlogVacuumPage *data = (ginxlogVacuumPage *) XLogRecGetData(record);
|
||||
Relation reln;
|
||||
Buffer buffer;
|
||||
|
@ -314,12 +347,16 @@ ginRedoVacuumPage(XLogRecPtr lsn, XLogRecord *record) {
|
|||
Assert(BufferIsValid(buffer));
|
||||
page = (Page) BufferGetPage(buffer);
|
||||
|
||||
if ( GinPageIsData( page ) ) {
|
||||
if (GinPageIsData(page))
|
||||
{
|
||||
memcpy(GinDataPageGetData(page), XLogRecGetData(record) + sizeof(ginxlogVacuumPage),
|
||||
GinSizeOfItem(page) *data->nitem);
|
||||
GinPageGetOpaque(page)->maxoff = data->nitem;
|
||||
} else {
|
||||
OffsetNumber i, *tod;
|
||||
}
|
||||
else
|
||||
{
|
||||
OffsetNumber i,
|
||||
*tod;
|
||||
IndexTuple itup = (IndexTuple) (XLogRecGetData(record) + sizeof(ginxlogVacuumPage));
|
||||
|
||||
tod = (OffsetNumber *) palloc(sizeof(OffsetNumber) * PageGetMaxOffsetNumber(page));
|
||||
|
@ -328,7 +365,8 @@ ginRedoVacuumPage(XLogRecPtr lsn, XLogRecord *record) {
|
|||
|
||||
PageIndexMultiDelete(page, tod, PageGetMaxOffsetNumber(page));
|
||||
|
||||
for(i=0;i<data->nitem;i++) {
|
||||
for (i = 0; i < data->nitem; i++)
|
||||
{
|
||||
if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber)
|
||||
elog(ERROR, "failed to add item to index page in %u/%u/%u",
|
||||
data->node.spcNode, data->node.dbNode, data->node.relNode);
|
||||
|
@ -344,7 +382,8 @@ ginRedoVacuumPage(XLogRecPtr lsn, XLogRecord *record) {
|
|||
}
|
||||
|
||||
static void
|
||||
ginRedoDeletePage(XLogRecPtr lsn, XLogRecord *record) {
|
||||
ginRedoDeletePage(XLogRecPtr lsn, XLogRecord *record)
|
||||
{
|
||||
ginxlogDeletePage *data = (ginxlogDeletePage *) XLogRecGetData(record);
|
||||
Relation reln;
|
||||
Buffer buffer;
|
||||
|
@ -352,7 +391,8 @@ ginRedoDeletePage(XLogRecPtr lsn, XLogRecord *record) {
|
|||
|
||||
reln = XLogOpenRelation(data->node);
|
||||
|
||||
if ( !( record->xl_info & XLR_BKP_BLOCK_1) ) {
|
||||
if (!(record->xl_info & XLR_BKP_BLOCK_1))
|
||||
{
|
||||
buffer = XLogReadBuffer(reln, data->blkno, false);
|
||||
page = BufferGetPage(buffer);
|
||||
Assert(GinPageIsData(page));
|
||||
|
@ -363,7 +403,8 @@ ginRedoDeletePage(XLogRecPtr lsn, XLogRecord *record) {
|
|||
UnlockReleaseBuffer(buffer);
|
||||
}
|
||||
|
||||
if ( !( record->xl_info & XLR_BKP_BLOCK_2) ) {
|
||||
if (!(record->xl_info & XLR_BKP_BLOCK_2))
|
||||
{
|
||||
buffer = XLogReadBuffer(reln, data->parentBlkno, false);
|
||||
page = BufferGetPage(buffer);
|
||||
Assert(GinPageIsData(page));
|
||||
|
@ -375,7 +416,8 @@ ginRedoDeletePage(XLogRecPtr lsn, XLogRecord *record) {
|
|||
UnlockReleaseBuffer(buffer);
|
||||
}
|
||||
|
||||
if ( !( record->xl_info & XLR_BKP_BLOCK_2) && data->leftBlkno != InvalidBlockNumber ) {
|
||||
if (!(record->xl_info & XLR_BKP_BLOCK_2) && data->leftBlkno != InvalidBlockNumber)
|
||||
{
|
||||
buffer = XLogReadBuffer(reln, data->leftBlkno, false);
|
||||
page = BufferGetPage(buffer);
|
||||
Assert(GinPageIsData(page));
|
||||
|
@ -388,11 +430,13 @@ ginRedoDeletePage(XLogRecPtr lsn, XLogRecord *record) {
|
|||
}
|
||||
|
||||
void
|
||||
gin_redo(XLogRecPtr lsn, XLogRecord *record) {
|
||||
gin_redo(XLogRecPtr lsn, XLogRecord *record)
|
||||
{
|
||||
uint8 info = record->xl_info & ~XLR_INFO_MASK;
|
||||
|
||||
topCtx = MemoryContextSwitchTo(opCtx);
|
||||
switch (info) {
|
||||
switch (info)
|
||||
{
|
||||
case XLOG_GIN_CREATE_INDEX:
|
||||
ginRedoCreateIndex(lsn, record);
|
||||
break;
|
||||
|
@ -419,16 +463,19 @@ gin_redo(XLogRecPtr lsn, XLogRecord *record) {
|
|||
}
|
||||
|
||||
static void
|
||||
desc_node( StringInfo buf, RelFileNode node, BlockNumber blkno ) {
|
||||
desc_node(StringInfo buf, RelFileNode node, BlockNumber blkno)
|
||||
{
|
||||
appendStringInfo(buf, "node: %u/%u/%u blkno: %u",
|
||||
node.spcNode, node.dbNode, node.relNode, blkno);
|
||||
}
|
||||
|
||||
void
|
||||
gin_desc(StringInfo buf, uint8 xl_info, char *rec) {
|
||||
gin_desc(StringInfo buf, uint8 xl_info, char *rec)
|
||||
{
|
||||
uint8 info = xl_info & ~XLR_INFO_MASK;
|
||||
|
||||
switch (info) {
|
||||
switch (info)
|
||||
{
|
||||
case XLOG_GIN_CREATE_INDEX:
|
||||
appendStringInfo(buf, "Create index, ");
|
||||
desc_node(buf, *(RelFileNode *) rec, GIN_ROOT_BLKNO);
|
||||
|
@ -469,7 +516,8 @@ gin_desc(StringInfo buf, uint8 xl_info, char *rec) {
|
|||
}
|
||||
|
||||
void
|
||||
gin_xlog_startup(void) {
|
||||
gin_xlog_startup(void)
|
||||
{
|
||||
incomplete_splits = NIL;
|
||||
|
||||
opCtx = AllocSetContextCreate(CurrentMemoryContext,
|
||||
|
@ -480,21 +528,28 @@ gin_xlog_startup(void) {
|
|||
}
|
||||
|
||||
static void
|
||||
ginContinueSplit( ginIncompleteSplit *split ) {
|
||||
ginContinueSplit(ginIncompleteSplit *split)
|
||||
{
|
||||
GinBtreeData btree;
|
||||
Relation reln;
|
||||
Buffer buffer;
|
||||
GinBtreeStack stack;
|
||||
|
||||
/* elog(NOTICE,"ginContinueSplit root:%u l:%u r:%u", split->rootBlkno, split->leftBlkno, split->rightBlkno); */
|
||||
/*
|
||||
* elog(NOTICE,"ginContinueSplit root:%u l:%u r:%u", split->rootBlkno,
|
||||
* split->leftBlkno, split->rightBlkno);
|
||||
*/
|
||||
reln = XLogOpenRelation(split->node);
|
||||
|
||||
buffer = XLogReadBuffer(reln, split->leftBlkno, false);
|
||||
|
||||
if ( split->rootBlkno == GIN_ROOT_BLKNO ) {
|
||||
if (split->rootBlkno == GIN_ROOT_BLKNO)
|
||||
{
|
||||
prepareEntryScan(&btree, reln, (Datum) 0, NULL);
|
||||
btree.entry = ginPageGetLinkItup(buffer);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Page page = BufferGetPage(buffer);
|
||||
|
||||
prepareDataScan(&btree, reln);
|
||||
|
@ -522,7 +577,8 @@ ginContinueSplit( ginIncompleteSplit *split ) {
|
|||
}
|
||||
|
||||
void
|
||||
gin_xlog_cleanup(void) {
|
||||
gin_xlog_cleanup(void)
|
||||
{
|
||||
ListCell *l;
|
||||
MemoryContext topCtx;
|
||||
|
||||
|
@ -531,6 +587,7 @@ gin_xlog_cleanup(void) {
|
|||
foreach(l, incomplete_splits)
|
||||
{
|
||||
ginIncompleteSplit *split = (ginIncompleteSplit *) lfirst(l);
|
||||
|
||||
ginContinueSplit(split);
|
||||
MemoryContextReset(opCtx);
|
||||
}
|
||||
|
|
|
@ -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.142 2006/07/14 14:52:16 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.143 2006/10/04 00:29:48 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -285,18 +285,17 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
|
|||
bool is_leaf = (GistPageIsLeaf(state->stack->page)) ? true : false;
|
||||
|
||||
/*
|
||||
* if (!is_leaf) remove old key:
|
||||
* This node's key has been modified, either because a child split
|
||||
* occurred or because we needed to adjust our key for an insert in a
|
||||
* child node. Therefore, remove the old version of this node's key.
|
||||
* if (!is_leaf) remove old key: This node's key has been modified, either
|
||||
* because a child split occurred or because we needed to adjust our key
|
||||
* for an insert in a child node. Therefore, remove the old version of
|
||||
* this node's key.
|
||||
*
|
||||
* for WAL replay, in the non-split case we handle this by
|
||||
* setting up a one-element todelete array; in the split case, it's
|
||||
* handled implicitly because the tuple vector passed to gistSplit
|
||||
* won't include this tuple.
|
||||
* for WAL replay, in the non-split case we handle this by setting up a
|
||||
* one-element todelete array; in the split case, it's handled implicitly
|
||||
* because the tuple vector passed to gistSplit won't include this tuple.
|
||||
*
|
||||
* XXX: If we want to change fillfactors between node and leaf,
|
||||
* fillfactor = (is_leaf ? state->leaf_fillfactor : state->node_fillfactor)
|
||||
* XXX: If we want to change fillfactors between node and leaf, fillfactor
|
||||
* = (is_leaf ? state->leaf_fillfactor : state->node_fillfactor)
|
||||
*/
|
||||
if (gistnospace(state->stack->page, state->itup, state->ituplen,
|
||||
is_leaf ? InvalidOffsetNumber : state->stack->childoffnum,
|
||||
|
@ -313,11 +312,12 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
|
|||
is_splitted = true;
|
||||
|
||||
/*
|
||||
* Form index tuples vector to split:
|
||||
* remove old tuple if t's needed and add new tuples to vector
|
||||
* Form index tuples vector to split: remove old tuple if t's needed
|
||||
* and add new tuples to vector
|
||||
*/
|
||||
itvec = gistextractpage(state->stack->page, &tlen);
|
||||
if ( !is_leaf ) {
|
||||
if (!is_leaf)
|
||||
{
|
||||
/* on inner page we should remove old tuple */
|
||||
int pos = state->stack->childoffnum - FirstOffsetNumber;
|
||||
|
||||
|
@ -331,9 +331,12 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
|
|||
state->itup = (IndexTuple *) palloc(sizeof(IndexTuple) * tlen);
|
||||
state->ituplen = 0;
|
||||
|
||||
if (state->stack->blkno != GIST_ROOT_BLKNO) {
|
||||
/* if non-root split then we should not allocate new buffer,
|
||||
but we must create temporary page to operate */
|
||||
if (state->stack->blkno != GIST_ROOT_BLKNO)
|
||||
{
|
||||
/*
|
||||
* if non-root split then we should not allocate new buffer, but
|
||||
* we must create temporary page to operate
|
||||
*/
|
||||
dist->buffer = state->stack->buffer;
|
||||
dist->page = PageGetTempPage(BufferGetPage(dist->buffer), sizeof(GISTPageOpaqueData));
|
||||
|
||||
|
@ -342,22 +345,27 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
|
|||
}
|
||||
|
||||
/* make new pages and fills them */
|
||||
for (ptr = dist; ptr; ptr = ptr->next) {
|
||||
for (ptr = dist; ptr; ptr = ptr->next)
|
||||
{
|
||||
int i;
|
||||
char *data;
|
||||
|
||||
/* get new page */
|
||||
if ( ptr->buffer == InvalidBuffer ) {
|
||||
if (ptr->buffer == InvalidBuffer)
|
||||
{
|
||||
ptr->buffer = gistNewBuffer(state->r);
|
||||
GISTInitBuffer(ptr->buffer, (is_leaf) ? F_LEAF : 0);
|
||||
ptr->page = BufferGetPage(ptr->buffer);
|
||||
}
|
||||
ptr->block.blkno = BufferGetBlockNumber(ptr->buffer);
|
||||
|
||||
/* fill page, we can do it becouse all this pages are new (ie not linked in tree
|
||||
or masked by temp page */
|
||||
/*
|
||||
* fill page, we can do it becouse all this pages are new (ie not
|
||||
* linked in tree or masked by temp page
|
||||
*/
|
||||
data = (char *) (ptr->list);
|
||||
for(i=0;i<ptr->block.num;i++) {
|
||||
for (i = 0; i < ptr->block.num; i++)
|
||||
{
|
||||
if (PageAddItem(ptr->page, (Item) data, IndexTupleSize((IndexTuple) data), i + FirstOffsetNumber, LP_USED) == InvalidOffsetNumber)
|
||||
elog(ERROR, "failed to add item to index page in \"%s\"", RelationGetRelationName(state->r));
|
||||
data += IndexTupleSize((IndexTuple) data);
|
||||
|
@ -376,9 +384,8 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
|
|||
START_CRIT_SECTION();
|
||||
|
||||
/*
|
||||
* must mark buffers dirty before XLogInsert, even though we'll
|
||||
* still be changing their opaque fields below.
|
||||
* set up right links.
|
||||
* must mark buffers dirty before XLogInsert, even though we'll still
|
||||
* be changing their opaque fields below. set up right links.
|
||||
*/
|
||||
for (ptr = dist; ptr; ptr = ptr->next)
|
||||
{
|
||||
|
@ -388,7 +395,8 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
|
|||
}
|
||||
|
||||
/* restore splitted non-root page */
|
||||
if ( state->stack->blkno != GIST_ROOT_BLKNO ) {
|
||||
if (state->stack->blkno != GIST_ROOT_BLKNO)
|
||||
{
|
||||
PageRestoreTempPage(dist->page, BufferGetPage(dist->buffer));
|
||||
dist->page = BufferGetPage(dist->buffer);
|
||||
}
|
||||
|
@ -423,21 +431,23 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
|
|||
/* if root split we should put initial value */
|
||||
oldnsn = PageGetLSN(dist->page);
|
||||
|
||||
for (ptr = dist; ptr; ptr = ptr->next) {
|
||||
for (ptr = dist; ptr; ptr = ptr->next)
|
||||
{
|
||||
/* only for last set oldnsn */
|
||||
GistPageGetOpaque(ptr->page)->nsn = (ptr->next) ?
|
||||
PageGetLSN(ptr->page) : oldnsn;
|
||||
}
|
||||
|
||||
/*
|
||||
* release buffers, if it was a root split then
|
||||
* release all buffers because we create all buffers
|
||||
* release buffers, if it was a root split then release all buffers
|
||||
* because we create all buffers
|
||||
*/
|
||||
ptr = (state->stack->blkno == GIST_ROOT_BLKNO) ? dist : dist->next;
|
||||
for (; ptr; ptr = ptr->next)
|
||||
UnlockReleaseBuffer(ptr->buffer);
|
||||
|
||||
if (state->stack->blkno == GIST_ROOT_BLKNO) {
|
||||
if (state->stack->blkno == GIST_ROOT_BLKNO)
|
||||
{
|
||||
gistnewroot(state->r, state->stack->buffer, state->itup, state->ituplen, &(state->key));
|
||||
state->needInsertComplete = false;
|
||||
}
|
||||
|
@ -959,7 +969,8 @@ gistSplit(Relation r,
|
|||
|
||||
if (!gistfitpage(lvectup, v.splitVector.spl_nleft))
|
||||
{
|
||||
SplitedPageLayout *resptr, *subres;
|
||||
SplitedPageLayout *resptr,
|
||||
*subres;
|
||||
|
||||
resptr = subres = gistSplit(r, page, lvectup, v.splitVector.spl_nleft, giststate);
|
||||
|
||||
|
|
|
@ -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.60 2006/07/14 14:52:16 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistget.c,v 1.61 2006/10/04 00:29:48 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -360,8 +360,7 @@ gistindex_keytest(IndexTuple tuple,
|
|||
IncrIndexProcessed();
|
||||
|
||||
/*
|
||||
* Tuple doesn't restore after crash recovery because of incomplete
|
||||
* insert
|
||||
* Tuple doesn't restore after crash recovery because of incomplete insert
|
||||
*/
|
||||
if (!GistPageIsLeaf(p) && GistTupleIsInvalid(tuple))
|
||||
return true;
|
||||
|
@ -378,14 +377,18 @@ gistindex_keytest(IndexTuple tuple,
|
|||
giststate->tupdesc,
|
||||
&isNull);
|
||||
|
||||
if ( key->sk_flags & SK_ISNULL ) {
|
||||
/* is the compared-to datum NULL? on non-leaf page it's possible
|
||||
to have nulls in childs :( */
|
||||
if (key->sk_flags & SK_ISNULL)
|
||||
{
|
||||
/*
|
||||
* is the compared-to datum NULL? on non-leaf page it's possible
|
||||
* to have nulls in childs :(
|
||||
*/
|
||||
|
||||
if (isNull || !GistPageIsLeaf(p))
|
||||
return true;
|
||||
return false;
|
||||
} else if ( isNull )
|
||||
}
|
||||
else if (isNull)
|
||||
return false;
|
||||
|
||||
gistdentryinit(giststate, key->sk_attno - 1, &de,
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistproc.c,v 1.8 2006/09/10 00:29:34 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistproc.c,v 1.9 2006/10/04 00:29:48 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -112,7 +112,8 @@ gist_box_consistent(PG_FUNCTION_ARGS)
|
|||
}
|
||||
|
||||
static void
|
||||
adjustBox( BOX *b, BOX *addon ) {
|
||||
adjustBox(BOX *b, BOX *addon)
|
||||
{
|
||||
if (b->high.x < addon->high.x)
|
||||
b->high.x = addon->high.x;
|
||||
if (b->low.x > addon->low.x)
|
||||
|
@ -216,11 +217,16 @@ chooseLR( GIST_SPLITVEC *v,
|
|||
{
|
||||
bool firstToLeft = true;
|
||||
|
||||
if ( v->spl_ldatum_exists || v->spl_rdatum_exists ) {
|
||||
if ( v->spl_ldatum_exists && v->spl_rdatum_exists ) {
|
||||
BOX LRl = *union1, LRr = *union2;
|
||||
BOX RLl = *union2, RLr = *union1;
|
||||
double sizeLR, sizeRL;
|
||||
if (v->spl_ldatum_exists || v->spl_rdatum_exists)
|
||||
{
|
||||
if (v->spl_ldatum_exists && v->spl_rdatum_exists)
|
||||
{
|
||||
BOX LRl = *union1,
|
||||
LRr = *union2;
|
||||
BOX RLl = *union2,
|
||||
RLr = *union1;
|
||||
double sizeLR,
|
||||
sizeRL;
|
||||
|
||||
adjustBox(&LRl, DatumGetBoxP(v->spl_ldatum));
|
||||
adjustBox(&LRr, DatumGetBoxP(v->spl_rdatum));
|
||||
|
@ -233,9 +239,13 @@ chooseLR( GIST_SPLITVEC *v,
|
|||
if (sizeLR > sizeRL)
|
||||
firstToLeft = false;
|
||||
|
||||
} else {
|
||||
float p1, p2;
|
||||
GISTENTRY oldUnion, addon;
|
||||
}
|
||||
else
|
||||
{
|
||||
float p1,
|
||||
p2;
|
||||
GISTENTRY oldUnion,
|
||||
addon;
|
||||
|
||||
gistentryinit(oldUnion, (v->spl_ldatum_exists) ? v->spl_ldatum : v->spl_rdatum,
|
||||
NULL, NULL, InvalidOffsetNumber, FALSE);
|
||||
|
@ -250,7 +260,8 @@ chooseLR( GIST_SPLITVEC *v,
|
|||
}
|
||||
}
|
||||
|
||||
if ( firstToLeft ) {
|
||||
if (firstToLeft)
|
||||
{
|
||||
v->spl_left = list1;
|
||||
v->spl_right = list2;
|
||||
v->spl_nleft = nlist1;
|
||||
|
@ -261,7 +272,9 @@ chooseLR( GIST_SPLITVEC *v,
|
|||
if (v->spl_rdatum_exists)
|
||||
adjustBox(union2, DatumGetBoxP(v->spl_rdatum));
|
||||
v->spl_rdatum = BoxPGetDatum(union2);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
v->spl_left = list2;
|
||||
v->spl_right = list1;
|
||||
v->spl_nleft = nlist2;
|
||||
|
|
|
@ -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.64 2006/07/14 14:52:16 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistscan.c,v 1.65 2006/10/04 00:29:48 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -232,8 +232,8 @@ gistfreestack(GISTSearchStack *s)
|
|||
while (s != NULL)
|
||||
{
|
||||
GISTSearchStack *p = s->next;
|
||||
|
||||
pfree(s);
|
||||
s = p;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistsplit.c,v 1.2 2006/07/14 14:52:16 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistsplit.c,v 1.3 2006/10/04 00:29:48 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -16,7 +16,8 @@
|
|||
|
||||
#include "access/gist_private.h"
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
Datum *attr;
|
||||
int len;
|
||||
OffsetNumber *entries;
|
||||
|
@ -31,13 +32,16 @@ typedef struct {
|
|||
*/
|
||||
static void
|
||||
gistunionsubkeyvec(GISTSTATE *giststate, IndexTuple *itvec,
|
||||
GistSplitUnion *gsvp, int startkey) {
|
||||
GistSplitUnion *gsvp, int startkey)
|
||||
{
|
||||
IndexTuple *cleanedItVec;
|
||||
int i, cleanedLen=0;
|
||||
int i,
|
||||
cleanedLen = 0;
|
||||
|
||||
cleanedItVec = (IndexTuple *) palloc(sizeof(IndexTuple) * gsvp->len);
|
||||
|
||||
for(i=0;i<gsvp->len;i++) {
|
||||
for (i = 0; i < gsvp->len; i++)
|
||||
{
|
||||
if (gsvp->equiv && gsvp->equiv[gsvp->entries[i]])
|
||||
continue;
|
||||
|
||||
|
@ -86,24 +90,30 @@ gistfindgroup(Relation r, GISTSTATE *giststate, GISTENTRY *valvec, GistSplitVect
|
|||
int len = 0;
|
||||
|
||||
/*
|
||||
* attno key is always not null (see gistSplitByKey), so we may not check for
|
||||
* nulls
|
||||
* attno key is always not null (see gistSplitByKey), so we may not check
|
||||
* for nulls
|
||||
*/
|
||||
gistentryinit(entry, spl->splitVector.spl_rdatum, r, NULL, (OffsetNumber) 0, FALSE);
|
||||
for (i = 0; i < spl->splitVector.spl_nleft; i++) {
|
||||
for (i = 0; i < spl->splitVector.spl_nleft; i++)
|
||||
{
|
||||
float penalty = gistpenalty(giststate, attno, &entry, false,
|
||||
&valvec[spl->splitVector.spl_left[i]], false);
|
||||
if ( penalty == 0.0 ) {
|
||||
|
||||
if (penalty == 0.0)
|
||||
{
|
||||
spl->spl_equiv[spl->splitVector.spl_left[i]] = true;
|
||||
len++;
|
||||
}
|
||||
}
|
||||
|
||||
gistentryinit(entry, spl->splitVector.spl_ldatum, r, NULL, (OffsetNumber) 0, FALSE);
|
||||
for (i = 0; i < spl->splitVector.spl_nright; i++) {
|
||||
for (i = 0; i < spl->splitVector.spl_nright; i++)
|
||||
{
|
||||
float penalty = gistpenalty(giststate, attno, &entry, false,
|
||||
&valvec[spl->splitVector.spl_right[i]], false);
|
||||
if ( penalty == 0.0 ) {
|
||||
|
||||
if (penalty == 0.0)
|
||||
{
|
||||
spl->spl_equiv[spl->splitVector.spl_right[i]] = true;
|
||||
len++;
|
||||
}
|
||||
|
@ -113,24 +123,32 @@ gistfindgroup(Relation r, GISTSTATE *giststate, GISTENTRY *valvec, GistSplitVect
|
|||
}
|
||||
|
||||
static void
|
||||
cleanupOffsets( OffsetNumber *a, int *len, bool *equiv, int *LenEquiv ) {
|
||||
int curlen,i;
|
||||
cleanupOffsets(OffsetNumber *a, int *len, bool *equiv, int *LenEquiv)
|
||||
{
|
||||
int curlen,
|
||||
i;
|
||||
OffsetNumber *curwpos;
|
||||
|
||||
curlen = *len;
|
||||
curwpos = a;
|
||||
for (i = 0; i < *len; i++) {
|
||||
if ( equiv[ a[i] ] == FALSE ) {
|
||||
for (i = 0; i < *len; i++)
|
||||
{
|
||||
if (equiv[a[i]] == FALSE)
|
||||
{
|
||||
*curwpos = a[i];
|
||||
curwpos++;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* corner case: we shouldn't make void array */
|
||||
if ( curlen==1 ) {
|
||||
if (curlen == 1)
|
||||
{
|
||||
equiv[a[i]] = FALSE; /* mark item as non-equivalent */
|
||||
i--; /* redo the same */
|
||||
*LenEquiv -= 1;
|
||||
continue;
|
||||
} else
|
||||
}
|
||||
else
|
||||
curlen--;
|
||||
}
|
||||
}
|
||||
|
@ -139,15 +157,18 @@ cleanupOffsets( OffsetNumber *a, int *len, bool *equiv, int *LenEquiv ) {
|
|||
}
|
||||
|
||||
static void
|
||||
placeOne( Relation r, GISTSTATE *giststate, GistSplitVector *v, IndexTuple itup, OffsetNumber off, int attno ) {
|
||||
placeOne(Relation r, GISTSTATE *giststate, GistSplitVector *v, IndexTuple itup, OffsetNumber off, int attno)
|
||||
{
|
||||
GISTENTRY identry[INDEX_MAX_KEYS];
|
||||
bool isnull[INDEX_MAX_KEYS];
|
||||
bool toLeft = true;
|
||||
|
||||
gistDeCompressAtt(giststate, r, itup, NULL, (OffsetNumber) 0, identry, isnull);
|
||||
|
||||
for(;attno<giststate->tupdesc->natts;attno++) {
|
||||
float lpenalty, rpenalty;
|
||||
for (; attno < giststate->tupdesc->natts; attno++)
|
||||
{
|
||||
float lpenalty,
|
||||
rpenalty;
|
||||
GISTENTRY entry;
|
||||
|
||||
gistentryinit(entry, v->spl_lattr[attno], r, NULL, 0, FALSE);
|
||||
|
@ -155,7 +176,8 @@ placeOne( Relation r, GISTSTATE *giststate, GistSplitVector *v, IndexTuple itup,
|
|||
gistentryinit(entry, v->spl_rattr[attno], r, NULL, 0, FALSE);
|
||||
rpenalty = gistpenalty(giststate, attno, &entry, v->spl_risnull[attno], identry + attno, isnull[attno]);
|
||||
|
||||
if ( lpenalty != rpenalty ) {
|
||||
if (lpenalty != rpenalty)
|
||||
{
|
||||
if (lpenalty > rpenalty)
|
||||
toLeft = false;
|
||||
break;
|
||||
|
@ -182,17 +204,24 @@ do { \
|
|||
*/
|
||||
|
||||
static void
|
||||
supportSecondarySplit( Relation r, GISTSTATE *giststate, int attno, GIST_SPLITVEC *sv, Datum oldL, Datum oldR ) {
|
||||
bool leaveOnLeft = true, tmpBool;
|
||||
GISTENTRY entryL, entryR, entrySL, entrySR;
|
||||
supportSecondarySplit(Relation r, GISTSTATE *giststate, int attno, GIST_SPLITVEC *sv, Datum oldL, Datum oldR)
|
||||
{
|
||||
bool leaveOnLeft = true,
|
||||
tmpBool;
|
||||
GISTENTRY entryL,
|
||||
entryR,
|
||||
entrySL,
|
||||
entrySR;
|
||||
|
||||
gistentryinit(entryL, oldL, r, NULL, 0, FALSE);
|
||||
gistentryinit(entryR, oldR, r, NULL, 0, FALSE);
|
||||
gistentryinit(entrySL, sv->spl_ldatum, r, NULL, 0, FALSE);
|
||||
gistentryinit(entrySR, sv->spl_rdatum, r, NULL, 0, FALSE);
|
||||
|
||||
if ( sv->spl_ldatum_exists && sv->spl_rdatum_exists ) {
|
||||
float penalty1, penalty2;
|
||||
if (sv->spl_ldatum_exists && sv->spl_rdatum_exists)
|
||||
{
|
||||
float penalty1,
|
||||
penalty2;
|
||||
|
||||
penalty1 = gistpenalty(giststate, attno, &entryL, false, &entrySL, false) +
|
||||
gistpenalty(giststate, attno, &entryR, false, &entrySR, false);
|
||||
|
@ -202,13 +231,16 @@ supportSecondarySplit( Relation r, GISTSTATE *giststate, int attno, GIST_SPLITVE
|
|||
if (penalty1 > penalty2)
|
||||
leaveOnLeft = false;
|
||||
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
GISTENTRY *entry1 = (sv->spl_ldatum_exists) ? &entryL : &entryR;
|
||||
float penalty1, penalty2;
|
||||
float penalty1,
|
||||
penalty2;
|
||||
|
||||
/*
|
||||
* there is only one previously defined union,
|
||||
* so we just choose swap or not by lowest penalty
|
||||
* there is only one previously defined union, so we just choose swap
|
||||
* or not by lowest penalty
|
||||
*/
|
||||
|
||||
penalty1 = gistpenalty(giststate, attno, entry1, false, &entrySL, false);
|
||||
|
@ -220,11 +252,13 @@ supportSecondarySplit( Relation r, GISTSTATE *giststate, int attno, GIST_SPLITVE
|
|||
leaveOnLeft = (sv->spl_rdatum_exists) ? true : false;
|
||||
}
|
||||
|
||||
if ( leaveOnLeft == false ) {
|
||||
if (leaveOnLeft == false)
|
||||
{
|
||||
/*
|
||||
* swap left and right
|
||||
*/
|
||||
OffsetNumber *off, noff;
|
||||
OffsetNumber *off,
|
||||
noff;
|
||||
Datum datum;
|
||||
|
||||
SWAPVAR(sv->spl_left, sv->spl_right, off);
|
||||
|
@ -258,6 +292,7 @@ gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVec
|
|||
IndexTuple *itup, int len, GISTSTATE *giststate)
|
||||
{
|
||||
GIST_SPLITVEC *sv = &v->splitVector;
|
||||
|
||||
/*
|
||||
* now let the user-defined picksplit function set up the split vector; in
|
||||
* entryvec have no null value!!
|
||||
|
@ -278,7 +313,8 @@ gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVec
|
|||
if (sv->spl_right[sv->spl_nright - 1] == InvalidOffsetNumber)
|
||||
sv->spl_right[sv->spl_nright - 1] = (OffsetNumber) (entryvec->n - 1);
|
||||
|
||||
if( sv->spl_ldatum_exists || sv->spl_rdatum_exists ) {
|
||||
if (sv->spl_ldatum_exists || sv->spl_rdatum_exists)
|
||||
{
|
||||
elog(LOG, "PickSplit method of %d columns of index '%s' doesn't support secondary split",
|
||||
attno + 1, RelationGetRelationName(r));
|
||||
|
||||
|
@ -298,15 +334,18 @@ gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVec
|
|||
|
||||
if (giststate->tupdesc->natts > 1 && attno + 1 != giststate->tupdesc->natts)
|
||||
{
|
||||
if ( gistKeyIsEQ(giststate, attno, sv->spl_ldatum, sv->spl_rdatum) ) {
|
||||
if (gistKeyIsEQ(giststate, attno, sv->spl_ldatum, sv->spl_rdatum))
|
||||
{
|
||||
/*
|
||||
* Left and right key's unions are equial, so
|
||||
* we can get better split by following columns. Note,
|
||||
* unions for attno columns are already done.
|
||||
* Left and right key's unions are equial, so we can get better
|
||||
* split by following columns. Note, unions for attno columns are
|
||||
* already done.
|
||||
*/
|
||||
|
||||
return true;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
int LenEquiv;
|
||||
|
||||
v->spl_equiv = (bool *) palloc0(sizeof(bool) * (entryvec->n + 1));
|
||||
|
@ -316,17 +355,21 @@ gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVec
|
|||
/*
|
||||
* if possible, we should distribute equivalent tuples
|
||||
*/
|
||||
if (LenEquiv == 0 ) {
|
||||
if (LenEquiv == 0)
|
||||
{
|
||||
gistunionsubkey(giststate, itup, v, attno + 1);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
cleanupOffsets(sv->spl_left, &sv->spl_nleft, v->spl_equiv, &LenEquiv);
|
||||
cleanupOffsets(sv->spl_right, &sv->spl_nright, v->spl_equiv, &LenEquiv);
|
||||
|
||||
gistunionsubkey(giststate, itup, v, attno + 1);
|
||||
if (LenEquiv == 1 ) {
|
||||
if (LenEquiv == 1)
|
||||
{
|
||||
/*
|
||||
* In case with one tuple we just choose left-right
|
||||
* by penalty. It's simplify user-defined pickSplit
|
||||
* In case with one tuple we just choose left-right by
|
||||
* penalty. It's simplify user-defined pickSplit
|
||||
*/
|
||||
OffsetNumber toMove = InvalidOffsetNumber;
|
||||
|
||||
|
@ -336,13 +379,17 @@ gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVec
|
|||
Assert(toMove < entryvec->n);
|
||||
|
||||
placeOne(r, giststate, v, itup[toMove - 1], toMove, attno + 1);
|
||||
/* redo gistunionsubkey(): it will not degradate performance,
|
||||
* because it's very rarely */
|
||||
|
||||
/*
|
||||
* redo gistunionsubkey(): it will not degradate
|
||||
* performance, because it's very rarely
|
||||
*/
|
||||
v->spl_equiv = NULL;
|
||||
gistunionsubkey(giststate, itup, v, attno + 1);
|
||||
|
||||
return false;
|
||||
} else if ( LenEquiv > 1 )
|
||||
}
|
||||
else if (LenEquiv > 1)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -355,7 +402,8 @@ gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVec
|
|||
* simple split page
|
||||
*/
|
||||
static void
|
||||
gistSplitHalf(GIST_SPLITVEC *v, int len) {
|
||||
gistSplitHalf(GIST_SPLITVEC *v, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
v->spl_nright = v->spl_nleft = 0;
|
||||
|
@ -379,7 +427,8 @@ gistSplitHalf(GIST_SPLITVEC *v, int len) {
|
|||
* to get 'invalid' tuples (probability is low enough)
|
||||
*/
|
||||
static void
|
||||
gistSplitByInvalid(GISTSTATE *giststate, GistSplitVector *v, IndexTuple *itup, int len) {
|
||||
gistSplitByInvalid(GISTSTATE *giststate, GistSplitVector *v, IndexTuple *itup, int len)
|
||||
{
|
||||
int i;
|
||||
static OffsetNumber offInvTuples[MaxOffsetNumber];
|
||||
int nOffInvTuples = 0;
|
||||
|
@ -388,11 +437,14 @@ gistSplitByInvalid(GISTSTATE *giststate, GistSplitVector *v, IndexTuple *itup, i
|
|||
if (GistTupleIsInvalid(itup[i - 1]))
|
||||
offInvTuples[nOffInvTuples++] = i;
|
||||
|
||||
if ( nOffInvTuples == len ) {
|
||||
if (nOffInvTuples == len)
|
||||
{
|
||||
/* corner case, all tuples are invalid */
|
||||
v->spl_rightvalid = v->spl_leftvalid = false;
|
||||
gistSplitHalf(&v->splitVector, len);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
GistSplitUnion gsvp;
|
||||
|
||||
v->splitVector.spl_right = offInvTuples;
|
||||
|
@ -422,16 +474,19 @@ gistSplitByInvalid(GISTSTATE *giststate, GistSplitVector *v, IndexTuple *itup, i
|
|||
*/
|
||||
void
|
||||
gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *giststate,
|
||||
GistSplitVector *v, GistEntryVector *entryvec, int attno) {
|
||||
GistSplitVector *v, GistEntryVector *entryvec, int attno)
|
||||
{
|
||||
int i;
|
||||
static OffsetNumber offNullTuples[MaxOffsetNumber];
|
||||
int nOffNullTuples = 0;
|
||||
|
||||
for (i = 1; i <= len; i++) {
|
||||
for (i = 1; i <= len; i++)
|
||||
{
|
||||
Datum datum;
|
||||
bool IsNull;
|
||||
|
||||
if (!GistPageIsLeaf(page) && GistTupleIsInvalid(itup[i - 1])) {
|
||||
if (!GistPageIsLeaf(page) && GistTupleIsInvalid(itup[i - 1]))
|
||||
{
|
||||
gistSplitByInvalid(giststate, v, itup, len);
|
||||
return;
|
||||
}
|
||||
|
@ -446,11 +501,12 @@ gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *gist
|
|||
|
||||
v->spl_leftvalid = v->spl_rightvalid = true;
|
||||
|
||||
if ( nOffNullTuples == len ) {
|
||||
if (nOffNullTuples == len)
|
||||
{
|
||||
/*
|
||||
* Corner case: All keys in attno column are null, we should try to
|
||||
* split by keys in next column. It all keys in all columns
|
||||
* are NULL just split page half by half
|
||||
* split by keys in next column. It all keys in all columns are NULL
|
||||
* just split page half by half
|
||||
*/
|
||||
v->spl_risnull[attno] = v->spl_lisnull[attno] = TRUE;
|
||||
|
||||
|
@ -458,12 +514,14 @@ gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *gist
|
|||
gistSplitHalf(&v->splitVector, len);
|
||||
else
|
||||
gistSplitByKey(r, page, itup, len, giststate, v, entryvec, attno + 1);
|
||||
} else if ( nOffNullTuples > 0 ) {
|
||||
}
|
||||
else if (nOffNullTuples > 0)
|
||||
{
|
||||
int j = 0;
|
||||
|
||||
/*
|
||||
* We don't want to mix NULLs and not-NULLs keys
|
||||
* on one page, so move nulls to right page
|
||||
* We don't want to mix NULLs and not-NULLs keys on one page, so move
|
||||
* nulls to right page
|
||||
*/
|
||||
v->splitVector.spl_right = offNullTuples;
|
||||
v->splitVector.spl_nright = nOffNullTuples;
|
||||
|
@ -479,22 +537,31 @@ gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *gist
|
|||
|
||||
v->spl_equiv = NULL;
|
||||
gistunionsubkey(giststate, itup, v, attno);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* all keys are not-null
|
||||
*/
|
||||
entryvec->n = len + 1;
|
||||
|
||||
if ( gistUserPicksplit(r, entryvec, attno, v, itup, len, giststate) && attno+1 != r->rd_att->natts ) {
|
||||
if (gistUserPicksplit(r, entryvec, attno, v, itup, len, giststate) && attno + 1 != r->rd_att->natts)
|
||||
{
|
||||
/*
|
||||
* Splitting on attno column is not optimized: there is a tuples which can be freely
|
||||
* left or right page, we will try to split page by
|
||||
* following columns
|
||||
* Splitting on attno column is not optimized: there is a tuples
|
||||
* which can be freely left or right page, we will try to split
|
||||
* page by following columns
|
||||
*/
|
||||
if (v->spl_equiv == NULL)
|
||||
{
|
||||
/*
|
||||
* simple case: left and right keys for attno column are
|
||||
* equial
|
||||
*/
|
||||
if ( v->spl_equiv == NULL ) {
|
||||
/* simple case: left and right keys for attno column are equial */
|
||||
gistSplitByKey(r, page, itup, len, giststate, v, entryvec, attno + 1);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* we should clean up vector from already distributed tuples */
|
||||
IndexTuple *newitup = (IndexTuple *) palloc((len + 1) * sizeof(IndexTuple));
|
||||
OffsetNumber *map = (OffsetNumber *) palloc((len + 1) * sizeof(IndexTuple));
|
||||
|
@ -502,7 +569,8 @@ gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *gist
|
|||
GIST_SPLITVEC backupSplit = v->splitVector;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
if ( v->spl_equiv[i+1] ) {
|
||||
if (v->spl_equiv[i + 1])
|
||||
{
|
||||
map[newlen] = i + 1;
|
||||
newitup[newlen++] = itup[i];
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistutil.c,v 1.19 2006/07/14 14:52:16 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistutil.c,v 1.20 2006/10/04 00:29:48 momjian Exp $
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
@ -57,14 +57,17 @@ gistfillbuffer(Relation r, Page page, IndexTuple *itup,
|
|||
bool
|
||||
gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace)
|
||||
{
|
||||
unsigned int size = freespace, deleted = 0;
|
||||
unsigned int size = freespace,
|
||||
deleted = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
size += IndexTupleSize(itvec[i]) + sizeof(ItemIdData);
|
||||
|
||||
if ( todelete != InvalidOffsetNumber ) {
|
||||
if (todelete != InvalidOffsetNumber)
|
||||
{
|
||||
IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, todelete));
|
||||
|
||||
deleted = IndexTupleSize(itup) + sizeof(ItemIdData);
|
||||
}
|
||||
|
||||
|
@ -72,7 +75,8 @@ gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size f
|
|||
}
|
||||
|
||||
bool
|
||||
gistfitpage(IndexTuple *itvec, int len) {
|
||||
gistfitpage(IndexTuple *itvec, int len)
|
||||
{
|
||||
int i;
|
||||
Size size = 0;
|
||||
|
||||
|
@ -119,8 +123,10 @@ gistjoinvector(IndexTuple *itvec, int *len, IndexTuple *additvec, int addlen)
|
|||
*/
|
||||
|
||||
IndexTupleData *
|
||||
gistfillitupvec(IndexTuple *vec, int veclen, int *memlen) {
|
||||
char *ptr, *ret;
|
||||
gistfillitupvec(IndexTuple *vec, int veclen, int *memlen)
|
||||
{
|
||||
char *ptr,
|
||||
*ret;
|
||||
int i;
|
||||
|
||||
*memlen = 0;
|
||||
|
@ -130,7 +136,8 @@ gistfillitupvec(IndexTuple *vec, int veclen, int *memlen) {
|
|||
|
||||
ptr = ret = palloc(*memlen);
|
||||
|
||||
for (i = 0; i < veclen; i++) {
|
||||
for (i = 0; i < veclen; i++)
|
||||
{
|
||||
memcpy(ptr, vec[i], IndexTupleSize(vec[i]));
|
||||
ptr += IndexTupleSize(vec[i]);
|
||||
}
|
||||
|
@ -145,30 +152,35 @@ gistfillitupvec(IndexTuple *vec, int veclen, int *memlen) {
|
|||
|
||||
bool
|
||||
gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len, int startkey,
|
||||
Datum *attr, bool *isnull ) {
|
||||
Datum *attr, bool *isnull)
|
||||
{
|
||||
int i;
|
||||
GistEntryVector *evec;
|
||||
int attrsize;
|
||||
|
||||
evec = (GistEntryVector *) palloc((len + 2) * sizeof(GISTENTRY) + GEVHDRSZ);
|
||||
|
||||
for (i = startkey; i < giststate->tupdesc->natts; i++) {
|
||||
for (i = startkey; i < giststate->tupdesc->natts; i++)
|
||||
{
|
||||
int j;
|
||||
|
||||
evec->n = 0;
|
||||
if ( !isnull[i] ) {
|
||||
if (!isnull[i])
|
||||
{
|
||||
gistentryinit(evec->vector[evec->n], attr[i],
|
||||
NULL, NULL, (OffsetNumber) 0,
|
||||
FALSE);
|
||||
evec->n++;
|
||||
}
|
||||
|
||||
for (j = 0; j < len; j++) {
|
||||
for (j = 0; j < len; j++)
|
||||
{
|
||||
Datum datum;
|
||||
bool IsNull;
|
||||
|
||||
if (GistTupleIsInvalid(itvec[j]))
|
||||
return FALSE; /* signals that union with invalid tuple => result is invalid */
|
||||
return FALSE; /* signals that union with invalid tuple =>
|
||||
* result is invalid */
|
||||
|
||||
datum = index_getattr(itvec[j], i + 1, giststate->tupdesc, &IsNull);
|
||||
if (IsNull)
|
||||
|
@ -183,11 +195,15 @@ gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len, int startke
|
|||
}
|
||||
|
||||
/* If this tuple vector was all NULLs, the union is NULL */
|
||||
if ( evec->n == 0 ) {
|
||||
if (evec->n == 0)
|
||||
{
|
||||
attr[i] = (Datum) 0;
|
||||
isnull[i] = TRUE;
|
||||
} else {
|
||||
if (evec->n == 1) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (evec->n == 1)
|
||||
{
|
||||
evec->n = 2;
|
||||
evec->vector[1] = evec->vector[0];
|
||||
}
|
||||
|
@ -226,7 +242,8 @@ void
|
|||
gistMakeUnionKey(GISTSTATE *giststate, int attno,
|
||||
GISTENTRY *entry1, bool isnull1,
|
||||
GISTENTRY *entry2, bool isnull2,
|
||||
Datum *dst, bool *dstisnull ) {
|
||||
Datum *dst, bool *dstisnull)
|
||||
{
|
||||
|
||||
int dstsize;
|
||||
|
||||
|
@ -235,17 +252,25 @@ gistMakeUnionKey( GISTSTATE *giststate, int attno,
|
|||
|
||||
evec->n = 2;
|
||||
|
||||
if ( isnull1 && isnull2 ) {
|
||||
if (isnull1 && isnull2)
|
||||
{
|
||||
*dstisnull = TRUE;
|
||||
*dst = (Datum) 0;
|
||||
} else {
|
||||
if ( isnull1 == FALSE && isnull2 == FALSE ) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isnull1 == FALSE && isnull2 == FALSE)
|
||||
{
|
||||
evec->vector[0] = *entry1;
|
||||
evec->vector[1] = *entry2;
|
||||
} else if ( isnull1 == FALSE ) {
|
||||
}
|
||||
else if (isnull1 == FALSE)
|
||||
{
|
||||
evec->vector[0] = *entry1;
|
||||
evec->vector[1] = *entry1;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
evec->vector[0] = *entry2;
|
||||
evec->vector[1] = *entry2;
|
||||
}
|
||||
|
@ -258,7 +283,8 @@ gistMakeUnionKey( GISTSTATE *giststate, int attno,
|
|||
}
|
||||
|
||||
bool
|
||||
gistKeyIsEQ(GISTSTATE *giststate, int attno, Datum a, Datum b) {
|
||||
gistKeyIsEQ(GISTSTATE *giststate, int attno, Datum a, Datum b)
|
||||
{
|
||||
bool result;
|
||||
|
||||
FunctionCall3(&giststate->equalFn[attno],
|
||||
|
@ -309,7 +335,8 @@ gistgetadjusted(Relation r, IndexTuple oldtup, IndexTuple addtup, GISTSTATE *gis
|
|||
gistDeCompressAtt(giststate, r, addtup, NULL,
|
||||
(OffsetNumber) 0, addentries, addisnull);
|
||||
|
||||
for(i = 0; i < r->rd_att->natts; i++) {
|
||||
for (i = 0; i < r->rd_att->natts; i++)
|
||||
{
|
||||
gistMakeUnionKey(giststate, i,
|
||||
oldentries + i, oldisnull[i],
|
||||
addentries + i, addisnull[i],
|
||||
|
@ -323,7 +350,8 @@ gistgetadjusted(Relation r, IndexTuple oldtup, IndexTuple addtup, GISTSTATE *gis
|
|||
/* union of key may be NULL if and only if both keys are NULL */
|
||||
continue;
|
||||
|
||||
if ( !addisnull[i] ) {
|
||||
if (!addisnull[i])
|
||||
{
|
||||
if (oldisnull[i] || gistKeyIsEQ(giststate, i, oldentries[i].key, attrS[i]) == false)
|
||||
neednew = true;
|
||||
}
|
||||
|
@ -510,7 +538,8 @@ gistpenalty(GISTSTATE *giststate, int attno,
|
|||
else if (isNullOrig && isNullAdd)
|
||||
penalty = 0.0;
|
||||
else
|
||||
penalty = 1e10; /* try to prevent to mix null and non-null value */
|
||||
penalty = 1e10; /* try to prevent to mix null and non-null
|
||||
* value */
|
||||
|
||||
return penalty;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.27 2006/09/21 20:31:21 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.28 2006/10/04 00:29:48 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -48,16 +48,21 @@ typedef struct
|
|||
* Make union of keys on page
|
||||
*/
|
||||
static IndexTuple
|
||||
PageMakeUnionKey(GistVacuum *gv, Buffer buffer) {
|
||||
PageMakeUnionKey(GistVacuum *gv, Buffer buffer)
|
||||
{
|
||||
Page page = BufferGetPage(buffer);
|
||||
IndexTuple *vec,
|
||||
tmp, res;
|
||||
tmp,
|
||||
res;
|
||||
int veclen = 0;
|
||||
MemoryContext oldCtx = MemoryContextSwitchTo(gv->opCtx);
|
||||
|
||||
vec = gistextractpage(page, &veclen);
|
||||
/* we call gistunion() in temprorary context because user-defined functions called in gistunion()
|
||||
may do not free all memory */
|
||||
|
||||
/*
|
||||
* we call gistunion() in temprorary context because user-defined
|
||||
* functions called in gistunion() may do not free all memory
|
||||
*/
|
||||
tmp = gistunion(gv->index, vec, veclen, &(gv->giststate));
|
||||
MemoryContextSwitchTo(oldCtx);
|
||||
|
||||
|
@ -73,7 +78,8 @@ PageMakeUnionKey(GistVacuum *gv, Buffer buffer) {
|
|||
}
|
||||
|
||||
static void
|
||||
gistDeleteSubtree( GistVacuum *gv, BlockNumber blkno ) {
|
||||
gistDeleteSubtree(GistVacuum *gv, BlockNumber blkno)
|
||||
{
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
|
||||
|
@ -81,12 +87,15 @@ gistDeleteSubtree( GistVacuum *gv, BlockNumber blkno ) {
|
|||
LockBuffer(buffer, GIST_EXCLUSIVE);
|
||||
page = (Page) BufferGetPage(buffer);
|
||||
|
||||
if ( !GistPageIsLeaf(page) ) {
|
||||
if (!GistPageIsLeaf(page))
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = FirstOffsetNumber; i <= PageGetMaxOffsetNumber(page); i = OffsetNumberNext(i)) {
|
||||
for (i = FirstOffsetNumber; i <= PageGetMaxOffsetNumber(page); i = OffsetNumberNext(i))
|
||||
{
|
||||
ItemId iid = PageGetItemId(page, i);
|
||||
IndexTuple idxtuple = (IndexTuple) PageGetItem(page, iid);
|
||||
|
||||
gistDeleteSubtree(gv, ItemPointerGetBlockNumber(&(idxtuple->t_tid)));
|
||||
}
|
||||
}
|
||||
|
@ -132,7 +141,8 @@ gistDeleteSubtree( GistVacuum *gv, BlockNumber blkno ) {
|
|||
}
|
||||
|
||||
static Page
|
||||
GistPageGetCopyPage( Page page ) {
|
||||
GistPageGetCopyPage(Page page)
|
||||
{
|
||||
Size pageSize = PageGetPageSize(page);
|
||||
Page tmppage;
|
||||
|
||||
|
@ -143,12 +153,14 @@ GistPageGetCopyPage( Page page ) {
|
|||
}
|
||||
|
||||
static ArrayTuple
|
||||
vacuumSplitPage(GistVacuum *gv, Page tempPage, Buffer buffer, IndexTuple *addon, int curlenaddon) {
|
||||
vacuumSplitPage(GistVacuum *gv, Page tempPage, Buffer buffer, IndexTuple *addon, int curlenaddon)
|
||||
{
|
||||
ArrayTuple res = {NULL, 0, false};
|
||||
IndexTuple *vec;
|
||||
SplitedPageLayout *dist = NULL,
|
||||
*ptr;
|
||||
int i, veclen=0;
|
||||
int i,
|
||||
veclen = 0;
|
||||
BlockNumber blkno = BufferGetBlockNumber(buffer);
|
||||
MemoryContext oldCtx = MemoryContextSwitchTo(gv->opCtx);
|
||||
|
||||
|
@ -158,23 +170,27 @@ vacuumSplitPage(GistVacuum *gv, Page tempPage, Buffer buffer, IndexTuple *addon,
|
|||
|
||||
MemoryContextSwitchTo(oldCtx);
|
||||
|
||||
if (blkno != GIST_ROOT_BLKNO) {
|
||||
if (blkno != GIST_ROOT_BLKNO)
|
||||
{
|
||||
/* if non-root split then we should not allocate new buffer */
|
||||
dist->buffer = buffer;
|
||||
dist->page = tempPage;
|
||||
/* during vacuum we never split leaf page */
|
||||
GistPageGetOpaque(dist->page)->flags = 0;
|
||||
} else
|
||||
}
|
||||
else
|
||||
pfree(tempPage);
|
||||
|
||||
res.itup = (IndexTuple *) palloc(sizeof(IndexTuple) * veclen);
|
||||
res.ituplen = 0;
|
||||
|
||||
/* make new pages and fills them */
|
||||
for (ptr = dist; ptr; ptr = ptr->next) {
|
||||
for (ptr = dist; ptr; ptr = ptr->next)
|
||||
{
|
||||
char *data;
|
||||
|
||||
if ( ptr->buffer == InvalidBuffer ) {
|
||||
if (ptr->buffer == InvalidBuffer)
|
||||
{
|
||||
ptr->buffer = gistNewBuffer(gv->index);
|
||||
GISTInitBuffer(ptr->buffer, 0);
|
||||
ptr->page = BufferGetPage(ptr->buffer);
|
||||
|
@ -182,7 +198,8 @@ vacuumSplitPage(GistVacuum *gv, Page tempPage, Buffer buffer, IndexTuple *addon,
|
|||
ptr->block.blkno = BufferGetBlockNumber(ptr->buffer);
|
||||
|
||||
data = (char *) (ptr->list);
|
||||
for(i=0;i<ptr->block.num;i++) {
|
||||
for (i = 0; i < ptr->block.num; i++)
|
||||
{
|
||||
if (PageAddItem(ptr->page, (Item) data, IndexTupleSize((IndexTuple) data), i + FirstOffsetNumber, LP_USED) == InvalidOffsetNumber)
|
||||
elog(ERROR, "failed to add item to index page in \"%s\"", RelationGetRelationName(gv->index));
|
||||
data += IndexTupleSize((IndexTuple) data);
|
||||
|
@ -196,13 +213,15 @@ vacuumSplitPage(GistVacuum *gv, Page tempPage, Buffer buffer, IndexTuple *addon,
|
|||
|
||||
START_CRIT_SECTION();
|
||||
|
||||
for (ptr = dist; ptr; ptr = ptr->next) {
|
||||
for (ptr = dist; ptr; ptr = ptr->next)
|
||||
{
|
||||
MarkBufferDirty(ptr->buffer);
|
||||
GistPageGetOpaque(ptr->page)->rightlink = InvalidBlockNumber;
|
||||
}
|
||||
|
||||
/* restore splitted non-root page */
|
||||
if (blkno != GIST_ROOT_BLKNO) {
|
||||
if (blkno != GIST_ROOT_BLKNO)
|
||||
{
|
||||
PageRestoreTempPage(dist->page, BufferGetPage(dist->buffer));
|
||||
dist->page = BufferGetPage(dist->buffer);
|
||||
}
|
||||
|
@ -211,8 +230,7 @@ vacuumSplitPage(GistVacuum *gv, Page tempPage, Buffer buffer, IndexTuple *addon,
|
|||
{
|
||||
XLogRecPtr recptr;
|
||||
XLogRecData *rdata;
|
||||
ItemPointerData key; /* set key for incomplete
|
||||
* insert */
|
||||
ItemPointerData key; /* set key for incomplete insert */
|
||||
char *xlinfo;
|
||||
|
||||
ItemPointerSet(&key, blkno, TUPLE_IS_VALID);
|
||||
|
@ -246,8 +264,7 @@ vacuumSplitPage(GistVacuum *gv, Page tempPage, Buffer buffer, IndexTuple *addon,
|
|||
|
||||
if (blkno == GIST_ROOT_BLKNO)
|
||||
{
|
||||
ItemPointerData key; /* set key for incomplete
|
||||
* insert */
|
||||
ItemPointerData key; /* set key for incomplete insert */
|
||||
|
||||
ItemPointerSet(&key, blkno, TUPLE_IS_VALID);
|
||||
|
||||
|
@ -266,7 +283,8 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
|
|||
{
|
||||
ArrayTuple res = {NULL, 0, false};
|
||||
Buffer buffer;
|
||||
Page page, tempPage = NULL;
|
||||
Page page,
|
||||
tempPage = NULL;
|
||||
OffsetNumber i,
|
||||
maxoff;
|
||||
ItemId iid;
|
||||
|
@ -373,38 +391,45 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
|
|||
if (curlenaddon)
|
||||
{
|
||||
/* insert updated tuples */
|
||||
if (gistnospace(tempPage, addon, curlenaddon, InvalidOffsetNumber, 0)) {
|
||||
if (gistnospace(tempPage, addon, curlenaddon, InvalidOffsetNumber, 0))
|
||||
{
|
||||
/* there is no space on page to insert tuples */
|
||||
res = vacuumSplitPage(gv, tempPage, buffer, addon, curlenaddon);
|
||||
tempPage = NULL; /* vacuumSplitPage() free tempPage */
|
||||
needwrite = needunion = false; /* gistSplit already forms unions and writes pages */
|
||||
} else
|
||||
needwrite = needunion = false; /* gistSplit already forms
|
||||
* unions and writes pages */
|
||||
}
|
||||
else
|
||||
/* enough free space */
|
||||
gistfillbuffer(gv->index, tempPage, addon, curlenaddon, InvalidOffsetNumber);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If page is empty, we should remove pointer to it before
|
||||
* deleting page (except root)
|
||||
* If page is empty, we should remove pointer to it before deleting page
|
||||
* (except root)
|
||||
*/
|
||||
|
||||
if ( blkno != GIST_ROOT_BLKNO && ( PageIsEmpty(page) || (tempPage && PageIsEmpty(tempPage)) ) ) {
|
||||
if (blkno != GIST_ROOT_BLKNO && (PageIsEmpty(page) || (tempPage && PageIsEmpty(tempPage))))
|
||||
{
|
||||
/*
|
||||
* New version of page is empty, so leave it unchanged,
|
||||
* upper call will mark our page as deleted.
|
||||
* In case of page split we never will be here...
|
||||
* New version of page is empty, so leave it unchanged, upper call
|
||||
* will mark our page as deleted. In case of page split we never will
|
||||
* be here...
|
||||
*
|
||||
* If page was empty it can't become non-empty during processing
|
||||
*/
|
||||
res.emptypage = true;
|
||||
UnlockReleaseBuffer(buffer);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* write page and remove its childs if it need */
|
||||
|
||||
START_CRIT_SECTION();
|
||||
|
||||
if ( tempPage && needwrite ) {
|
||||
if (tempPage && needwrite)
|
||||
{
|
||||
PageRestoreTempPage(tempPage, page);
|
||||
tempPage = NULL;
|
||||
}
|
||||
|
@ -506,9 +531,10 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
|
|||
/* use heap's tuple count */
|
||||
Assert(info->num_heap_tuples >= 0);
|
||||
stats->std.num_index_tuples = info->num_heap_tuples;
|
||||
|
||||
/*
|
||||
* XXX the above is wrong if index is partial. Would it be OK to
|
||||
* just return NULL, or is there work we must do below?
|
||||
* XXX the above is wrong if index is partial. Would it be OK to just
|
||||
* return NULL, or is there work we must do below?
|
||||
*/
|
||||
}
|
||||
|
||||
|
@ -545,8 +571,8 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
|
|||
RelationGetRelationName(rel))));
|
||||
|
||||
/*
|
||||
* If vacuum full, we already have exclusive lock on the index.
|
||||
* Otherwise, need lock unless it's local to this backend.
|
||||
* If vacuum full, we already have exclusive lock on the index. Otherwise,
|
||||
* need lock unless it's local to this backend.
|
||||
*/
|
||||
if (info->vacuum_full)
|
||||
needLock = false;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistxlog.c,v 1.23 2006/08/07 16:57:56 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistxlog.c,v 1.24 2006/10/04 00:29:48 momjian Exp $
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
@ -73,6 +73,7 @@ pushIncompleteInsert(RelFileNode node, XLogRecPtr lsn, ItemPointerData key,
|
|||
gistIncompleteInsert *ninsert;
|
||||
|
||||
if (!ItemPointerIsValid(&key))
|
||||
|
||||
/*
|
||||
* if key is null then we should not store insertion as incomplete,
|
||||
* because it's a vacuum operation..
|
||||
|
@ -108,8 +109,8 @@ pushIncompleteInsert(RelFileNode node, XLogRecPtr lsn, ItemPointerData key,
|
|||
|
||||
/*
|
||||
* Stick the new incomplete insert onto the front of the list, not the
|
||||
* back. This is so that gist_xlog_cleanup will process incompletions
|
||||
* in last-in-first-out order.
|
||||
* back. This is so that gist_xlog_cleanup will process incompletions in
|
||||
* last-in-first-out order.
|
||||
*/
|
||||
incomplete_inserts = lcons(ninsert, incomplete_inserts);
|
||||
|
||||
|
@ -242,8 +243,11 @@ gistRedoPageUpdateRecord(XLogRecPtr lsn, XLogRecord *record, bool isnewroot)
|
|||
GistClearTuplesDeleted(page);
|
||||
|
||||
if (!GistPageIsLeaf(page) && PageGetMaxOffsetNumber(page) == InvalidOffsetNumber && xldata->blkno == GIST_ROOT_BLKNO)
|
||||
/* all links on non-leaf root page was deleted by vacuum full,
|
||||
so root page becomes a leaf */
|
||||
|
||||
/*
|
||||
* all links on non-leaf root page was deleted by vacuum full, so root
|
||||
* page becomes a leaf
|
||||
*/
|
||||
GistPageSetLeaf(page);
|
||||
|
||||
GistPageGetOpaque(page)->rightlink = InvalidBlockNumber;
|
||||
|
@ -548,10 +552,13 @@ gistxlogFindPath(Relation index, gistIncompleteInsert *insert)
|
|||
}
|
||||
|
||||
static SplitedPageLayout *
|
||||
gistMakePageLayout(Buffer *buffers, int nbuffers) {
|
||||
SplitedPageLayout *res=NULL, *resptr;
|
||||
gistMakePageLayout(Buffer *buffers, int nbuffers)
|
||||
{
|
||||
SplitedPageLayout *res = NULL,
|
||||
*resptr;
|
||||
|
||||
while( nbuffers-- > 0 ) {
|
||||
while (nbuffers-- > 0)
|
||||
{
|
||||
Page page = BufferGetPage(buffers[nbuffers]);
|
||||
IndexTuple *vec;
|
||||
int veclen;
|
||||
|
@ -650,6 +657,7 @@ gistContinueInsert(gistIncompleteInsert *insert)
|
|||
numbuffer = 1;
|
||||
buffers[0] = ReadBuffer(index, insert->path[i]);
|
||||
LockBuffer(buffers[0], GIST_EXCLUSIVE);
|
||||
|
||||
/*
|
||||
* we check buffer, because we restored page earlier
|
||||
*/
|
||||
|
@ -682,8 +690,8 @@ gistContinueInsert(gistIncompleteInsert *insert)
|
|||
elog(PANIC, "gistContinueInsert: can't find pointer to page(s)");
|
||||
|
||||
/*
|
||||
* we check space with subtraction only first tuple to delete, hope,
|
||||
* that wiil be enough space....
|
||||
* we check space with subtraction only first tuple to delete,
|
||||
* hope, that wiil be enough space....
|
||||
*/
|
||||
|
||||
if (gistnospace(pages[0], itup, lenitup, *todelete, 0))
|
||||
|
@ -718,7 +726,8 @@ gistContinueInsert(gistIncompleteInsert *insert)
|
|||
/* swap buffers[0] (was root) and temp buffer */
|
||||
tmp = buffers[0];
|
||||
buffers[0] = tempbuffer;
|
||||
tempbuffer = tmp; /* now in tempbuffer GIST_ROOT_BLKNO, it is still unchanged */
|
||||
tempbuffer = tmp; /* now in tempbuffer GIST_ROOT_BLKNO,
|
||||
* it is still unchanged */
|
||||
|
||||
pages[0] = BufferGetPage(buffers[0]);
|
||||
}
|
||||
|
@ -732,7 +741,9 @@ gistContinueInsert(gistIncompleteInsert *insert)
|
|||
false, &(insert->key),
|
||||
gistMakePageLayout(buffers, numbuffer));
|
||||
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
START_CRIT_SECTION();
|
||||
|
||||
for (j = 0; j < ntodelete; j++)
|
||||
|
@ -745,12 +756,13 @@ gistContinueInsert(gistIncompleteInsert *insert)
|
|||
}
|
||||
|
||||
/*
|
||||
* use insert->key as mark for completion of insert (form*Rdata() above)
|
||||
* for following possible replays
|
||||
* use insert->key as mark for completion of insert (form*Rdata()
|
||||
* above) for following possible replays
|
||||
*/
|
||||
|
||||
/* write pages, we should mark it dirty befor XLogInsert() */
|
||||
for (j = 0; j < numbuffer; j++) {
|
||||
for (j = 0; j < numbuffer; j++)
|
||||
{
|
||||
GistPageGetOpaque(pages[j])->rightlink = InvalidBlockNumber;
|
||||
MarkBufferDirty(buffers[j]);
|
||||
}
|
||||
|
@ -764,12 +776,14 @@ gistContinueInsert(gistIncompleteInsert *insert)
|
|||
END_CRIT_SECTION();
|
||||
|
||||
lenitup = numbuffer;
|
||||
for (j = 0; j < numbuffer; j++) {
|
||||
for (j = 0; j < numbuffer; j++)
|
||||
{
|
||||
itup[j] = gist_form_invalid_tuple(BufferGetBlockNumber(buffers[j]));
|
||||
UnlockReleaseBuffer(buffers[j]);
|
||||
}
|
||||
|
||||
if ( tempbuffer != InvalidBuffer ) {
|
||||
if (tempbuffer != InvalidBuffer)
|
||||
{
|
||||
/*
|
||||
* it was a root split, so fill it by new values
|
||||
*/
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/hash/hashfunc.c,v 1.47 2006/03/05 15:58:20 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/hash/hashfunc.c,v 1.48 2006/10/04 00:29:48 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* These functions are stored in pg_amproc. For each operator class
|
||||
|
@ -138,8 +138,8 @@ hashtext(PG_FUNCTION_ARGS)
|
|||
Datum result;
|
||||
|
||||
/*
|
||||
* Note: this is currently identical in behavior to hashvarlena, but
|
||||
* keep it as a separate function in case we someday want to do something
|
||||
* Note: this is currently identical in behavior to hashvarlena, but keep
|
||||
* it as a separate function in case we someday want to do something
|
||||
* different in non-C locales. (See also hashbpchar, if so.)
|
||||
*/
|
||||
result = hash_any((unsigned char *) VARDATA(key),
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/hash/hashpage.c,v 1.59 2006/07/03 22:45:36 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/hash/hashpage.c,v 1.60 2006/10/04 00:29:48 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Postgres hash pages look like ordinary relation pages. The opaque
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.219 2006/08/18 16:09:08 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.220 2006/10/04 00:29:48 momjian Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
|
@ -133,9 +133,9 @@ heapgetpage(HeapScanDesc scan, BlockNumber page)
|
|||
snapshot = scan->rs_snapshot;
|
||||
|
||||
/*
|
||||
* We must hold share lock on the buffer content while examining
|
||||
* tuple visibility. Afterwards, however, the tuples we have found
|
||||
* to be visible are guaranteed good as long as we hold the buffer pin.
|
||||
* We must hold share lock on the buffer content while examining tuple
|
||||
* visibility. Afterwards, however, the tuples we have found to be
|
||||
* visible are guaranteed good as long as we hold the buffer pin.
|
||||
*/
|
||||
LockBuffer(buffer, BUFFER_LOCK_SHARE);
|
||||
|
||||
|
@ -721,8 +721,8 @@ try_relation_open(Oid relationId, LOCKMODE lockmode)
|
|||
LockRelationOid(relationId, lockmode);
|
||||
|
||||
/*
|
||||
* Now that we have the lock, probe to see if the relation really
|
||||
* exists or not.
|
||||
* Now that we have the lock, probe to see if the relation really exists
|
||||
* or not.
|
||||
*/
|
||||
if (!SearchSysCacheExists(RELOID,
|
||||
ObjectIdGetDatum(relationId),
|
||||
|
@ -801,8 +801,8 @@ relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
|
|||
|
||||
/*
|
||||
* Check for shared-cache-inval messages before trying to open the
|
||||
* relation. This is needed to cover the case where the name identifies
|
||||
* a rel that has been dropped and recreated since the start of our
|
||||
* relation. This is needed to cover the case where the name identifies a
|
||||
* rel that has been dropped and recreated since the start of our
|
||||
* transaction: if we don't flush the old syscache entry then we'll latch
|
||||
* onto that entry and suffer an error when we do RelationIdGetRelation.
|
||||
* Note that relation_open does not need to do this, since a relation's
|
||||
|
@ -2840,6 +2840,7 @@ heap_restrpos(HeapScanDesc scan)
|
|||
if (!ItemPointerIsValid(&scan->rs_mctid))
|
||||
{
|
||||
scan->rs_ctup.t_data = NULL;
|
||||
|
||||
/*
|
||||
* unpin scan buffers
|
||||
*/
|
||||
|
@ -3308,6 +3309,7 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool move)
|
|||
/* Set forward chain link in t_ctid */
|
||||
htup->t_ctid = xlrec->newtid;
|
||||
}
|
||||
|
||||
/*
|
||||
* this test is ugly, but necessary to avoid thinking that insert change
|
||||
* is already applied
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.64 2006/09/10 23:33:22 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.65 2006/10/04 00:29:48 momjian Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.58 2006/07/31 20:08:59 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.59 2006/10/04 00:29:48 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* many of the old access method routines have been turned into
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.94 2006/07/31 20:08:59 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.95 2006/10/04 00:29:48 momjian Exp $
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
* index_open - open an index relation by relation OID
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.143 2006/08/25 04:06:46 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.144 2006/10/04 00:29:48 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -888,12 +888,13 @@ _bt_split(Relation rel, Buffer buf, OffsetNumber firstright,
|
|||
sopaque = (BTPageOpaque) PageGetSpecialPointer(spage);
|
||||
if (sopaque->btpo_prev != ropaque->btpo_prev)
|
||||
elog(PANIC, "right sibling's left-link doesn't match");
|
||||
|
||||
/*
|
||||
* Check to see if we can set the SPLIT_END flag in the right-hand
|
||||
* split page; this can save some I/O for vacuum since it need not
|
||||
* proceed to the right sibling. We can set the flag if the right
|
||||
* sibling has a different cycleid: that means it could not be part
|
||||
* of a group of pages that were all split off from the same ancestor
|
||||
* sibling has a different cycleid: that means it could not be part of
|
||||
* a group of pages that were all split off from the same ancestor
|
||||
* page. If you're confused, imagine that page A splits to A B and
|
||||
* then again, yielding A C B, while vacuum is in progress. Tuples
|
||||
* originally in A could now be in either B or C, hence vacuum must
|
||||
|
@ -911,8 +912,8 @@ _bt_split(Relation rel, Buffer buf, OffsetNumber firstright,
|
|||
*
|
||||
* NO EREPORT(ERROR) till right sibling is updated. We can get away with
|
||||
* not starting the critical section till here because we haven't been
|
||||
* scribbling on the original page yet, and we don't care about the
|
||||
* new sibling until it's linked into the btree.
|
||||
* scribbling on the original page yet, and we don't care about the new
|
||||
* sibling until it's linked into the btree.
|
||||
*/
|
||||
START_CRIT_SECTION();
|
||||
|
||||
|
@ -947,8 +948,8 @@ _bt_split(Relation rel, Buffer buf, OffsetNumber firstright,
|
|||
* Direct access to page is not good but faster - we should implement
|
||||
* some new func in page API. Note we only store the tuples
|
||||
* themselves, knowing that the item pointers are in the same order
|
||||
* and can be reconstructed by scanning the tuples. See comments
|
||||
* for _bt_restore_page().
|
||||
* and can be reconstructed by scanning the tuples. See comments for
|
||||
* _bt_restore_page().
|
||||
*/
|
||||
xlrec.leftlen = ((PageHeader) leftpage)->pd_special -
|
||||
((PageHeader) leftpage)->pd_upper;
|
||||
|
@ -1717,8 +1718,8 @@ _bt_vacuum_one_page(Relation rel, Buffer buffer)
|
|||
BTPageOpaque opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||
|
||||
/*
|
||||
* Scan over all items to see which ones need deleted
|
||||
* according to LP_DELETE flags.
|
||||
* Scan over all items to see which ones need deleted according to
|
||||
* LP_DELETE flags.
|
||||
*/
|
||||
minoff = P_FIRSTDATAKEY(opaque);
|
||||
maxoff = PageGetMaxOffsetNumber(page);
|
||||
|
@ -1734,10 +1735,11 @@ _bt_vacuum_one_page(Relation rel, Buffer buffer)
|
|||
|
||||
if (ndeletable > 0)
|
||||
_bt_delitems(rel, buffer, deletable, ndeletable);
|
||||
|
||||
/*
|
||||
* Note: if we didn't find any LP_DELETE items, then the page's
|
||||
* BTP_HAS_GARBAGE hint bit is falsely set. We do not bother
|
||||
* expending a separate write to clear it, however. We will clear
|
||||
* it when we split the page.
|
||||
* BTP_HAS_GARBAGE hint bit is falsely set. We do not bother expending a
|
||||
* separate write to clear it, however. We will clear it when we split
|
||||
* the page.
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtpage.c,v 1.99 2006/07/25 19:13:00 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtpage.c,v 1.100 2006/10/04 00:29:49 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Postgres btree pages look like ordinary relation pages. The opaque
|
||||
|
@ -124,10 +124,10 @@ _bt_getroot(Relation rel, int access)
|
|||
|
||||
/*
|
||||
* Since the cache might be stale, we check the page more carefully
|
||||
* here than normal. We *must* check that it's not deleted.
|
||||
* If it's not alone on its level, then we reject too --- this
|
||||
* may be overly paranoid but better safe than sorry. Note we
|
||||
* don't check P_ISROOT, because that's not set in a "fast root".
|
||||
* here than normal. We *must* check that it's not deleted. If it's
|
||||
* not alone on its level, then we reject too --- this may be overly
|
||||
* paranoid but better safe than sorry. Note we don't check P_ISROOT,
|
||||
* because that's not set in a "fast root".
|
||||
*/
|
||||
if (!P_IGNORE(rootopaque) &&
|
||||
rootopaque->btpo.level == rootlevel &&
|
||||
|
@ -662,18 +662,18 @@ _bt_delitems(Relation rel, Buffer buf,
|
|||
PageIndexMultiDelete(page, itemnos, nitems);
|
||||
|
||||
/*
|
||||
* We can clear the vacuum cycle ID since this page has certainly
|
||||
* been processed by the current vacuum scan.
|
||||
* We can clear the vacuum cycle ID since this page has certainly been
|
||||
* processed by the current vacuum scan.
|
||||
*/
|
||||
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||
opaque->btpo_cycleid = 0;
|
||||
|
||||
/*
|
||||
* Mark the page as not containing any LP_DELETE items. This is not
|
||||
* certainly true (there might be some that have recently been marked,
|
||||
* but weren't included in our target-item list), but it will almost
|
||||
* always be true and it doesn't seem worth an additional page scan
|
||||
* to check it. Remember that BTP_HAS_GARBAGE is only a hint anyway.
|
||||
* certainly true (there might be some that have recently been marked, but
|
||||
* weren't included in our target-item list), but it will almost always be
|
||||
* true and it doesn't seem worth an additional page scan to check it.
|
||||
* Remember that BTP_HAS_GARBAGE is only a hint anyway.
|
||||
*/
|
||||
opaque->btpo_flags &= ~BTP_HAS_GARBAGE;
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.151 2006/09/21 20:31:22 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.152 2006/10/04 00:29:49 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -109,8 +109,8 @@ btbuild(PG_FUNCTION_ARGS)
|
|||
buildstate.spool = _bt_spoolinit(index, indexInfo->ii_Unique, false);
|
||||
|
||||
/*
|
||||
* If building a unique index, put dead tuples in a second spool to
|
||||
* keep them out of the uniqueness check.
|
||||
* If building a unique index, put dead tuples in a second spool to keep
|
||||
* them out of the uniqueness check.
|
||||
*/
|
||||
if (indexInfo->ii_Unique)
|
||||
buildstate.spool2 = _bt_spoolinit(index, false, true);
|
||||
|
@ -146,11 +146,11 @@ btbuild(PG_FUNCTION_ARGS)
|
|||
#endif /* BTREE_BUILD_STATS */
|
||||
|
||||
/*
|
||||
* If we are reindexing a pre-existing index, it is critical to send out
|
||||
* a relcache invalidation SI message to ensure all backends re-read the
|
||||
* If we are reindexing a pre-existing index, it is critical to send out a
|
||||
* relcache invalidation SI message to ensure all backends re-read the
|
||||
* index metapage. We expect that the caller will ensure that happens
|
||||
* (typically as a side effect of updating index stats, but it must
|
||||
* happen even if the stats don't change!)
|
||||
* (typically as a side effect of updating index stats, but it must happen
|
||||
* even if the stats don't change!)
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -316,8 +316,8 @@ btgetmulti(PG_FUNCTION_ARGS)
|
|||
while (ntids < max_tids)
|
||||
{
|
||||
/*
|
||||
* Advance to next tuple within page. This is the same as the
|
||||
* easy case in _bt_next().
|
||||
* Advance to next tuple within page. This is the same as the easy
|
||||
* case in _bt_next().
|
||||
*/
|
||||
if (++so->currPos.itemIndex > so->currPos.lastItem)
|
||||
{
|
||||
|
@ -461,9 +461,9 @@ btmarkpos(PG_FUNCTION_ARGS)
|
|||
|
||||
/*
|
||||
* Just record the current itemIndex. If we later step to next page
|
||||
* before releasing the marked position, _bt_steppage makes a full copy
|
||||
* of the currPos struct in markPos. If (as often happens) the mark is
|
||||
* moved before we leave the page, we don't have to do that work.
|
||||
* before releasing the marked position, _bt_steppage makes a full copy of
|
||||
* the currPos struct in markPos. If (as often happens) the mark is moved
|
||||
* before we leave the page, we don't have to do that work.
|
||||
*/
|
||||
if (BTScanPosIsValid(so->currPos))
|
||||
so->markItemIndex = so->currPos.itemIndex;
|
||||
|
@ -485,8 +485,8 @@ btrestrpos(PG_FUNCTION_ARGS)
|
|||
if (so->markItemIndex >= 0)
|
||||
{
|
||||
/*
|
||||
* The mark position is on the same page we are currently on.
|
||||
* Just restore the itemIndex.
|
||||
* The mark position is on the same page we are currently on. Just
|
||||
* restore the itemIndex.
|
||||
*/
|
||||
so->currPos.itemIndex = so->markItemIndex;
|
||||
}
|
||||
|
@ -569,10 +569,10 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
|
|||
IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
|
||||
|
||||
/*
|
||||
* If btbulkdelete was called, we need not do anything, just return
|
||||
* the stats from the latest btbulkdelete call. If it wasn't called,
|
||||
* we must still do a pass over the index, to recycle any newly-recyclable
|
||||
* pages and to obtain index statistics.
|
||||
* If btbulkdelete was called, we need not do anything, just return the
|
||||
* stats from the latest btbulkdelete call. If it wasn't called, we must
|
||||
* still do a pass over the index, to recycle any newly-recyclable pages
|
||||
* and to obtain index statistics.
|
||||
*
|
||||
* Since we aren't going to actually delete any leaf items, there's no
|
||||
* need to go through all the vacuum-cycle-ID pushups.
|
||||
|
@ -586,8 +586,8 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
|
|||
/*
|
||||
* During a non-FULL vacuum it's quite possible for us to be fooled by
|
||||
* concurrent page splits into double-counting some index tuples, so
|
||||
* disbelieve any total that exceeds the underlying heap's count.
|
||||
* (We can't check this during btbulkdelete.)
|
||||
* disbelieve any total that exceeds the underlying heap's count. (We
|
||||
* can't check this during btbulkdelete.)
|
||||
*/
|
||||
if (!info->vacuum_full)
|
||||
{
|
||||
|
@ -622,8 +622,8 @@ btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
|
|||
bool needLock;
|
||||
|
||||
/*
|
||||
* Reset counts that will be incremented during the scan; needed in
|
||||
* case of multiple scans during a single VACUUM command
|
||||
* Reset counts that will be incremented during the scan; needed in case
|
||||
* of multiple scans during a single VACUUM command
|
||||
*/
|
||||
stats->num_index_tuples = 0;
|
||||
stats->pages_deleted = 0;
|
||||
|
@ -647,24 +647,24 @@ btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
|
|||
ALLOCSET_DEFAULT_MAXSIZE);
|
||||
|
||||
/*
|
||||
* The outer loop iterates over all index pages except the metapage,
|
||||
* in physical order (we hope the kernel will cooperate in providing
|
||||
* The outer loop iterates over all index pages except the metapage, in
|
||||
* physical order (we hope the kernel will cooperate in providing
|
||||
* read-ahead for speed). It is critical that we visit all leaf pages,
|
||||
* including ones added after we start the scan, else we might fail to
|
||||
* delete some deletable tuples. Hence, we must repeatedly check the
|
||||
* relation length. We must acquire the relation-extension lock while
|
||||
* doing so to avoid a race condition: if someone else is extending the
|
||||
* relation, there is a window where bufmgr/smgr have created a new
|
||||
* all-zero page but it hasn't yet been write-locked by _bt_getbuf().
|
||||
* If we manage to scan such a page here, we'll improperly assume it can
|
||||
* be recycled. Taking the lock synchronizes things enough to prevent a
|
||||
* all-zero page but it hasn't yet been write-locked by _bt_getbuf(). If
|
||||
* we manage to scan such a page here, we'll improperly assume it can be
|
||||
* recycled. Taking the lock synchronizes things enough to prevent a
|
||||
* problem: either num_pages won't include the new page, or _bt_getbuf
|
||||
* already has write lock on the buffer and it will be fully initialized
|
||||
* before we can examine it. (See also vacuumlazy.c, which has the same
|
||||
* issue.) Also, we need not worry if a page is added immediately after
|
||||
* we look; the page splitting code already has write-lock on the left
|
||||
* page before it adds a right page, so we must already have processed
|
||||
* any tuples due to be moved into such a page.
|
||||
* page before it adds a right page, so we must already have processed any
|
||||
* tuples due to be moved into such a page.
|
||||
*
|
||||
* We can skip locking for new or temp relations, however, since no one
|
||||
* else could be accessing them.
|
||||
|
@ -796,10 +796,10 @@ restart:
|
|||
_bt_checkpage(rel, buf);
|
||||
|
||||
/*
|
||||
* If we are recursing, the only case we want to do anything with is
|
||||
* a live leaf page having the current vacuum cycle ID. Any other state
|
||||
* implies we already saw the page (eg, deleted it as being empty).
|
||||
* In particular, we don't want to risk adding it to freePages twice.
|
||||
* If we are recursing, the only case we want to do anything with is a
|
||||
* live leaf page having the current vacuum cycle ID. Any other state
|
||||
* implies we already saw the page (eg, deleted it as being empty). In
|
||||
* particular, we don't want to risk adding it to freePages twice.
|
||||
*/
|
||||
if (blkno != orig_blkno)
|
||||
{
|
||||
|
@ -842,21 +842,20 @@ restart:
|
|||
maxoff;
|
||||
|
||||
/*
|
||||
* Trade in the initial read lock for a super-exclusive write
|
||||
* lock on this page. We must get such a lock on every leaf page
|
||||
* over the course of the vacuum scan, whether or not it actually
|
||||
* contains any deletable tuples --- see nbtree/README.
|
||||
* Trade in the initial read lock for a super-exclusive write lock on
|
||||
* this page. We must get such a lock on every leaf page over the
|
||||
* course of the vacuum scan, whether or not it actually contains any
|
||||
* deletable tuples --- see nbtree/README.
|
||||
*/
|
||||
LockBuffer(buf, BUFFER_LOCK_UNLOCK);
|
||||
LockBufferForCleanup(buf);
|
||||
|
||||
/*
|
||||
* Check whether we need to recurse back to earlier pages. What
|
||||
* we are concerned about is a page split that happened since we
|
||||
* started the vacuum scan. If the split moved some tuples to a
|
||||
* lower page then we might have missed 'em. If so, set up for
|
||||
* tail recursion. (Must do this before possibly clearing
|
||||
* btpo_cycleid below!)
|
||||
* Check whether we need to recurse back to earlier pages. What we
|
||||
* are concerned about is a page split that happened since we started
|
||||
* the vacuum scan. If the split moved some tuples to a lower page
|
||||
* then we might have missed 'em. If so, set up for tail recursion.
|
||||
* (Must do this before possibly clearing btpo_cycleid below!)
|
||||
*/
|
||||
if (vstate->cycleid != 0 &&
|
||||
opaque->btpo_cycleid == vstate->cycleid &&
|
||||
|
@ -866,8 +865,8 @@ restart:
|
|||
recurse_to = opaque->btpo_next;
|
||||
|
||||
/*
|
||||
* Scan over all items to see which ones need deleted
|
||||
* according to the callback function.
|
||||
* Scan over all items to see which ones need deleted according to the
|
||||
* callback function.
|
||||
*/
|
||||
ndeletable = 0;
|
||||
minoff = P_FIRSTDATAKEY(opaque);
|
||||
|
@ -890,8 +889,8 @@ restart:
|
|||
}
|
||||
|
||||
/*
|
||||
* Apply any needed deletes. We issue just one _bt_delitems()
|
||||
* call per page, so as to minimize WAL traffic.
|
||||
* Apply any needed deletes. We issue just one _bt_delitems() call
|
||||
* per page, so as to minimize WAL traffic.
|
||||
*/
|
||||
if (ndeletable > 0)
|
||||
{
|
||||
|
@ -908,8 +907,8 @@ restart:
|
|||
* have any deletions to do. (If we do, _bt_delitems takes care
|
||||
* of this.) This ensures we won't process the page again.
|
||||
*
|
||||
* We treat this like a hint-bit update because there's no need
|
||||
* to WAL-log it.
|
||||
* We treat this like a hint-bit update because there's no need to
|
||||
* WAL-log it.
|
||||
*/
|
||||
if (vstate->cycleid != 0 &&
|
||||
opaque->btpo_cycleid == vstate->cycleid)
|
||||
|
@ -920,10 +919,10 @@ restart:
|
|||
}
|
||||
|
||||
/*
|
||||
* If it's now empty, try to delete; else count the live tuples.
|
||||
* We don't delete when recursing, though, to avoid putting entries
|
||||
* into freePages out-of-order (doesn't seem worth any extra code to
|
||||
* handle the case).
|
||||
* If it's now empty, try to delete; else count the live tuples. We
|
||||
* don't delete when recursing, though, to avoid putting entries into
|
||||
* freePages out-of-order (doesn't seem worth any extra code to handle
|
||||
* the case).
|
||||
*/
|
||||
if (minoff > maxoff)
|
||||
delete_now = (blkno == orig_blkno);
|
||||
|
@ -947,13 +946,12 @@ restart:
|
|||
stats->pages_deleted++;
|
||||
|
||||
/*
|
||||
* During VACUUM FULL it's okay to recycle deleted pages
|
||||
* immediately, since there can be no other transactions scanning
|
||||
* the index. Note that we will only recycle the current page and
|
||||
* not any parent pages that _bt_pagedel might have recursed to;
|
||||
* this seems reasonable in the name of simplicity. (Trying to do
|
||||
* otherwise would mean we'd have to sort the list of recyclable
|
||||
* pages we're building.)
|
||||
* During VACUUM FULL it's okay to recycle deleted pages immediately,
|
||||
* since there can be no other transactions scanning the index. Note
|
||||
* that we will only recycle the current page and not any parent pages
|
||||
* that _bt_pagedel might have recursed to; this seems reasonable in
|
||||
* the name of simplicity. (Trying to do otherwise would mean we'd
|
||||
* have to sort the list of recyclable pages we're building.)
|
||||
*/
|
||||
if (ndel && info->vacuum_full)
|
||||
{
|
||||
|
@ -969,11 +967,11 @@ restart:
|
|||
_bt_relbuf(rel, buf);
|
||||
|
||||
/*
|
||||
* This is really tail recursion, but if the compiler is too stupid
|
||||
* to optimize it as such, we'd eat an uncomfortably large amount of
|
||||
* stack space per recursion level (due to the deletable[] array).
|
||||
* A failure is improbable since the number of levels isn't likely to be
|
||||
* large ... but just in case, let's hand-optimize into a loop.
|
||||
* This is really tail recursion, but if the compiler is too stupid to
|
||||
* optimize it as such, we'd eat an uncomfortably large amount of stack
|
||||
* space per recursion level (due to the deletable[] array). A failure is
|
||||
* improbable since the number of levels isn't likely to be large ... but
|
||||
* just in case, let's hand-optimize into a loop.
|
||||
*/
|
||||
if (recurse_to != P_NONE)
|
||||
{
|
||||
|
|
|
@ -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.106 2006/08/24 01:18:34 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.107 2006/10/04 00:29:49 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -612,16 +612,17 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
|||
* Row comparison header: look to the first row member instead.
|
||||
*
|
||||
* The member scankeys are already in insertion format (ie, they
|
||||
* have sk_func = 3-way-comparison function), but we have to
|
||||
* watch out for nulls, which _bt_preprocess_keys didn't check.
|
||||
* A null in the first row member makes the condition unmatchable,
|
||||
* just like qual_ok = false.
|
||||
* have sk_func = 3-way-comparison function), but we have to watch
|
||||
* out for nulls, which _bt_preprocess_keys didn't check. A null
|
||||
* in the first row member makes the condition unmatchable, just
|
||||
* like qual_ok = false.
|
||||
*/
|
||||
cur = (ScanKey) DatumGetPointer(cur->sk_argument);
|
||||
Assert(cur->sk_flags & SK_ROW_MEMBER);
|
||||
if (cur->sk_flags & SK_ISNULL)
|
||||
return false;
|
||||
memcpy(scankeys + i, cur, sizeof(ScanKeyData));
|
||||
|
||||
/*
|
||||
* If the row comparison is the last positioning key we accepted,
|
||||
* try to add additional keys from the lower-order row members.
|
||||
|
@ -833,10 +834,10 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
|||
*
|
||||
* 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. Adjust the starting offset if needed.
|
||||
* (If this results in an offset before the first item or after the last
|
||||
* one, _bt_readpage will report no items found, and then we'll step to
|
||||
* the next page as needed.)
|
||||
* the last item on this page. Adjust the starting offset if needed. (If
|
||||
* this results in an offset before the first item or after the last one,
|
||||
* _bt_readpage will report no items found, and then we'll step to the
|
||||
* next page as needed.)
|
||||
*/
|
||||
if (goback)
|
||||
offnum = OffsetNumberPrev(offnum);
|
||||
|
@ -882,8 +883,8 @@ _bt_next(IndexScanDesc scan, ScanDirection dir)
|
|||
BTScanOpaque so = (BTScanOpaque) scan->opaque;
|
||||
|
||||
/*
|
||||
* Advance to next tuple on current page; or if there's no more,
|
||||
* try to step to the next page with data.
|
||||
* Advance to next tuple on current page; or if there's no more, try to
|
||||
* step to the next page with data.
|
||||
*/
|
||||
if (ScanDirectionIsForward(dir))
|
||||
{
|
||||
|
@ -954,8 +955,8 @@ _bt_readpage(IndexScanDesc scan, ScanDirection dir, OffsetNumber offnum)
|
|||
|
||||
/*
|
||||
* we must save the page's right-link while scanning it; this tells us
|
||||
* where to step right to after we're done with these items. There is
|
||||
* no corresponding need for the left-link, since splits always go right.
|
||||
* where to step right to after we're done with these items. There is no
|
||||
* corresponding need for the left-link, since splits always go right.
|
||||
*/
|
||||
so->currPos.nextPage = opaque->btpo_next;
|
||||
|
||||
|
@ -1055,8 +1056,8 @@ _bt_steppage(IndexScanDesc scan, ScanDirection dir)
|
|||
_bt_killitems(scan, true);
|
||||
|
||||
/*
|
||||
* Before we modify currPos, make a copy of the page data if there
|
||||
* was a mark position that needs it.
|
||||
* Before we modify currPos, make a copy of the page data if there was a
|
||||
* mark position that needs it.
|
||||
*/
|
||||
if (so->markItemIndex >= 0)
|
||||
{
|
||||
|
@ -1112,11 +1113,11 @@ _bt_steppage(IndexScanDesc scan, ScanDirection dir)
|
|||
so->currPos.moreRight = true;
|
||||
|
||||
/*
|
||||
* Walk left to the next page with data. This is much more
|
||||
* complex than the walk-right case because of the possibility
|
||||
* that the page to our left splits while we are in flight to it,
|
||||
* plus the possibility that the page we were on gets deleted
|
||||
* after we leave it. See nbtree/README for details.
|
||||
* Walk left to the next page with data. This is much more complex
|
||||
* than the walk-right case because of the possibility that the page
|
||||
* to our left splits while we are in flight to it, plus the
|
||||
* possibility that the page we were on gets deleted after we leave
|
||||
* it. See nbtree/README for details.
|
||||
*/
|
||||
for (;;)
|
||||
{
|
||||
|
@ -1136,9 +1137,9 @@ _bt_steppage(IndexScanDesc scan, ScanDirection dir)
|
|||
return false;
|
||||
|
||||
/*
|
||||
* Okay, we managed to move left to a non-deleted page.
|
||||
* Done if it's not half-dead and contains matching tuples.
|
||||
* Else loop back and do it all again.
|
||||
* Okay, we managed to move left to a non-deleted page. Done if
|
||||
* it's not half-dead and contains matching tuples. Else loop back
|
||||
* and do it all again.
|
||||
*/
|
||||
page = BufferGetPage(so->currPos.buf);
|
||||
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsort.c,v 1.106 2006/07/14 14:52:17 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsort.c,v 1.107 2006/10/04 00:29:49 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -464,8 +464,8 @@ _bt_buildadd(BTWriteState *wstate, BTPageState *state, IndexTuple itup)
|
|||
Size itupsz;
|
||||
|
||||
/*
|
||||
* This is a handy place to check for cancel interrupts during the
|
||||
* btree load phase of index creation.
|
||||
* This is a handy place to check for cancel interrupts during the btree
|
||||
* load phase of index creation.
|
||||
*/
|
||||
CHECK_FOR_INTERRUPTS();
|
||||
|
||||
|
@ -499,10 +499,10 @@ _bt_buildadd(BTWriteState *wstate, BTPageState *state, IndexTuple itup)
|
|||
"or use full text indexing.")));
|
||||
|
||||
/*
|
||||
* Check to see if page is "full". It's definitely full if the item
|
||||
* won't fit. Otherwise, compare to the target freespace derived from
|
||||
* the fillfactor. However, we must put at least two items on each
|
||||
* page, so disregard fillfactor if we don't have that many.
|
||||
* Check to see if page is "full". It's definitely full if the item won't
|
||||
* fit. Otherwise, compare to the target freespace derived from the
|
||||
* fillfactor. However, we must put at least two items on each page, so
|
||||
* disregard fillfactor if we don't have that many.
|
||||
*/
|
||||
if (pgspc < itupsz || (pgspc < state->btps_full && last_off > P_FIRSTKEY))
|
||||
{
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.78 2006/07/25 19:13:00 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.79 2006/10/04 00:29:49 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -558,12 +558,12 @@ _bt_checkkeys(IndexScanDesc scan,
|
|||
*continuescan = true; /* default assumption */
|
||||
|
||||
/*
|
||||
* If the scan specifies not to return killed tuples, then we treat
|
||||
* a killed tuple as not passing the qual. Most of the time, it's a
|
||||
* win to not bother examining the tuple's index keys, but just return
|
||||
* If the scan specifies not to return killed tuples, then we treat a
|
||||
* killed tuple as not passing the qual. Most of the time, it's a win to
|
||||
* not bother examining the tuple's index keys, but just return
|
||||
* immediately with continuescan = true to proceed to the next tuple.
|
||||
* However, if this is the last tuple on the page, we should check
|
||||
* the index keys to prevent uselessly advancing to the next page.
|
||||
* However, if this is the last tuple on the page, we should check the
|
||||
* index keys to prevent uselessly advancing to the next page.
|
||||
*/
|
||||
if (scan->ignore_killed_tuples && ItemIdDeleted(iid))
|
||||
{
|
||||
|
@ -580,9 +580,10 @@ _bt_checkkeys(IndexScanDesc scan,
|
|||
if (offnum > P_FIRSTDATAKEY(opaque))
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* OK, we want to check the keys, but we'll return FALSE even
|
||||
* if the tuple passes the key tests.
|
||||
* OK, we want to check the keys, but we'll return FALSE even if the
|
||||
* tuple passes the key tests.
|
||||
*/
|
||||
tuple_valid = false;
|
||||
}
|
||||
|
@ -735,9 +736,8 @@ _bt_check_rowcompare(ScanKey skey, IndexTuple tuple, TupleDesc tupdesc,
|
|||
/*
|
||||
* Unlike the simple-scankey case, this isn't a disallowed case.
|
||||
* But it can never match. If all the earlier row comparison
|
||||
* columns are required for the scan direction, we can stop
|
||||
* the scan, because there can't be another tuple that will
|
||||
* succeed.
|
||||
* columns are required for the scan direction, we can stop the
|
||||
* scan, because there can't be another tuple that will succeed.
|
||||
*/
|
||||
if (subkey != (ScanKey) DatumGetPointer(skey->sk_argument))
|
||||
subkey--;
|
||||
|
@ -795,8 +795,8 @@ _bt_check_rowcompare(ScanKey skey, IndexTuple tuple, TupleDesc tupdesc,
|
|||
{
|
||||
/*
|
||||
* Tuple fails this qual. If it's a required qual for the current
|
||||
* scan direction, then we can conclude no further tuples will
|
||||
* pass, either. Note we have to look at the deciding column, not
|
||||
* scan direction, then we can conclude no further tuples will pass,
|
||||
* either. Note we have to look at the deciding column, not
|
||||
* necessarily the first or last column of the row condition.
|
||||
*/
|
||||
if ((subkey->sk_flags & SK_BT_REQFWD) &&
|
||||
|
@ -881,9 +881,9 @@ _bt_killitems(IndexScanDesc scan, bool haveLock)
|
|||
}
|
||||
|
||||
/*
|
||||
* Since this can be redone later if needed, it's treated the same
|
||||
* as a commit-hint-bit status update for heap tuples: we mark the
|
||||
* buffer dirty but don't make a WAL log entry.
|
||||
* Since this can be redone later if needed, it's treated the same as a
|
||||
* commit-hint-bit status update for heap tuples: we mark the buffer dirty
|
||||
* but don't make a WAL log entry.
|
||||
*
|
||||
* Whenever we mark anything LP_DELETEd, we also set the page's
|
||||
* BTP_HAS_GARBAGE flag, which is likewise just a hint.
|
||||
|
@ -898,8 +898,8 @@ _bt_killitems(IndexScanDesc scan, bool haveLock)
|
|||
LockBuffer(so->currPos.buf, BUFFER_LOCK_UNLOCK);
|
||||
|
||||
/*
|
||||
* Always reset the scan state, so we don't look for same items
|
||||
* on other pages.
|
||||
* Always reset the scan state, so we don't look for same items on other
|
||||
* pages.
|
||||
*/
|
||||
so->numKilled = 0;
|
||||
}
|
||||
|
@ -987,7 +987,8 @@ _bt_start_vacuum(Relation rel)
|
|||
LWLockAcquire(BtreeVacuumLock, LW_EXCLUSIVE);
|
||||
|
||||
/* Assign the next cycle ID, being careful to avoid zero */
|
||||
do {
|
||||
do
|
||||
{
|
||||
result = ++(btvacinfo->cycle_ctr);
|
||||
} while (result == 0);
|
||||
|
||||
|
|
|
@ -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.37 2006/08/07 16:57:56 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtxlog.c,v 1.38 2006/10/04 00:29:49 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -376,8 +376,8 @@ btree_xlog_delete(XLogRecPtr lsn, XLogRecord *record)
|
|||
}
|
||||
|
||||
/*
|
||||
* Mark the page as not containing any LP_DELETE items --- see comments
|
||||
* in _bt_delitems().
|
||||
* Mark the page as not containing any LP_DELETE items --- see comments in
|
||||
* _bt_delitems().
|
||||
*/
|
||||
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||
opaque->btpo_flags &= ~BTP_HAS_GARBAGE;
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/clog.c,v 1.39 2006/07/13 16:49:12 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/clog.c,v 1.40 2006/10/04 00:29:49 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/multixact.c,v 1.20 2006/07/20 00:46:42 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/multixact.c,v 1.21 2006/10/04 00:29:49 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -1493,10 +1493,10 @@ CheckPointMultiXact(void)
|
|||
|
||||
/*
|
||||
* Truncate the SLRU files. This could be done at any time, but
|
||||
* checkpoint seems a reasonable place for it. There is one exception:
|
||||
* if we are called during xlog recovery, then shared->latest_page_number
|
||||
* isn't valid (because StartupMultiXact hasn't been called yet) and
|
||||
* so SimpleLruTruncate would get confused. It seems best not to risk
|
||||
* checkpoint seems a reasonable place for it. There is one exception: if
|
||||
* we are called during xlog recovery, then shared->latest_page_number
|
||||
* isn't valid (because StartupMultiXact hasn't been called yet) and so
|
||||
* SimpleLruTruncate would get confused. It seems best not to risk
|
||||
* removing any data during recovery anyway, so don't truncate.
|
||||
*/
|
||||
if (!InRecovery)
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/slru.c,v 1.38 2006/07/14 14:52:17 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/slru.c,v 1.39 2006/10/04 00:29:49 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -653,9 +653,9 @@ SlruPhysicalWritePage(SlruCtl ctl, int pageno, int slotno, SlruFlush fdata)
|
|||
* Easiest way to deal with that is to accept references to
|
||||
* nonexistent files here and in SlruPhysicalReadPage.)
|
||||
*
|
||||
* Note: it is possible for more than one backend to be executing
|
||||
* this code simultaneously for different pages of the same file.
|
||||
* Hence, don't use O_EXCL or O_TRUNC or anything like that.
|
||||
* Note: it is possible for more than one backend to be executing this
|
||||
* code simultaneously for different pages of the same file. Hence,
|
||||
* don't use O_EXCL or O_TRUNC or anything like that.
|
||||
*/
|
||||
SlruFileName(ctl, path, segno);
|
||||
fd = BasicOpenFile(path, O_RDWR | O_CREAT | PG_BINARY,
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/twophase.c,v 1.23 2006/10/03 21:21:35 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/twophase.c,v 1.24 2006/10/04 00:29:49 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Each global transaction is associated with a global transaction
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/varsup.c,v 1.74 2006/09/26 17:21:39 alvherre Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/varsup.c,v 1.75 2006/10/04 00:29:49 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -133,10 +133,10 @@ GetNewTransactionId(bool isSubXact)
|
|||
{
|
||||
/*
|
||||
* Use volatile pointer to prevent code rearrangement; other backends
|
||||
* could be examining my subxids info concurrently, and we don't
|
||||
* want them to see an invalid intermediate state, such as
|
||||
* incrementing nxids before filling the array entry. Note we are
|
||||
* assuming that TransactionId and int fetch/store are atomic.
|
||||
* could be examining my subxids info concurrently, and we don't want
|
||||
* them to see an invalid intermediate state, such as incrementing
|
||||
* nxids before filling the array entry. Note we are assuming that
|
||||
* TransactionId and int fetch/store are atomic.
|
||||
*/
|
||||
volatile PGPROC *myproc = MyProc;
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.226 2006/08/27 19:11:46 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.227 2006/10/04 00:29:49 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -1379,9 +1379,9 @@ StartTransaction(void)
|
|||
PG_TRACE1(transaction__start, s->transactionId);
|
||||
|
||||
/*
|
||||
* set transaction_timestamp() (a/k/a now()). We want this to be the
|
||||
* same as the first command's statement_timestamp(), so don't do a
|
||||
* fresh GetCurrentTimestamp() call (which'd be expensive anyway).
|
||||
* set transaction_timestamp() (a/k/a now()). We want this to be the same
|
||||
* as the first command's statement_timestamp(), so don't do a fresh
|
||||
* GetCurrentTimestamp() call (which'd be expensive anyway).
|
||||
*/
|
||||
xactStartTimestamp = stmtStartTimestamp;
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.249 2006/08/21 16:16:31 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.250 2006/10/04 00:29:49 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -697,9 +697,9 @@ begin:;
|
|||
/*
|
||||
* NOTE: We disallow len == 0 because it provides a useful bit of extra
|
||||
* error checking in ReadRecord. This means that all callers of
|
||||
* XLogInsert must supply at least some not-in-a-buffer data. However,
|
||||
* we make an exception for XLOG SWITCH records because we don't want
|
||||
* them to ever cross a segment boundary.
|
||||
* XLogInsert must supply at least some not-in-a-buffer data. However, we
|
||||
* make an exception for XLOG SWITCH records because we don't want them to
|
||||
* ever cross a segment boundary.
|
||||
*/
|
||||
if (len == 0 && !isLogSwitch)
|
||||
elog(PANIC, "invalid xlog record length %u", len);
|
||||
|
@ -752,8 +752,8 @@ begin:;
|
|||
* checkpoint, so it's better to be slow in this case and fast otherwise.
|
||||
*
|
||||
* If we aren't doing full-page writes then RedoRecPtr doesn't actually
|
||||
* affect the contents of the XLOG record, so we'll update our local
|
||||
* copy but not force a recomputation.
|
||||
* affect the contents of the XLOG record, so we'll update our local copy
|
||||
* but not force a recomputation.
|
||||
*/
|
||||
if (!XLByteEQ(RedoRecPtr, Insert->RedoRecPtr))
|
||||
{
|
||||
|
@ -782,10 +782,10 @@ begin:;
|
|||
}
|
||||
|
||||
/*
|
||||
* Also check to see if forcePageWrites was just turned on; if we
|
||||
* weren't already doing full-page writes then go back and recompute.
|
||||
* (If it was just turned off, we could recompute the record without
|
||||
* full pages, but we choose not to bother.)
|
||||
* Also check to see if forcePageWrites was just turned on; if we weren't
|
||||
* already doing full-page writes then go back and recompute. (If it was
|
||||
* just turned off, we could recompute the record without full pages, but
|
||||
* we choose not to bother.)
|
||||
*/
|
||||
if (Insert->forcePageWrites && !doPageWrites)
|
||||
{
|
||||
|
@ -870,11 +870,11 @@ begin:;
|
|||
INSERT_RECPTR(RecPtr, Insert, curridx);
|
||||
|
||||
/*
|
||||
* If the record is an XLOG_SWITCH, and we are exactly at the start
|
||||
* of a segment, we need not insert it (and don't want to because
|
||||
* we'd like consecutive switch requests to be no-ops). Instead,
|
||||
* make sure everything is written and flushed through the end of
|
||||
* the prior segment, and return the prior segment's end address.
|
||||
* If the record is an XLOG_SWITCH, and we are exactly at the start of a
|
||||
* segment, we need not insert it (and don't want to because we'd like
|
||||
* consecutive switch requests to be no-ops). Instead, make sure
|
||||
* everything is written and flushed through the end of the prior segment,
|
||||
* and return the prior segment's end address.
|
||||
*/
|
||||
if (isLogSwitch &&
|
||||
(RecPtr.xrecoff % XLogSegSize) == SizeOfXLogLongPHD)
|
||||
|
@ -1019,8 +1019,8 @@ begin:;
|
|||
LWLockAcquire(WALWriteLock, LW_EXCLUSIVE);
|
||||
|
||||
/*
|
||||
* Flush through the end of the page containing XLOG_SWITCH,
|
||||
* and perform end-of-segment actions (eg, notifying archiver).
|
||||
* Flush through the end of the page containing XLOG_SWITCH, and
|
||||
* perform end-of-segment actions (eg, notifying archiver).
|
||||
*/
|
||||
WriteRqst = XLogCtl->xlblocks[curridx];
|
||||
FlushRqst.Write = WriteRqst;
|
||||
|
@ -1667,8 +1667,8 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible, bool xlog_switch)
|
|||
* switch.
|
||||
*
|
||||
* This is also the right place to notify the Archiver that the
|
||||
* segment is ready to copy to archival storage, and to update
|
||||
* the timer for archive_timeout.
|
||||
* segment is ready to copy to archival storage, and to update the
|
||||
* timer for archive_timeout.
|
||||
*/
|
||||
if (finishing_seg || (xlog_switch && last_iteration))
|
||||
{
|
||||
|
@ -2300,12 +2300,12 @@ XLogFileClose(void)
|
|||
Assert(openLogFile >= 0);
|
||||
|
||||
/*
|
||||
* posix_fadvise is problematic on many platforms: on older x86 Linux
|
||||
* it just dumps core, and there are reports of problems on PPC platforms
|
||||
* as well. The following is therefore disabled for the time being.
|
||||
* We could consider some kind of configure test to see if it's safe to
|
||||
* use, but since we lack hard evidence that there's any useful performance
|
||||
* gain to be had, spending time on that seems unprofitable for now.
|
||||
* posix_fadvise is problematic on many platforms: on older x86 Linux it
|
||||
* just dumps core, and there are reports of problems on PPC platforms as
|
||||
* well. The following is therefore disabled for the time being. We could
|
||||
* consider some kind of configure test to see if it's safe to use, but
|
||||
* since we lack hard evidence that there's any useful performance gain to
|
||||
* be had, spending time on that seems unprofitable for now.
|
||||
*/
|
||||
#ifdef NOT_USED
|
||||
|
||||
|
@ -2315,14 +2315,13 @@ XLogFileClose(void)
|
|||
* active, because archiver process could use the cache to read the WAL
|
||||
* segment.
|
||||
*
|
||||
* While O_DIRECT works for O_SYNC, posix_fadvise() works for fsync()
|
||||
* and O_SYNC, and some platforms only have posix_fadvise().
|
||||
* While O_DIRECT works for O_SYNC, posix_fadvise() works for fsync() and
|
||||
* O_SYNC, and some platforms only have posix_fadvise().
|
||||
*/
|
||||
#if defined(HAVE_DECL_POSIX_FADVISE) && defined(POSIX_FADV_DONTNEED)
|
||||
if (!XLogArchivingActive())
|
||||
posix_fadvise(openLogFile, 0, 0, POSIX_FADV_DONTNEED);
|
||||
#endif
|
||||
|
||||
#endif /* NOT_USED */
|
||||
|
||||
if (close(openLogFile))
|
||||
|
@ -2978,8 +2977,8 @@ ReadRecord(XLogRecPtr *RecPtr, int emode)
|
|||
got_record:;
|
||||
|
||||
/*
|
||||
* xl_len == 0 is bad data for everything except XLOG SWITCH, where
|
||||
* it is required.
|
||||
* xl_len == 0 is bad data for everything except XLOG SWITCH, where it is
|
||||
* required.
|
||||
*/
|
||||
if (record->xl_rmid == RM_XLOG_ID && record->xl_info == XLOG_SWITCH)
|
||||
{
|
||||
|
@ -3168,6 +3167,7 @@ got_record:;
|
|||
EndRecPtr.xrecoff = RecPtr->xrecoff + MAXALIGN(total_len);
|
||||
ReadRecPtr = *RecPtr;
|
||||
memcpy(buffer, record, total_len);
|
||||
|
||||
/*
|
||||
* Special processing if it's an XLOG SWITCH record
|
||||
*/
|
||||
|
@ -3177,10 +3177,11 @@ got_record:;
|
|||
EndRecPtr.xrecoff += XLogSegSize - 1;
|
||||
EndRecPtr.xrecoff -= EndRecPtr.xrecoff % XLogSegSize;
|
||||
nextRecord = NULL; /* definitely not on same page */
|
||||
|
||||
/*
|
||||
* Pretend that readBuf contains the last page of the segment.
|
||||
* This is just to avoid Assert failure in StartupXLOG if XLOG
|
||||
* ends with this segment.
|
||||
* Pretend that readBuf contains the last page of the segment. This is
|
||||
* just to avoid Assert failure in StartupXLOG if XLOG ends with this
|
||||
* segment.
|
||||
*/
|
||||
readOff = XLogSegSize - XLOG_BLCKSZ;
|
||||
}
|
||||
|
@ -4812,10 +4813,10 @@ StartupXLOG(void)
|
|||
int rmid;
|
||||
|
||||
/*
|
||||
* Update pg_control to show that we are recovering and to show
|
||||
* the selected checkpoint as the place we are starting from.
|
||||
* We also mark pg_control with any minimum recovery stop point
|
||||
* obtained from a backup history file.
|
||||
* Update pg_control to show that we are recovering and to show the
|
||||
* selected checkpoint as the place we are starting from. We also mark
|
||||
* pg_control with any minimum recovery stop point obtained from a
|
||||
* backup history file.
|
||||
*/
|
||||
if (InArchiveRecovery)
|
||||
{
|
||||
|
@ -4839,12 +4840,12 @@ StartupXLOG(void)
|
|||
UpdateControlFile();
|
||||
|
||||
/*
|
||||
* If there was a backup label file, it's done its job and the
|
||||
* info has now been propagated into pg_control. We must get rid of
|
||||
* the label file so that if we crash during recovery, we'll pick up
|
||||
* at the latest recovery restartpoint instead of going all the way
|
||||
* back to the backup start point. It seems prudent though to just
|
||||
* rename the file out of the way rather than delete it completely.
|
||||
* If there was a backup label file, it's done its job and the info
|
||||
* has now been propagated into pg_control. We must get rid of the
|
||||
* label file so that if we crash during recovery, we'll pick up at
|
||||
* the latest recovery restartpoint instead of going all the way back
|
||||
* to the backup start point. It seems prudent though to just rename
|
||||
* the file out of the way rather than delete it completely.
|
||||
*/
|
||||
if (haveBackupLabel)
|
||||
{
|
||||
|
@ -5739,8 +5740,8 @@ RecoveryRestartPoint(const CheckPoint *checkPoint)
|
|||
int rmid;
|
||||
|
||||
/*
|
||||
* Do nothing if the elapsed time since the last restartpoint is less
|
||||
* than half of checkpoint_timeout. (We use a value less than
|
||||
* Do nothing if the elapsed time since the last restartpoint is less than
|
||||
* half of checkpoint_timeout. (We use a value less than
|
||||
* checkpoint_timeout so that variations in the timing of checkpoints on
|
||||
* the master, or speed of transmission of WAL segments to a slave, won't
|
||||
* make the slave skip a restartpoint once it's synced with the master.)
|
||||
|
@ -5770,9 +5771,9 @@ RecoveryRestartPoint(const CheckPoint *checkPoint)
|
|||
CheckPointGuts(checkPoint->redo);
|
||||
|
||||
/*
|
||||
* Update pg_control so that any subsequent crash will restart from
|
||||
* this checkpoint. Note: ReadRecPtr gives the XLOG address of the
|
||||
* checkpoint record itself.
|
||||
* Update pg_control so that any subsequent crash will restart from this
|
||||
* checkpoint. Note: ReadRecPtr gives the XLOG address of the checkpoint
|
||||
* record itself.
|
||||
*/
|
||||
ControlFile->prevCheckPoint = ControlFile->checkPoint;
|
||||
ControlFile->checkPoint = ReadRecPtr;
|
||||
|
@ -6142,18 +6143,18 @@ pg_start_backup(PG_FUNCTION_ARGS)
|
|||
* Mark backup active in shared memory. We must do full-page WAL writes
|
||||
* during an on-line backup even if not doing so at other times, because
|
||||
* it's quite possible for the backup dump to obtain a "torn" (partially
|
||||
* written) copy of a database page if it reads the page concurrently
|
||||
* with our write to the same page. This can be fixed as long as the
|
||||
* first write to the page in the WAL sequence is a full-page write.
|
||||
* Hence, we turn on forcePageWrites and then force a CHECKPOINT, to
|
||||
* ensure there are no dirty pages in shared memory that might get
|
||||
* dumped while the backup is in progress without having a corresponding
|
||||
* WAL record. (Once the backup is complete, we need not force full-page
|
||||
* writes anymore, since we expect that any pages not modified during
|
||||
* the backup interval must have been correctly captured by the backup.)
|
||||
* written) copy of a database page if it reads the page concurrently with
|
||||
* our write to the same page. This can be fixed as long as the first
|
||||
* write to the page in the WAL sequence is a full-page write. Hence, we
|
||||
* turn on forcePageWrites and then force a CHECKPOINT, to ensure there
|
||||
* are no dirty pages in shared memory that might get dumped while the
|
||||
* backup is in progress without having a corresponding WAL record. (Once
|
||||
* the backup is complete, we need not force full-page writes anymore,
|
||||
* since we expect that any pages not modified during the backup interval
|
||||
* must have been correctly captured by the backup.)
|
||||
*
|
||||
* We must hold WALInsertLock to change the value of forcePageWrites,
|
||||
* to ensure adequate interlocking against XLogInsert().
|
||||
* We must hold WALInsertLock to change the value of forcePageWrites, to
|
||||
* ensure adequate interlocking against XLogInsert().
|
||||
*/
|
||||
LWLockAcquire(WALInsertLock, LW_EXCLUSIVE);
|
||||
if (XLogCtl->Insert.forcePageWrites)
|
||||
|
@ -6303,10 +6304,9 @@ pg_stop_backup(PG_FUNCTION_ARGS)
|
|||
LWLockRelease(WALInsertLock);
|
||||
|
||||
/*
|
||||
* Force a switch to a new xlog segment file, so that the backup
|
||||
* is valid as soon as archiver moves out the current segment file.
|
||||
* We'll report the end address of the XLOG SWITCH record as the backup
|
||||
* stopping point.
|
||||
* Force a switch to a new xlog segment file, so that the backup is valid
|
||||
* as soon as archiver moves out the current segment file. We'll report
|
||||
* the end address of the XLOG SWITCH record as the backup stopping point.
|
||||
*/
|
||||
stoppoint = RequestXLogSwitch();
|
||||
|
||||
|
@ -6392,9 +6392,9 @@ pg_stop_backup(PG_FUNCTION_ARGS)
|
|||
BACKUP_LABEL_FILE)));
|
||||
|
||||
/*
|
||||
* Clean out any no-longer-needed history files. As a side effect,
|
||||
* this will post a .ready file for the newly created history file,
|
||||
* notifying the archiver that history file may be archived immediately.
|
||||
* Clean out any no-longer-needed history files. As a side effect, this
|
||||
* will post a .ready file for the newly created history file, notifying
|
||||
* the archiver that history file may be archived immediately.
|
||||
*/
|
||||
CleanupBackupHistory();
|
||||
|
||||
|
@ -6536,8 +6536,8 @@ pg_xlogfile_name_offset(PG_FUNCTION_ARGS)
|
|||
locationpoint.xrecoff = uxrecoff;
|
||||
|
||||
/*
|
||||
* Construct a tuple descriptor for the result row. This must match
|
||||
* this function's pg_proc entry!
|
||||
* Construct a tuple descriptor for the result row. This must match this
|
||||
* function's pg_proc entry!
|
||||
*/
|
||||
resultTupleDesc = CreateTemplateTupleDesc(2, false);
|
||||
TupleDescInitEntry(resultTupleDesc, (AttrNumber) 1, "file_name",
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue