pgindent run for 8.2.

This commit is contained in:
Bruce Momjian 2006-10-04 00:30:14 +00:00
parent 451e419e98
commit f99a569a2e
522 changed files with 21297 additions and 17170 deletions

View File

@ -8,7 +8,7 @@
* Author: Andreas Pflug <pgadmin@pse-consulting.de> * Author: Andreas Pflug <pgadmin@pse-consulting.de>
* *
* IDENTIFICATION * 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 #ifdef unlink
#undef unlink #undef unlink
#endif #endif
#endif #endif
extern DLLIMPORT char *DataDir; extern DLLIMPORT char *DataDir;
@ -68,13 +67,14 @@ typedef struct
* Return an absolute path. Argument may be absolute or * Return an absolute path. Argument may be absolute or
* relative to the DataDir. * relative to the DataDir.
*/ */
static char *absClusterPath(text *arg, bool logAllowed) static char *
absClusterPath(text *arg, bool logAllowed)
{ {
char *filename; char *filename;
int len=VARSIZE(arg) - VARHDRSZ; int len = VARSIZE(arg) - VARHDRSZ;
int dlen = strlen(DataDir); int dlen = strlen(DataDir);
filename = palloc(len+1); filename = palloc(len + 1);
memcpy(filename, VARDATA(arg), len); memcpy(filename, VARDATA(arg), len);
filename[len] = 0; filename[len] = 0;
@ -96,7 +96,8 @@ static char *absClusterPath(text *arg, bool logAllowed)
} }
else else
{ {
char *absname = palloc(dlen+len+2); char *absname = palloc(dlen + len + 2);
sprintf(absname, "%s/%s", DataDir, filename); sprintf(absname, "%s/%s", DataDir, filename);
pfree(filename); pfree(filename);
return absname; return absname;
@ -122,7 +123,8 @@ requireSuperuser(void)
* generic file handling functions * generic file handling functions
*/ */
Datum pg_file_write(PG_FUNCTION_ARGS) Datum
pg_file_write(PG_FUNCTION_ARGS)
{ {
FILE *f; FILE *f;
char *filename; char *filename;
@ -137,6 +139,7 @@ Datum pg_file_write(PG_FUNCTION_ARGS)
if (PG_ARGISNULL(2) || !PG_GETARG_BOOL(2)) if (PG_ARGISNULL(2) || !PG_GETARG_BOOL(2))
{ {
struct stat fst; struct stat fst;
if (stat(filename, &fst) >= 0) if (stat(filename, &fst) >= 0)
ereport(ERROR, ereport(ERROR,
(ERRCODE_DUPLICATE_FILE, (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; int rc;
requireSuperuser(); requireSuperuser();
@ -179,12 +185,12 @@ Datum pg_file_rename(PG_FUNCTION_ARGS)
if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
PG_RETURN_NULL(); PG_RETURN_NULL();
fn1=absClusterPath(PG_GETARG_TEXT_P(0), false); fn1 = absClusterPath(PG_GETARG_TEXT_P(0), false);
fn2=absClusterPath(PG_GETARG_TEXT_P(1), false); fn2 = absClusterPath(PG_GETARG_TEXT_P(1), false);
if (PG_ARGISNULL(2)) if (PG_ARGISNULL(2))
fn3=0; fn3 = 0;
else else
fn3=absClusterPath(PG_GETARG_TEXT_P(2), false); fn3 = absClusterPath(PG_GETARG_TEXT_P(2), false);
if (access(fn1, W_OK) < 0) if (access(fn1, W_OK) < 0)
{ {
@ -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; 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; FuncCallContext *funcctx;
struct dirent *de; struct dirent *de;
@ -308,7 +316,7 @@ Datum pg_logdir_ls(PG_FUNCTION_ARGS)
MemoryContext oldcontext; MemoryContext oldcontext;
TupleDesc tupdesc; TupleDesc tupdesc;
funcctx=SRF_FIRSTCALL_INIT(); funcctx = SRF_FIRSTCALL_INIT();
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
fctx = palloc(sizeof(directory_fctx)); fctx = palloc(sizeof(directory_fctx));
@ -316,7 +324,7 @@ Datum pg_logdir_ls(PG_FUNCTION_ARGS)
fctx->location = Log_directory; fctx->location = Log_directory;
else else
{ {
fctx->location = palloc(strlen(DataDir) + strlen(Log_directory) +2); fctx->location = palloc(strlen(DataDir) + strlen(Log_directory) + 2);
sprintf(fctx->location, "%s/%s", DataDir, Log_directory); sprintf(fctx->location, "%s/%s", DataDir, Log_directory);
} }
tupdesc = CreateTemplateTupleDesc(2, false); tupdesc = CreateTemplateTupleDesc(2, false);
@ -338,8 +346,8 @@ Datum pg_logdir_ls(PG_FUNCTION_ARGS)
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
} }
funcctx=SRF_PERCALL_SETUP(); funcctx = SRF_PERCALL_SETUP();
fctx = (directory_fctx*) funcctx->user_fctx; fctx = (directory_fctx *) funcctx->user_fctx;
if (!fctx->dirdesc) /* not a readable directory */ if (!fctx->dirdesc) /* not a readable directory */
SRF_RETURN_DONE(funcctx); SRF_RETURN_DONE(funcctx);
@ -352,14 +360,14 @@ Datum pg_logdir_ls(PG_FUNCTION_ARGS)
char *field[MAXDATEFIELDS]; char *field[MAXDATEFIELDS];
char lowstr[MAXDATELEN + 1]; char lowstr[MAXDATELEN + 1];
int dtype; int dtype;
int nf, ftype[MAXDATEFIELDS]; int nf,
ftype[MAXDATEFIELDS];
fsec_t fsec; fsec_t fsec;
int tz = 0; int tz = 0;
struct pg_tm date; struct pg_tm date;
/* /*
* Default format: * Default format: postgresql-YYYY-MM-DD_HHMMSS.log
* postgresql-YYYY-MM-DD_HHMMSS.log
*/ */
if (strlen(de->d_name) != 32 if (strlen(de->d_name) != 32
|| memcmp(de->d_name, "postgresql-", 11) || memcmp(de->d_name, "postgresql-", 11)

View File

@ -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 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 called by the backend in the process of processing queries. The calling
@ -170,7 +170,7 @@ cube_in(PG_FUNCTION_ARGS)
cube_scanner_finish(); cube_scanner_finish();
PG_RETURN_POINTER (result); PG_RETURN_POINTER(result);
} }
/* Allow conversion from text to cube to allow input of computed strings */ /* Allow conversion from text to cube to allow input of computed strings */
@ -182,7 +182,7 @@ cube(PG_FUNCTION_ARGS)
cstring = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(PG_GETARG_TEXT_P(0)))); cstring = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(PG_GETARG_TEXT_P(0))));
PG_RETURN_DATUM (DirectFunctionCall1 (cube_in, PointerGetDatum(cstring))); PG_RETURN_DATUM(DirectFunctionCall1(cube_in, PointerGetDatum(cstring)));
} }
@ -196,8 +196,10 @@ cube_a_f8_f8(PG_FUNCTION_ARGS)
int dim; int dim;
int size; int size;
NDBOX *result; NDBOX *result;
ArrayType *ur, *ll; ArrayType *ur,
double *dur, *dll; *ll;
double *dur,
*dll;
ur = (ArrayType *) PG_GETARG_VARLENA_P(0); ur = (ArrayType *) PG_GETARG_VARLENA_P(0);
ll = (ArrayType *) PG_GETARG_VARLENA_P(1); ll = (ArrayType *) PG_GETARG_VARLENA_P(1);
@ -221,15 +223,15 @@ cube_a_f8_f8(PG_FUNCTION_ARGS)
dll = ARRPTR(ll); dll = ARRPTR(ll);
size = offsetof(NDBOX, x[0]) + sizeof(double) * 2 * dim; size = offsetof(NDBOX, x[0]) + sizeof(double) * 2 * dim;
result = (NDBOX *) palloc (size); result = (NDBOX *) palloc(size);
memset (result, 0, size); memset(result, 0, size);
result->size = size; result->size = size;
result->dim = dim; result->dim = dim;
for (i=0; i<dim; i++) for (i = 0; i < dim; i++)
{ {
result->x[i] = dur[i]; result->x[i] = dur[i];
result->x[i+dim] = dll[i]; result->x[i + dim] = dll[i];
} }
PG_RETURN_POINTER(result); PG_RETURN_POINTER(result);
@ -262,15 +264,15 @@ cube_a_f8(PG_FUNCTION_ARGS)
dur = ARRPTR(ur); dur = ARRPTR(ur);
size = offsetof(NDBOX, x[0]) + sizeof(double) * 2 * dim; size = offsetof(NDBOX, x[0]) + sizeof(double) * 2 * dim;
result = (NDBOX *) palloc (size); result = (NDBOX *) palloc(size);
memset (result, 0, size); memset(result, 0, size);
result->size = size; result->size = size;
result->dim = dim; result->dim = dim;
for (i=0; i<dim; i++) for (i = 0; i < dim; i++)
{ {
result->x[i] = dur[i]; result->x[i] = dur[i];
result->x[i+dim] = dur[i]; result->x[i + dim] = dur[i];
} }
PG_RETURN_POINTER(result); PG_RETURN_POINTER(result);
@ -279,9 +281,12 @@ cube_a_f8(PG_FUNCTION_ARGS)
Datum Datum
cube_subset(PG_FUNCTION_ARGS) cube_subset(PG_FUNCTION_ARGS)
{ {
NDBOX *c, *result; NDBOX *c,
*result;
ArrayType *idx; ArrayType *idx;
int size, dim, i; int size,
dim,
i;
int *dx; int *dx;
c = (NDBOX *) PG_GETARG_POINTER(0); c = (NDBOX *) PG_GETARG_POINTER(0);
@ -294,26 +299,26 @@ cube_subset(PG_FUNCTION_ARGS)
errmsg("Cannot work with NULL arrays"))); errmsg("Cannot work with NULL arrays")));
} }
dx = (int4 *) ARR_DATA_PTR (idx); dx = (int4 *) ARR_DATA_PTR(idx);
dim = ARRNELEMS(idx); dim = ARRNELEMS(idx);
size = offsetof(NDBOX, x[0]) + sizeof(double) * 2 * dim; size = offsetof(NDBOX, x[0]) + sizeof(double) * 2 * dim;
result = (NDBOX *) palloc (size); result = (NDBOX *) palloc(size);
memset (result, 0, size); memset(result, 0, size);
result->size = size; result->size = size;
result->dim = dim; result->dim = dim;
for (i=0; i<dim; i++) for (i = 0; i < dim; i++)
{ {
if ((dx[i] <= 0) || (dx[i] > c->dim)) if ((dx[i] <= 0) || (dx[i] > c->dim))
{ {
pfree (result); pfree(result);
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR), (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
errmsg("Index out of bounds"))); errmsg("Index out of bounds")));
} }
result->x[i] = c->x[dx[i]-1]; result->x[i] = c->x[dx[i] - 1];
result->x[i+dim] = c->x[dx[i]+c->dim-1]; result->x[i + dim] = c->x[dx[i] + c->dim - 1];
} }
PG_RETURN_POINTER(result); PG_RETURN_POINTER(result);
@ -331,7 +336,7 @@ cube_out(PG_FUNCTION_ARGS)
initStringInfo(&buf); initStringInfo(&buf);
cube = (NDBOX *) PG_GETARG_POINTER (0); cube = (NDBOX *) PG_GETARG_POINTER(0);
dim = cube->dim; dim = cube->dim;
@ -369,7 +374,7 @@ cube_out(PG_FUNCTION_ARGS)
appendStringInfoChar(&buf, ')'); appendStringInfoChar(&buf, ')');
} }
PG_RETURN_CSTRING (buf.data); PG_RETURN_CSTRING(buf.data);
} }
@ -446,13 +451,13 @@ g_cube_union(PG_FUNCTION_ARGS)
*/ */
Datum Datum
g_cube_compress (PG_FUNCTION_ARGS) g_cube_compress(PG_FUNCTION_ARGS)
{ {
PG_RETURN_DATUM(PG_GETARG_DATUM(0)); PG_RETURN_DATUM(PG_GETARG_DATUM(0));
} }
Datum Datum
g_cube_decompress (PG_FUNCTION_ARGS) g_cube_decompress(PG_FUNCTION_ARGS)
{ {
PG_RETURN_DATUM(PG_GETARG_DATUM(0)); PG_RETURN_DATUM(PG_GETARG_DATUM(0));
} }
@ -463,7 +468,7 @@ g_cube_decompress (PG_FUNCTION_ARGS)
** As in the R-tree paper, we use change in area as our penalty metric ** As in the R-tree paper, we use change in area as our penalty metric
*/ */
Datum Datum
g_cube_penalty (PG_FUNCTION_ARGS) g_cube_penalty(PG_FUNCTION_ARGS)
{ {
GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0); GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1); GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
@ -481,7 +486,7 @@ g_cube_penalty (PG_FUNCTION_ARGS)
/* /*
* fprintf(stderr, "penalty\n"); fprintf(stderr, "\t%g\n", *result); * fprintf(stderr, "penalty\n"); fprintf(stderr, "\t%g\n", *result);
*/ */
PG_RETURN_FLOAT8 (*result); PG_RETURN_FLOAT8(*result);
} }
@ -546,7 +551,7 @@ g_cube_picksplit(PG_FUNCTION_ARGS)
/* size_waste = size_union - size_inter; */ /* size_waste = size_union - size_inter; */
union_d = cube_union_v0(datum_alpha, datum_beta); union_d = cube_union_v0(datum_alpha, datum_beta);
rt_cube_size(union_d, &size_union); rt_cube_size(union_d, &size_union);
inter_d = (NDBOX *) DatumGetPointer (DirectFunctionCall2 inter_d = (NDBOX *) DatumGetPointer(DirectFunctionCall2
(cube_inter, (cube_inter,
entryvec->vector[i].key, entryvec->vector[j].key)); entryvec->vector[i].key, entryvec->vector[j].key));
rt_cube_size(inter_d, &size_inter); rt_cube_size(inter_d, &size_inter);
@ -649,12 +654,13 @@ g_cube_picksplit(PG_FUNCTION_ARGS)
Datum Datum
g_cube_same(PG_FUNCTION_ARGS) g_cube_same(PG_FUNCTION_ARGS)
{ {
NDBOX *b1, *b2; NDBOX *b1,
*b2;
bool *result; bool *result;
b1 = (NDBOX *) PG_GETARG_POINTER (0); b1 = (NDBOX *) PG_GETARG_POINTER(0);
b2 = (NDBOX *) PG_GETARG_POINTER (1); b2 = (NDBOX *) PG_GETARG_POINTER(1);
result = (bool *) PG_GETARG_POINTER (2); result = (bool *) PG_GETARG_POINTER(2);
if (cube_cmp_v0(b1, b2) == 0) if (cube_cmp_v0(b1, b2) == 0)
*result = TRUE; *result = TRUE;
@ -664,7 +670,7 @@ g_cube_same(PG_FUNCTION_ARGS)
/* /*
* fprintf(stderr, "same: %s\n", (*result ? "TRUE" : "FALSE" )); * fprintf(stderr, "same: %s\n", (*result ? "TRUE" : "FALSE" ));
*/ */
PG_RETURN_POINTER (result); PG_RETURN_POINTER(result);
} }
/* /*
@ -803,14 +809,15 @@ cube_union_v0(NDBOX * a, NDBOX * b)
} }
Datum Datum
cube_union (PG_FUNCTION_ARGS) cube_union(PG_FUNCTION_ARGS)
{ {
NDBOX *a, *b; NDBOX *a,
*b;
a = (NDBOX *) PG_GETARG_POINTER(0); a = (NDBOX *) PG_GETARG_POINTER(0);
b = (NDBOX *) PG_GETARG_POINTER(1); b = (NDBOX *) PG_GETARG_POINTER(1);
PG_RETURN_POINTER(cube_union_v0(a,b)); PG_RETURN_POINTER(cube_union_v0(a, b));
} }
/* cube_inter */ /* cube_inter */
@ -818,7 +825,9 @@ Datum
cube_inter(PG_FUNCTION_ARGS) cube_inter(PG_FUNCTION_ARGS)
{ {
int i; int i;
NDBOX *result, *a, *b; NDBOX *result,
*a,
*b;
a = (NDBOX *) PG_GETARG_POINTER(0); a = (NDBOX *) PG_GETARG_POINTER(0);
b = (NDBOX *) PG_GETARG_POINTER(1); b = (NDBOX *) PG_GETARG_POINTER(1);
@ -874,7 +883,7 @@ cube_inter(PG_FUNCTION_ARGS)
/* /*
* Is it OK to return a non-null intersection for non-overlapping boxes? * Is it OK to return a non-null intersection for non-overlapping boxes?
*/ */
PG_RETURN_POINTER (result); PG_RETURN_POINTER(result);
} }
/* cube_size */ /* cube_size */
@ -892,7 +901,7 @@ cube_size(PG_FUNCTION_ARGS)
for (i = 0, j = a->dim; i < a->dim; i++, j++) for (i = 0, j = a->dim; i < a->dim; i++, j++)
result = result * Abs((a->x[j] - a->x[i])); result = result * Abs((a->x[j] - a->x[i]));
PG_RETURN_FLOAT8 (result); PG_RETURN_FLOAT8(result);
} }
void void
@ -997,7 +1006,8 @@ cube_cmp_v0(NDBOX * a, NDBOX * b)
Datum Datum
cube_cmp(PG_FUNCTION_ARGS) cube_cmp(PG_FUNCTION_ARGS)
{ {
NDBOX *a, *b; NDBOX *a,
*b;
a = (NDBOX *) PG_GETARG_POINTER(0); a = (NDBOX *) PG_GETARG_POINTER(0);
b = (NDBOX *) PG_GETARG_POINTER(1); b = (NDBOX *) PG_GETARG_POINTER(1);
@ -1009,7 +1019,8 @@ cube_cmp(PG_FUNCTION_ARGS)
Datum Datum
cube_eq(PG_FUNCTION_ARGS) cube_eq(PG_FUNCTION_ARGS)
{ {
NDBOX *a, *b; NDBOX *a,
*b;
a = (NDBOX *) PG_GETARG_POINTER(0); a = (NDBOX *) PG_GETARG_POINTER(0);
b = (NDBOX *) PG_GETARG_POINTER(1); b = (NDBOX *) PG_GETARG_POINTER(1);
@ -1021,7 +1032,8 @@ cube_eq(PG_FUNCTION_ARGS)
Datum Datum
cube_ne(PG_FUNCTION_ARGS) cube_ne(PG_FUNCTION_ARGS)
{ {
NDBOX *a, *b; NDBOX *a,
*b;
a = (NDBOX *) PG_GETARG_POINTER(0); a = (NDBOX *) PG_GETARG_POINTER(0);
b = (NDBOX *) PG_GETARG_POINTER(1); b = (NDBOX *) PG_GETARG_POINTER(1);
@ -1033,7 +1045,8 @@ cube_ne(PG_FUNCTION_ARGS)
Datum Datum
cube_lt(PG_FUNCTION_ARGS) cube_lt(PG_FUNCTION_ARGS)
{ {
NDBOX *a, *b; NDBOX *a,
*b;
a = (NDBOX *) PG_GETARG_POINTER(0); a = (NDBOX *) PG_GETARG_POINTER(0);
b = (NDBOX *) PG_GETARG_POINTER(1); b = (NDBOX *) PG_GETARG_POINTER(1);
@ -1045,7 +1058,8 @@ cube_lt(PG_FUNCTION_ARGS)
Datum Datum
cube_gt(PG_FUNCTION_ARGS) cube_gt(PG_FUNCTION_ARGS)
{ {
NDBOX *a, *b; NDBOX *a,
*b;
a = (NDBOX *) PG_GETARG_POINTER(0); a = (NDBOX *) PG_GETARG_POINTER(0);
b = (NDBOX *) PG_GETARG_POINTER(1); b = (NDBOX *) PG_GETARG_POINTER(1);
@ -1057,7 +1071,8 @@ cube_gt(PG_FUNCTION_ARGS)
Datum Datum
cube_le(PG_FUNCTION_ARGS) cube_le(PG_FUNCTION_ARGS)
{ {
NDBOX *a, *b; NDBOX *a,
*b;
a = (NDBOX *) PG_GETARG_POINTER(0); a = (NDBOX *) PG_GETARG_POINTER(0);
b = (NDBOX *) PG_GETARG_POINTER(1); b = (NDBOX *) PG_GETARG_POINTER(1);
@ -1069,7 +1084,8 @@ cube_le(PG_FUNCTION_ARGS)
Datum Datum
cube_ge(PG_FUNCTION_ARGS) cube_ge(PG_FUNCTION_ARGS)
{ {
NDBOX *a, *b; NDBOX *a,
*b;
a = (NDBOX *) PG_GETARG_POINTER(0); a = (NDBOX *) PG_GETARG_POINTER(0);
b = (NDBOX *) PG_GETARG_POINTER(1); b = (NDBOX *) PG_GETARG_POINTER(1);
@ -1122,7 +1138,8 @@ cube_contains_v0(NDBOX * a, NDBOX * b)
Datum Datum
cube_contains(PG_FUNCTION_ARGS) cube_contains(PG_FUNCTION_ARGS)
{ {
NDBOX *a, *b; NDBOX *a,
*b;
a = (NDBOX *) PG_GETARG_POINTER(0); a = (NDBOX *) PG_GETARG_POINTER(0);
b = (NDBOX *) PG_GETARG_POINTER(1); b = (NDBOX *) PG_GETARG_POINTER(1);
@ -1135,12 +1152,13 @@ cube_contains(PG_FUNCTION_ARGS)
Datum Datum
cube_contained(PG_FUNCTION_ARGS) cube_contained(PG_FUNCTION_ARGS)
{ {
NDBOX *a, *b; NDBOX *a,
*b;
a = (NDBOX *) PG_GETARG_POINTER(0); a = (NDBOX *) PG_GETARG_POINTER(0);
b = (NDBOX *) PG_GETARG_POINTER(1); b = (NDBOX *) PG_GETARG_POINTER(1);
PG_RETURN_BOOL (cube_contains_v0(b, a)); PG_RETURN_BOOL(cube_contains_v0(b, a));
} }
/* Overlap */ /* Overlap */
@ -1193,12 +1211,13 @@ cube_overlap_v0(NDBOX * a, NDBOX * b)
Datum Datum
cube_overlap(PG_FUNCTION_ARGS) cube_overlap(PG_FUNCTION_ARGS)
{ {
NDBOX *a, *b; NDBOX *a,
*b;
a = (NDBOX *) PG_GETARG_POINTER(0); a = (NDBOX *) PG_GETARG_POINTER(0);
b = (NDBOX *) PG_GETARG_POINTER(1); b = (NDBOX *) PG_GETARG_POINTER(1);
PG_RETURN_BOOL (cube_overlap_v0(a, b)); PG_RETURN_BOOL(cube_overlap_v0(a, b));
} }
@ -1213,7 +1232,8 @@ cube_distance(PG_FUNCTION_ARGS)
int i; int i;
double d, double d,
distance; distance;
NDBOX *a, *b; NDBOX *a,
*b;
a = (NDBOX *) PG_GETARG_POINTER(0); a = (NDBOX *) PG_GETARG_POINTER(0);
b = (NDBOX *) PG_GETARG_POINTER(1); b = (NDBOX *) PG_GETARG_POINTER(1);
@ -1398,7 +1418,7 @@ cube_f8(PG_FUNCTION_ARGS)
result->x[0] = PG_GETARG_FLOAT8(0); result->x[0] = PG_GETARG_FLOAT8(0);
result->x[1] = result->x[0]; result->x[1] = result->x[0];
PG_RETURN_POINTER (result); PG_RETURN_POINTER(result);
} }
/* Create a one dimensional box */ /* Create a one dimensional box */
@ -1416,7 +1436,7 @@ cube_f8_f8(PG_FUNCTION_ARGS)
result->x[0] = PG_GETARG_FLOAT8(0); result->x[0] = PG_GETARG_FLOAT8(0);
result->x[1] = PG_GETARG_FLOAT8(1); result->x[1] = PG_GETARG_FLOAT8(1);
PG_RETURN_POINTER (result); PG_RETURN_POINTER(result);
} }
/* Add a dimension to an existing cube with the same values for the new /* Add a dimension to an existing cube with the same values for the new
@ -1431,7 +1451,7 @@ cube_c_f8(PG_FUNCTION_ARGS)
int i; int i;
c = (NDBOX *) PG_GETARG_POINTER(0); c = (NDBOX *) PG_GETARG_POINTER(0);
x = PG_GETARG_FLOAT8 (1); x = PG_GETARG_FLOAT8(1);
size = offsetof(NDBOX, x[0]) + sizeof(double) * (c->dim + 1) *2; size = offsetof(NDBOX, x[0]) + sizeof(double) * (c->dim + 1) *2;
result = (NDBOX *) palloc(size); result = (NDBOX *) palloc(size);
@ -1455,13 +1475,14 @@ cube_c_f8_f8(PG_FUNCTION_ARGS)
{ {
NDBOX *c; NDBOX *c;
NDBOX *result; NDBOX *result;
double x1, x2; double x1,
x2;
int size; int size;
int i; int i;
c = (NDBOX *) PG_GETARG_POINTER(0); c = (NDBOX *) PG_GETARG_POINTER(0);
x1 = PG_GETARG_FLOAT8 (1); x1 = PG_GETARG_FLOAT8(1);
x2 = PG_GETARG_FLOAT8 (2); x2 = PG_GETARG_FLOAT8(2);
size = offsetof(NDBOX, x[0]) + sizeof(double) * (c->dim + 1) *2; size = offsetof(NDBOX, x[0]) + sizeof(double) * (c->dim + 1) *2;
result = (NDBOX *) palloc(size); result = (NDBOX *) palloc(size);
@ -1478,5 +1499,3 @@ cube_c_f8_f8(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(result); PG_RETURN_POINTER(result);
} }

View File

@ -8,7 +8,7 @@
* Darko Prenosil <Darko.Prenosil@finteh.hr> * Darko Prenosil <Darko.Prenosil@finteh.hr>
* Shridhar Daithankar <shridhar_daithankar@persistent.co.in> * 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 * Copyright (c) 2001-2006, PostgreSQL Global Development Group
* ALL RIGHTS RESERVED; * ALL RIGHTS RESERVED;
* *
@ -362,11 +362,11 @@ dblink_open(PG_FUNCTION_ARGS)
DBLINK_RES_INTERNALERROR("begin error"); DBLINK_RES_INTERNALERROR("begin error");
PQclear(res); PQclear(res);
rconn->newXactForCursor = TRUE; rconn->newXactForCursor = TRUE;
/* /*
* Since transaction state was IDLE, we force cursor count to * Since transaction state was IDLE, we force cursor count to
* initially be 0. This is needed as a previous ABORT might * initially be 0. This is needed as a previous ABORT might have wiped
* have wiped out our transaction without maintaining the * out our transaction without maintaining the cursor count for us.
* cursor count for us.
*/ */
rconn->openCursorCount = 0; rconn->openCursorCount = 0;
} }
@ -850,8 +850,8 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async, bool do_get)
TEXTOID, -1, 0); TEXTOID, -1, 0);
/* /*
* and save a copy of the command status string to return as our * and save a copy of the command status string to return as
* result tuple * our result tuple
*/ */
sql_cmd_status = PQcmdStatus(res); sql_cmd_status = PQcmdStatus(res);
funcctx->max_calls = 1; funcctx->max_calls = 1;
@ -891,7 +891,10 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async, bool do_get)
tupdesc = CreateTupleDescCopy(tupdesc); 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) if (PQnfields(res) != tupdesc->natts)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH), (errcode(ERRCODE_DATATYPE_MISMATCH),

View File

@ -11,7 +11,8 @@
#include "storage/bufpage.h" #include "storage/bufpage.h"
typedef struct { typedef struct
{
uint16 keylen; uint16 keylen;
uint16 vallen; uint16 vallen;
uint32 uint32
@ -20,7 +21,8 @@ typedef struct {
} HEntry; } HEntry;
typedef struct { typedef struct
{
int4 len; int4 len;
int4 size; int4 size;
char data[1]; char data[1];
@ -34,7 +36,8 @@ typedef struct {
#define PG_GETARG_HS(x) ((HStore*)PG_DETOAST_DATUM(PG_GETARG_DATUM(x))) #define PG_GETARG_HS(x) ((HStore*)PG_DETOAST_DATUM(PG_GETARG_DATUM(x)))
typedef struct { typedef struct
{
char *key; char *key;
char *val; char *val;
uint16 keylen; uint16 keylen;

View File

@ -36,7 +36,8 @@ typedef char *BITVECP;
#define HASHVAL(val) (((unsigned int)(val)) % SIGLENBIT) #define HASHVAL(val) (((unsigned int)(val)) % SIGLENBIT)
#define HASH(sign, val) SETBIT((sign), HASHVAL(val)) #define HASH(sign, val) SETBIT((sign), HASHVAL(val))
typedef struct { typedef struct
{
int4 len; int4 len;
int4 flag; int4 flag;
char data[1]; char data[1];
@ -74,13 +75,15 @@ Datum ghstore_out(PG_FUNCTION_ARGS);
Datum Datum
ghstore_in(PG_FUNCTION_ARGS) { ghstore_in(PG_FUNCTION_ARGS)
{
elog(ERROR, "Not implemented"); elog(ERROR, "Not implemented");
PG_RETURN_DATUM(0); PG_RETURN_DATUM(0);
} }
Datum Datum
ghstore_out(PG_FUNCTION_ARGS) { ghstore_out(PG_FUNCTION_ARGS)
{
elog(ERROR, "Not implemented"); elog(ERROR, "Not implemented");
PG_RETURN_DATUM(0); PG_RETURN_DATUM(0);
} }
@ -102,27 +105,32 @@ Datum ghstore_union(PG_FUNCTION_ARGS);
Datum ghstore_same(PG_FUNCTION_ARGS); Datum ghstore_same(PG_FUNCTION_ARGS);
Datum Datum
ghstore_compress(PG_FUNCTION_ARGS) { ghstore_compress(PG_FUNCTION_ARGS)
{
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
GISTENTRY *retval = entry; GISTENTRY *retval = entry;
if (entry->leafkey) { if (entry->leafkey)
GISTTYPE *res = (GISTTYPE*)palloc(CALCGTSIZE(0)); {
GISTTYPE *res = (GISTTYPE *) palloc(CALCGTSIZE(0));
HStore *toastedval = (HStore *) DatumGetPointer(entry->key); HStore *toastedval = (HStore *) DatumGetPointer(entry->key);
HStore *val = (HStore *) DatumGetPointer(PG_DETOAST_DATUM(entry->key)); HStore *val = (HStore *) DatumGetPointer(PG_DETOAST_DATUM(entry->key));
HEntry *ptr = ARRPTR(val); HEntry *ptr = ARRPTR(val);
char *words = STRPTR(val); char *words = STRPTR(val);
memset(res,0,CALCGTSIZE(0)); memset(res, 0, CALCGTSIZE(0));
res->len=CALCGTSIZE(0); res->len = CALCGTSIZE(0);
while(ptr-ARRPTR(val) < val->size) { while (ptr - ARRPTR(val) < val->size)
{
int h; int h;
h = crc32_sz((char*)(words+ptr->pos), ptr->keylen);
HASH( GETSIGN(res), h); h = crc32_sz((char *) (words + ptr->pos), ptr->keylen);
if ( !ptr->valisnull ) { HASH(GETSIGN(res), h);
h = crc32_sz((char *)(words+ptr->pos+ptr->keylen), ptr->vallen); if (!ptr->valisnull)
HASH( GETSIGN(res), h); {
h = crc32_sz((char *) (words + ptr->pos + ptr->keylen), ptr->vallen);
HASH(GETSIGN(res), h);
} }
ptr++; ptr++;
} }
@ -135,7 +143,9 @@ ghstore_compress(PG_FUNCTION_ARGS) {
entry->rel, entry->page, entry->rel, entry->page,
entry->offset, entry->offset,
FALSE); FALSE);
} else if ( !ISALLTRUE(DatumGetPointer(entry->key)) ) { }
else if (!ISALLTRUE(DatumGetPointer(entry->key)))
{
int4 i; int4 i;
GISTTYPE *res; GISTTYPE *res;
BITVECP sign = GETSIGN(DatumGetPointer(entry->key)); BITVECP sign = GETSIGN(DatumGetPointer(entry->key));
@ -160,12 +170,14 @@ ghstore_compress(PG_FUNCTION_ARGS) {
} }
Datum Datum
ghstore_decompress(PG_FUNCTION_ARGS) { ghstore_decompress(PG_FUNCTION_ARGS)
{
PG_RETURN_DATUM(PG_GETARG_DATUM(0)); PG_RETURN_DATUM(PG_GETARG_DATUM(0));
} }
Datum Datum
ghstore_same(PG_FUNCTION_ARGS) { ghstore_same(PG_FUNCTION_ARGS)
{
GISTTYPE *a = (GISTTYPE *) PG_GETARG_POINTER(0); GISTTYPE *a = (GISTTYPE *) PG_GETARG_POINTER(0);
GISTTYPE *b = (GISTTYPE *) PG_GETARG_POINTER(1); GISTTYPE *b = (GISTTYPE *) PG_GETARG_POINTER(1);
bool *result = (bool *) PG_GETARG_POINTER(2); bool *result = (bool *) PG_GETARG_POINTER(2);
@ -176,13 +188,16 @@ ghstore_same(PG_FUNCTION_ARGS) {
*result = false; *result = false;
else if (ISALLTRUE(b)) else if (ISALLTRUE(b))
*result = false; *result = false;
else { else
{
int4 i; int4 i;
BITVECP sa = GETSIGN(a), BITVECP sa = GETSIGN(a),
sb = GETSIGN(b); sb = GETSIGN(b);
*result = true; *result = true;
LOOPBYTE( LOOPBYTE(
if (sa[i] != sb[i]) { if (sa[i] != sb[i])
{
*result = false; *result = false;
break; break;
} }
@ -192,8 +207,11 @@ ghstore_same(PG_FUNCTION_ARGS) {
} }
static int4 static int4
sizebitvec(BITVECP sign) { sizebitvec(BITVECP sign)
int4 size = 0, i; {
int4 size = 0,
i;
LOOPBYTE( LOOPBYTE(
size += SUMBIT(sign); size += SUMBIT(sign);
sign = (BITVECP) (((char *) sign) + 1); sign = (BITVECP) (((char *) sign) + 1);
@ -202,27 +220,32 @@ sizebitvec(BITVECP sign) {
} }
static int static int
hemdistsign(BITVECP a, BITVECP b) { hemdistsign(BITVECP a, BITVECP b)
int i,dist=0; {
int i,
dist = 0;
LOOPBIT( LOOPBIT(
if ( GETBIT(a,i) != GETBIT(b,i) ) if (GETBIT(a, i) != GETBIT(b, i))
dist++; dist++;
); );
return dist; return dist;
} }
static int static int
hemdist(GISTTYPE *a, GISTTYPE *b) { hemdist(GISTTYPE * a, GISTTYPE * b)
if ( ISALLTRUE(a) ) { {
if (ISALLTRUE(a))
{
if (ISALLTRUE(b)) if (ISALLTRUE(b))
return 0; return 0;
else else
return SIGLENBIT-sizebitvec(GETSIGN(b)); return SIGLENBIT - sizebitvec(GETSIGN(b));
} else if (ISALLTRUE(b)) }
return SIGLENBIT-sizebitvec(GETSIGN(a)); else if (ISALLTRUE(b))
return SIGLENBIT - sizebitvec(GETSIGN(a));
return hemdistsign( GETSIGN(a), GETSIGN(b) ); return hemdistsign(GETSIGN(a), GETSIGN(b));
} }
static int4 static int4
@ -240,7 +263,8 @@ unionkey(BITVECP sbase, GISTTYPE * add)
} }
Datum Datum
ghstore_union(PG_FUNCTION_ARGS) { ghstore_union(PG_FUNCTION_ARGS)
{
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0); GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
int4 len = entryvec->n; int4 len = entryvec->n;
@ -251,8 +275,10 @@ ghstore_union(PG_FUNCTION_ARGS) {
GISTTYPE *result; GISTTYPE *result;
MemSet((void *) base, 0, sizeof(BITVEC)); MemSet((void *) base, 0, sizeof(BITVEC));
for (i = 0; i < len; i++) { for (i = 0; i < len; i++)
if (unionkey(base, GETENTRY(entryvec, i))) { {
if (unionkey(base, GETENTRY(entryvec, i)))
{
flag = ALLISTRUE; flag = ALLISTRUE;
break; break;
} }
@ -269,31 +295,35 @@ ghstore_union(PG_FUNCTION_ARGS) {
} }
Datum Datum
ghstore_penalty(PG_FUNCTION_ARGS) { ghstore_penalty(PG_FUNCTION_ARGS)
{
GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0); /* always ISSIGNKEY */ GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0); /* always ISSIGNKEY */
GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1); GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
float *penalty = (float *) PG_GETARG_POINTER(2); float *penalty = (float *) PG_GETARG_POINTER(2);
GISTTYPE *origval = (GISTTYPE *) DatumGetPointer(origentry->key); GISTTYPE *origval = (GISTTYPE *) DatumGetPointer(origentry->key);
GISTTYPE *newval = (GISTTYPE *) DatumGetPointer(newentry->key); GISTTYPE *newval = (GISTTYPE *) DatumGetPointer(newentry->key);
*penalty=hemdist(origval,newval); *penalty = hemdist(origval, newval);
PG_RETURN_POINTER(penalty); PG_RETURN_POINTER(penalty);
} }
typedef struct { typedef struct
{
OffsetNumber pos; OffsetNumber pos;
int4 cost; int4 cost;
} SPLITCOST; } SPLITCOST;
static int static int
comparecost(const void *a, const void *b) { comparecost(const void *a, const void *b)
{
return ((SPLITCOST *) a)->cost - ((SPLITCOST *) b)->cost; return ((SPLITCOST *) a)->cost - ((SPLITCOST *) b)->cost;
} }
Datum Datum
ghstore_picksplit(PG_FUNCTION_ARGS) { ghstore_picksplit(PG_FUNCTION_ARGS)
{
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0); GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
OffsetNumber maxoff = entryvec->n - 2; OffsetNumber maxoff = entryvec->n - 2;
@ -304,7 +334,8 @@ ghstore_picksplit(PG_FUNCTION_ARGS) {
*datum_r; *datum_r;
BITVECP union_l, BITVECP union_l,
union_r; union_r;
int4 size_alpha, size_beta; int4 size_alpha,
size_beta;
int4 size_waste, int4 size_waste,
waste = -1; waste = -1;
int4 nbytes; int4 nbytes;
@ -322,11 +353,14 @@ ghstore_picksplit(PG_FUNCTION_ARGS) {
v->spl_left = (OffsetNumber *) palloc(nbytes); v->spl_left = (OffsetNumber *) palloc(nbytes);
v->spl_right = (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); _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 ) { size_waste = hemdist(_k, GETENTRY(entryvec, j));
if (size_waste > waste)
{
waste = size_waste; waste = size_waste;
seed_1 = k; seed_1 = k;
seed_2 = j; seed_2 = j;
@ -346,26 +380,32 @@ ghstore_picksplit(PG_FUNCTION_ARGS) {
} }
/* form initial .. */ /* form initial .. */
if (ISALLTRUE(GETENTRY(entryvec, seed_1))) { if (ISALLTRUE(GETENTRY(entryvec, seed_1)))
{
datum_l = (GISTTYPE *) palloc(GTHDRSIZE); datum_l = (GISTTYPE *) palloc(GTHDRSIZE);
datum_l->len = GTHDRSIZE; datum_l->len = GTHDRSIZE;
datum_l->flag = ALLISTRUE; datum_l->flag = ALLISTRUE;
} else { }
else
{
datum_l = (GISTTYPE *) palloc(GTHDRSIZE + SIGLEN); datum_l = (GISTTYPE *) palloc(GTHDRSIZE + SIGLEN);
datum_l->len = GTHDRSIZE + SIGLEN; datum_l->len = GTHDRSIZE + SIGLEN;
datum_l->flag = 0; datum_l->flag = 0;
memcpy((void *) GETSIGN(datum_l), (void *) GETSIGN(GETENTRY(entryvec, seed_1)), sizeof(BITVEC)) 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 = (GISTTYPE *) palloc(GTHDRSIZE);
datum_r->len = GTHDRSIZE; datum_r->len = GTHDRSIZE;
datum_r->flag = ALLISTRUE; datum_r->flag = ALLISTRUE;
} else { }
else
{
datum_r = (GISTTYPE *) palloc(GTHDRSIZE + SIGLEN); datum_r = (GISTTYPE *) palloc(GTHDRSIZE + SIGLEN);
datum_r->len = GTHDRSIZE + SIGLEN; datum_r->len = GTHDRSIZE + SIGLEN;
datum_r->flag = 0; datum_r->flag = 0;
memcpy((void *) GETSIGN(datum_r), (void *) GETSIGN(GETENTRY(entryvec, seed_2)), sizeof(BITVEC)) ; memcpy((void *) GETSIGN(datum_r), (void *) GETSIGN(GETENTRY(entryvec, seed_2)), sizeof(BITVEC));
} }
maxoff = OffsetNumberNext(maxoff); maxoff = OffsetNumberNext(maxoff);
@ -375,48 +415,61 @@ ghstore_picksplit(PG_FUNCTION_ARGS) {
{ {
costvector[j - 1].pos = j; costvector[j - 1].pos = j;
_j = GETENTRY(entryvec, j); _j = GETENTRY(entryvec, j);
size_alpha = hemdist(datum_l,_j); size_alpha = hemdist(datum_l, _j);
size_beta = hemdist(datum_r,_j); size_beta = hemdist(datum_r, _j);
costvector[j - 1].cost = abs(size_alpha - size_beta); costvector[j - 1].cost = abs(size_alpha - size_beta);
} }
qsort((void *) costvector, maxoff, sizeof(SPLITCOST), comparecost); qsort((void *) costvector, maxoff, sizeof(SPLITCOST), comparecost);
union_l=GETSIGN(datum_l); union_l = GETSIGN(datum_l);
union_r=GETSIGN(datum_r); union_r = GETSIGN(datum_r);
for (k = 0; k < maxoff; k++) { for (k = 0; k < maxoff; k++)
{
j = costvector[k].pos; j = costvector[k].pos;
if (j == seed_1) { if (j == seed_1)
{
*left++ = j; *left++ = j;
v->spl_nleft++; v->spl_nleft++;
continue; continue;
} else if (j == seed_2) { }
else if (j == seed_2)
{
*right++ = j; *right++ = j;
v->spl_nright++; v->spl_nright++;
continue; continue;
} }
_j = GETENTRY(entryvec, j); _j = GETENTRY(entryvec, j);
size_alpha = hemdist(datum_l,_j); size_alpha = hemdist(datum_l, _j);
size_beta = hemdist(datum_r,_j); size_beta = hemdist(datum_r, _j);
if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.0001)) { 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) || ISALLTRUE(_j))
{
if (!ISALLTRUE(datum_l)) if (!ISALLTRUE(datum_l))
MemSet((void *) union_l, 0xff, sizeof(BITVEC)); MemSet((void *) union_l, 0xff, sizeof(BITVEC));
} else { }
ptr=GETSIGN(_j); else
{
ptr = GETSIGN(_j);
LOOPBYTE( LOOPBYTE(
union_l[i] |= ptr[i]; union_l[i] |= ptr[i];
); );
} }
*left++ = j; *left++ = j;
v->spl_nleft++; v->spl_nleft++;
} else { }
if (ISALLTRUE(datum_r) || ISALLTRUE(_j) ) { else
{
if (ISALLTRUE(datum_r) || ISALLTRUE(_j))
{
if (!ISALLTRUE(datum_r)) if (!ISALLTRUE(datum_r))
MemSet((void *) union_r, 0xff, sizeof(BITVEC)); MemSet((void *) union_r, 0xff, sizeof(BITVEC));
} else { }
ptr=GETSIGN(_j); else
{
ptr = GETSIGN(_j);
LOOPBYTE( LOOPBYTE(
union_r[i] |= ptr[i]; union_r[i] |= ptr[i];
); );
@ -437,35 +490,40 @@ ghstore_picksplit(PG_FUNCTION_ARGS) {
Datum 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); GISTTYPE *entry = (GISTTYPE *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
bool res=true; HStore *query = PG_GETARG_HS(1);
bool res = true;
HEntry *qe = ARRPTR(query); HEntry *qe = ARRPTR(query);
char *qv = STRPTR(query); char *qv = STRPTR(query);
BITVECP sign; BITVECP sign;
if ( ISALLTRUE(entry) ) { if (ISALLTRUE(entry))
PG_FREE_IF_COPY(query,1); {
PG_FREE_IF_COPY(query, 1);
PG_RETURN_BOOL(true); PG_RETURN_BOOL(true);
} }
sign=GETSIGN(entry); 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))) { int crc = crc32_sz((char *) (qv + qe->pos), qe->keylen);
if ( !qe->valisnull ) {
crc = crc32_sz((char *)(qv + qe->pos + qe->keylen), qe->vallen); if (GETBIT(sign, HASHVAL(crc)))
if ( !GETBIT(sign,HASHVAL(crc)) ) {
res=false; if (!qe->valisnull)
{
crc = crc32_sz((char *) (qv + qe->pos + qe->keylen), qe->vallen);
if (!GETBIT(sign, HASHVAL(crc)))
res = false;
} }
} else }
res=false; else
res = false;
qe++; qe++;
} }
PG_FREE_IF_COPY(query,1); PG_FREE_IF_COPY(query, 1);
PG_RETURN_BOOL(res); PG_RETURN_BOOL(res);
} }

View File

@ -3,7 +3,8 @@
PG_MODULE_MAGIC; PG_MODULE_MAGIC;
typedef struct { typedef struct
{
char *begin; char *begin;
char *ptr; char *ptr;
char *cur; char *cur;
@ -34,75 +35,115 @@ do { \
#define GV_WAITESCESCIN 4 #define GV_WAITESCESCIN 4
static bool static bool
get_val( HSParser *state, bool ignoreeq, bool *escaped ) { get_val(HSParser * state, bool ignoreeq, bool *escaped)
{
int st = GV_WAITVAL; int st = GV_WAITVAL;
state->wordlen=32;
state->cur = state->word = palloc( state->wordlen );
*escaped=false;
while(1) { state->wordlen = 32;
if ( st == GV_WAITVAL ) { state->cur = state->word = palloc(state->wordlen);
if ( *(state->ptr) == '"' ) { *escaped = false;
*escaped=true;
while (1)
{
if (st == GV_WAITVAL)
{
if (*(state->ptr) == '"')
{
*escaped = true;
st = GV_INESCVAL; st = GV_INESCVAL;
} else if ( *(state->ptr) == '\0' ) { }
else if (*(state->ptr) == '\0')
{
return false; return false;
} 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) == '=' && !ignoreeq)
} else if ( *(state->ptr) == '\\' ) { {
elog(ERROR, "Syntax error near '%c' at postion %d", *(state->ptr), (int4) (state->ptr - state->begin));
}
else if (*(state->ptr) == '\\')
{
st = GV_WAITESCIN; st = GV_WAITESCIN;
} else if ( !isspace((unsigned char) *(state->ptr)) ) { }
else if (!isspace((unsigned char) *(state->ptr)))
{
*(state->cur) = *(state->ptr); *(state->cur) = *(state->ptr);
state->cur++; state->cur++;
st = GV_INVAL; st = GV_INVAL;
} }
} else if ( st == GV_INVAL ) { }
if ( *(state->ptr) == '\\' ) { else if (st == GV_INVAL)
{
if (*(state->ptr) == '\\')
{
st = GV_WAITESCIN; st = GV_WAITESCIN;
} else if ( *(state->ptr) == '=' && !ignoreeq ) { }
else if (*(state->ptr) == '=' && !ignoreeq)
{
state->ptr--; state->ptr--;
return true; return true;
} else if ( *(state->ptr) == ',' && ignoreeq ) { }
else if (*(state->ptr) == ',' && ignoreeq)
{
state->ptr--; state->ptr--;
return true; return true;
} else if ( isspace((unsigned char) *(state->ptr)) ) { }
else if (isspace((unsigned char) *(state->ptr)))
{
return true; return true;
} else if ( *(state->ptr) == '\0' ) { }
else if (*(state->ptr) == '\0')
{
state->ptr--; state->ptr--;
return true; return true;
} else { }
else
{
RESIZEPRSBUF; RESIZEPRSBUF;
*(state->cur) = *(state->ptr); *(state->cur) = *(state->ptr);
state->cur++; state->cur++;
} }
} else if ( st == GV_INESCVAL ) { }
if ( *(state->ptr) == '\\' ) { else if (st == GV_INESCVAL)
{
if (*(state->ptr) == '\\')
{
st = GV_WAITESCESCIN; st = GV_WAITESCESCIN;
} else if ( *(state->ptr) == '"' ) { }
else if (*(state->ptr) == '"')
{
return true; return true;
} else if ( *(state->ptr) == '\0' ) { }
elog(ERROR,"Unexpected end of string"); else if (*(state->ptr) == '\0')
} else { {
elog(ERROR, "Unexpected end of string");
}
else
{
RESIZEPRSBUF; RESIZEPRSBUF;
*(state->cur) = *(state->ptr); *(state->cur) = *(state->ptr);
state->cur++; state->cur++;
} }
} else if ( st == GV_WAITESCIN ) { }
if ( *(state->ptr) == '\0' ) else if (st == GV_WAITESCIN)
elog(ERROR,"Unexpected end of string"); {
if (*(state->ptr) == '\0')
elog(ERROR, "Unexpected end of string");
RESIZEPRSBUF; RESIZEPRSBUF;
*(state->cur) = *(state->ptr); *(state->cur) = *(state->ptr);
state->cur++; state->cur++;
st = GV_INVAL; st = GV_INVAL;
} else if ( st == GV_WAITESCESCIN ) { }
if ( *(state->ptr) == '\0' ) else if (st == GV_WAITESCESCIN)
elog(ERROR,"Unexpected end of string"); {
if (*(state->ptr) == '\0')
elog(ERROR, "Unexpected end of string");
RESIZEPRSBUF; RESIZEPRSBUF;
*(state->cur) = *(state->ptr); *(state->cur) = *(state->ptr);
state->cur++; state->cur++;
st = GV_INESCVAL; st = GV_INESCVAL;
} else }
elog(ERROR,"Unknown state %d at postion line %d in file '%s'", st, __LINE__, __FILE__); else
elog(ERROR, "Unknown state %d at postion line %d in file '%s'", st, __LINE__, __FILE__);
state->ptr++; state->ptr++;
} }
@ -118,149 +159,197 @@ get_val( HSParser *state, bool ignoreeq, bool *escaped ) {
static void static void
parse_hstore( HSParser *state ) { parse_hstore(HSParser * state)
{
int st = WKEY; int st = WKEY;
bool escaped=false; bool escaped = false;
state->plen=16; state->plen = 16;
state->pairs = (Pairs*)palloc( sizeof(Pairs) * state->plen ); state->pairs = (Pairs *) palloc(sizeof(Pairs) * state->plen);
state->pcur=0; state->pcur = 0;
state->ptr = state->begin; state->ptr = state->begin;
state->word=NULL; state->word = NULL;
while(1) { while (1)
if (st == WKEY) { {
if ( !get_val(state, false, &escaped) ) if (st == WKEY)
{
if (!get_val(state, false, &escaped))
return; return;
if ( state->pcur >= state->plen ) { if (state->pcur >= state->plen)
{
state->plen *= 2; state->plen *= 2;
state->pairs = (Pairs*)repalloc( state->pairs, sizeof(Pairs) * state->plen ); state->pairs = (Pairs *) repalloc(state->pairs, sizeof(Pairs) * state->plen);
} }
state->pairs[ state->pcur ].key = state->word; state->pairs[state->pcur].key = state->word;
state->pairs[ state->pcur ].keylen = state->cur - state->word; state->pairs[state->pcur].keylen = state->cur - state->word;
state->pairs[ state->pcur ].val=NULL; state->pairs[state->pcur].val = NULL;
state->word=NULL; state->word = NULL;
st = WEQ; st = WEQ;
} else if ( st == WEQ ) { }
if ( *(state->ptr) == '=' ) { else if (st == WEQ)
{
if (*(state->ptr) == '=')
{
st = WGT; st = WGT;
} else if ( *(state->ptr) == '\0' ) {
elog(ERROR,"Unexpectd end of string");
} 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 ) { else if (*(state->ptr) == '\0')
if ( *(state->ptr) == '>' ) { {
elog(ERROR, "Unexpectd end of string");
}
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) == '>')
{
st = WVAL; st = WVAL;
} else if ( *(state->ptr) == '\0' ) {
elog(ERROR,"Unexpectd end of string");
} else {
elog(ERROR,"Syntax error near '%c' at postion %d", *(state->ptr), (int4)(state->ptr-state->begin));
} }
} else if ( st == WVAL ) { else if (*(state->ptr) == '\0')
if ( !get_val(state, true, &escaped) ) {
elog(ERROR,"Unexpected end of string"); elog(ERROR, "Unexpectd end of string");
state->pairs[ state->pcur ].val = state->word; }
state->pairs[ state->pcur ].vallen = state->cur - state->word; else
state->pairs[ state->pcur ].isnull = false; {
state->pairs[ state->pcur ].needfree = true; elog(ERROR, "Syntax error near '%c' at postion %d", *(state->ptr), (int4) (state->ptr - state->begin));
if ( state->cur - state->word == 4 && !escaped) { }
}
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)
{
state->word[4] = '\0'; state->word[4] = '\0';
if ( 0==pg_strcasecmp(state->word, "null") ) if (0 == pg_strcasecmp(state->word, "null"))
state->pairs[ state->pcur ].isnull=true; state->pairs[state->pcur].isnull = true;
} }
state->word=NULL; state->word = NULL;
state->pcur++; state->pcur++;
st = WDEL; st = WDEL;
} else if ( st == WDEL ) {
if ( *(state->ptr) == ',' ) {
st = WKEY;
} else if ( *(state->ptr) == '\0' ) {
return;
} 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 if (st == WDEL)
elog(ERROR,"Unknown state %d at line %d in file '%s'", st, __LINE__, __FILE__); {
if (*(state->ptr) == ',')
{
st = WKEY;
}
else if (*(state->ptr) == '\0')
{
return;
}
else if (!isspace((unsigned char) *(state->ptr)))
{
elog(ERROR, "Syntax error near '%c' at postion %d", *(state->ptr), (int4) (state->ptr - state->begin));
}
}
else
elog(ERROR, "Unknown state %d at line %d in file '%s'", st, __LINE__, __FILE__);
state->ptr++; state->ptr++;
} }
} }
int int
comparePairs(const void *a, const void *b) { comparePairs(const void *a, const void *b)
if ( ((Pairs*)a)->keylen == ((Pairs*)b)->keylen ) { {
if (((Pairs *) a)->keylen == ((Pairs *) b)->keylen)
{
int res = strncmp( int res = strncmp(
((Pairs*)a)->key, ((Pairs *) a)->key,
((Pairs*)b)->key, ((Pairs *) b)->key,
((Pairs*)a)->keylen ((Pairs *) a)->keylen
); );
if ( res )
if (res)
return res; return res;
/* guarantee that neddfree willl be later */ /* guarantee that neddfree willl be later */
if ( ((Pairs*)b)->needfree == ((Pairs*)a)->needfree ) if (((Pairs *) b)->needfree == ((Pairs *) a)->needfree)
return 0; return 0;
else if ( ((Pairs*)a)->needfree ) else if (((Pairs *) a)->needfree)
return 1; return 1;
else else
return -1; return -1;
} }
return ( ((Pairs*)a)->keylen > ((Pairs*)b)->keylen ) ? 1 : -1; return (((Pairs *) a)->keylen > ((Pairs *) b)->keylen) ? 1 : -1;
} }
int int
uniquePairs(Pairs * a, int4 l, int4 *buflen) { uniquePairs(Pairs * a, int4 l, int4 *buflen)
Pairs *ptr, *res; {
Pairs *ptr,
*res;
*buflen=0; *buflen = 0;
if ( l < 2 ) { if (l < 2)
if ( l==1 ) {
*buflen = a->keylen + ((a->isnull) ? 0 : a->vallen) ; if (l == 1)
*buflen = a->keylen + ((a->isnull) ? 0 : a->vallen);
return l; return l;
} }
qsort((void *) a, l, sizeof(Pairs), comparePairs); qsort((void *) a, l, sizeof(Pairs), comparePairs);
ptr=a+1; ptr = a + 1;
res=a; res = a;
while( ptr - a < l ) { while (ptr - a < l)
if ( ptr->keylen == res->keylen && strncmp( ptr->key, res->key, res->keylen )==0 ) { {
if ( ptr->needfree ) { if (ptr->keylen == res->keylen && strncmp(ptr->key, res->key, res->keylen) == 0)
{
if (ptr->needfree)
{
pfree(ptr->key); pfree(ptr->key);
pfree(ptr->val); pfree(ptr->val);
} }
} else { }
*buflen += res->keylen + (( res->isnull ) ? 0 : res->vallen); else
{
*buflen += res->keylen + ((res->isnull) ? 0 : res->vallen);
res++; res++;
memcpy(res,ptr,sizeof(Pairs)); memcpy(res, ptr, sizeof(Pairs));
} }
ptr++; ptr++;
} }
*buflen += res->keylen + (( res->isnull ) ? 0 : res->vallen); *buflen += res->keylen + ((res->isnull) ? 0 : res->vallen);
return res + 1 - a; return res + 1 - a;
} }
static void static void
freeHSParse(HSParser *state) { freeHSParse(HSParser * state)
{
int i; int i;
if ( state->word ) pfree( state->word ); if (state->word)
for (i=0;i<state->pcur;i++) pfree(state->word);
if ( state->pairs[i].needfree ) { for (i = 0; i < state->pcur; i++)
if (state->pairs[i].key) pfree(state->pairs[i].key); if (state->pairs[i].needfree)
if (state->pairs[i].val) pfree(state->pairs[i].val); {
if (state->pairs[i].key)
pfree(state->pairs[i].key);
if (state->pairs[i].val)
pfree(state->pairs[i].val);
} }
pfree( state->pairs ); pfree(state->pairs);
} }
PG_FUNCTION_INFO_V1(hstore_in); PG_FUNCTION_INFO_V1(hstore_in);
Datum hstore_in(PG_FUNCTION_ARGS); Datum hstore_in(PG_FUNCTION_ARGS);
Datum Datum
hstore_in(PG_FUNCTION_ARGS) { hstore_in(PG_FUNCTION_ARGS)
{
HSParser state; HSParser state;
int4 len,buflen,i; int4 len,
buflen,
i;
HStore *out; HStore *out;
HEntry *entries; HEntry *entries;
char *ptr; char *ptr;
@ -269,38 +358,41 @@ hstore_in(PG_FUNCTION_ARGS) {
parse_hstore(&state); parse_hstore(&state);
if ( state.pcur == 0 ) { if (state.pcur == 0)
{
freeHSParse(&state); freeHSParse(&state);
len = CALCDATASIZE(0,0); len = CALCDATASIZE(0, 0);
out = palloc(len); out = palloc(len);
out->len=len; out->len = len;
out->size=0; out->size = 0;
PG_RETURN_POINTER(out); PG_RETURN_POINTER(out);
} }
state.pcur = uniquePairs(state.pairs, state.pcur, &buflen); state.pcur = uniquePairs(state.pairs, state.pcur, &buflen);
len=CALCDATASIZE(state.pcur, buflen); len = CALCDATASIZE(state.pcur, buflen);
out = palloc(len); out = palloc(len);
out->len=len; out->len = len;
out->size=state.pcur; out->size = state.pcur;
entries=ARRPTR(out); entries = ARRPTR(out);
ptr = STRPTR(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].keylen = state.pairs[i].keylen;
entries[i].pos = ptr - STRPTR(out); entries[i].pos = ptr - STRPTR(out);
memcpy(ptr, state.pairs[i].key, state.pairs[i].keylen); memcpy(ptr, state.pairs[i].key, state.pairs[i].keylen);
ptr+=entries[i].keylen; ptr += entries[i].keylen;
entries[i].valisnull = state.pairs[i].isnull; entries[i].valisnull = state.pairs[i].isnull;
if ( entries[i].valisnull ) if (entries[i].valisnull)
entries[i].vallen=4; /* null */ entries[i].vallen = 4; /* null */
else { else
{
entries[i].vallen = state.pairs[i].vallen; entries[i].vallen = state.pairs[i].vallen;
memcpy(ptr, state.pairs[i].val,state.pairs[i].vallen); memcpy(ptr, state.pairs[i].val, state.pairs[i].vallen);
ptr+=entries[i].vallen; ptr += entries[i].vallen;
} }
} }
@ -308,13 +400,15 @@ hstore_in(PG_FUNCTION_ARGS) {
PG_RETURN_POINTER(out); PG_RETURN_POINTER(out);
} }
static char* static char *
cpw(char *dst, char *src, int len) { cpw(char *dst, char *src, int len)
{
char *ptr = src; char *ptr = src;
while(ptr-src<len) { while (ptr - src < len)
if ( *ptr == '"' || *ptr == '\\' ) {
*dst++='\\'; if (*ptr == '"' || *ptr == '\\')
*dst++ = '\\';
*dst++ = *ptr++; *dst++ = *ptr++;
} }
return dst; return dst;
@ -323,48 +417,57 @@ cpw(char *dst, char *src, int len) {
PG_FUNCTION_INFO_V1(hstore_out); PG_FUNCTION_INFO_V1(hstore_out);
Datum hstore_out(PG_FUNCTION_ARGS); Datum hstore_out(PG_FUNCTION_ARGS);
Datum Datum
hstore_out(PG_FUNCTION_ARGS) { hstore_out(PG_FUNCTION_ARGS)
{
HStore *in = PG_GETARG_HS(0); HStore *in = PG_GETARG_HS(0);
int buflen,i; int buflen,
char *out,*ptr; i;
char *out,
*ptr;
char *base = STRPTR(in); char *base = STRPTR(in);
HEntry *entries = ARRPTR(in); HEntry *entries = ARRPTR(in);
if ( in->size==0 ) { if (in->size == 0)
out=palloc(1); {
*out='\0'; out = palloc(1);
PG_FREE_IF_COPY(in,0); *out = '\0';
PG_FREE_IF_COPY(in, 0);
PG_RETURN_CSTRING(out); PG_RETURN_CSTRING(out);
} }
buflen = ( 4 /* " */ + 2 /* => */ + 2 /*, */ )*in->size + buflen = (4 /* " */ + 2 /* => */ + 2 /* , */ ) * in->size +
2 /* esc */ * ( in->len - CALCDATASIZE(in->size,0) ); 2 /* esc */ * (in->len - CALCDATASIZE(in->size, 0));
out=ptr=palloc(buflen); 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 = cpw(ptr, base + entries[i].pos, entries[i].keylen);
*ptr++='='; *ptr++ = '"';
*ptr++='>'; *ptr++ = '=';
if ( entries[i].valisnull ) { *ptr++ = '>';
*ptr++='N'; if (entries[i].valisnull)
*ptr++='U'; {
*ptr++='L'; *ptr++ = 'N';
*ptr++='L'; *ptr++ = 'U';
} else { *ptr++ = 'L';
*ptr++='"'; *ptr++ = 'L';
ptr = cpw( ptr, base + entries[i].pos + entries[i].keylen, entries[i].vallen ); }
*ptr++='"'; 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++=' '; *ptr++ = ',';
*ptr++ = ' ';
} }
} }
*ptr='\0'; *ptr = '\0';
PG_FREE_IF_COPY(in,0); PG_FREE_IF_COPY(in, 0);
PG_RETURN_CSTRING(out); PG_RETURN_CSTRING(out);
} }

View File

@ -7,20 +7,22 @@
static HEntry * static HEntry *
findkey(HStore *hs, char *key, int keylen) { findkey(HStore * hs, char *key, int keylen)
{
HEntry *StopLow = ARRPTR(hs); HEntry *StopLow = ARRPTR(hs);
HEntry *StopHigh = StopLow + hs->size; HEntry *StopHigh = StopLow + hs->size;
HEntry *StopMiddle; HEntry *StopMiddle;
int difference; int difference;
char *base = STRPTR(hs); char *base = STRPTR(hs);
while (StopLow < StopHigh) { while (StopLow < StopHigh)
{
StopMiddle = StopLow + (StopHigh - StopLow) / 2; StopMiddle = StopLow + (StopHigh - StopLow) / 2;
if ( StopMiddle->keylen == keylen ) if (StopMiddle->keylen == keylen)
difference=strncmp(base+StopMiddle->pos, key, StopMiddle->keylen); difference = strncmp(base + StopMiddle->pos, key, StopMiddle->keylen);
else else
difference=(StopMiddle->keylen > keylen) ? 1 : -1; difference = (StopMiddle->keylen > keylen) ? 1 : -1;
if (difference == 0) if (difference == 0)
return StopMiddle; return StopMiddle;
@ -36,39 +38,42 @@ findkey(HStore *hs, char *key, int keylen) {
PG_FUNCTION_INFO_V1(fetchval); PG_FUNCTION_INFO_V1(fetchval);
Datum fetchval(PG_FUNCTION_ARGS); Datum fetchval(PG_FUNCTION_ARGS);
Datum Datum
fetchval(PG_FUNCTION_ARGS) { fetchval(PG_FUNCTION_ARGS)
{
HStore *hs = PG_GETARG_HS(0); HStore *hs = PG_GETARG_HS(0);
text *key = PG_GETARG_TEXT_P(1); text *key = PG_GETARG_TEXT_P(1);
HEntry *entry; HEntry *entry;
text *out; 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_FREE_IF_COPY(hs, 0);
PG_FREE_IF_COPY(key, 1);
PG_RETURN_NULL(); PG_RETURN_NULL();
} }
out=palloc(VARHDRSZ+entry->vallen); out = palloc(VARHDRSZ + entry->vallen);
memcpy(VARDATA(out),STRPTR(hs) + entry->pos + entry->keylen, entry->vallen); memcpy(VARDATA(out), STRPTR(hs) + entry->pos + entry->keylen, entry->vallen);
VARATT_SIZEP(out) = VARHDRSZ+entry->vallen; VARATT_SIZEP(out) = VARHDRSZ + entry->vallen;
PG_FREE_IF_COPY(hs,0); PG_FREE_IF_COPY(hs, 0);
PG_FREE_IF_COPY(key,1); PG_FREE_IF_COPY(key, 1);
PG_RETURN_POINTER(out); PG_RETURN_POINTER(out);
} }
PG_FUNCTION_INFO_V1(exists); PG_FUNCTION_INFO_V1(exists);
Datum exists(PG_FUNCTION_ARGS); Datum exists(PG_FUNCTION_ARGS);
Datum Datum
exists(PG_FUNCTION_ARGS) { exists(PG_FUNCTION_ARGS)
{
HStore *hs = PG_GETARG_HS(0); HStore *hs = PG_GETARG_HS(0);
text *key = PG_GETARG_TEXT_P(1); text *key = PG_GETARG_TEXT_P(1);
HEntry *entry; HEntry *entry;
entry=findkey(hs,VARDATA(key), VARSIZE(key)-VARHDRSZ); entry = findkey(hs, VARDATA(key), VARSIZE(key) - VARHDRSZ);
PG_FREE_IF_COPY(hs,0); PG_FREE_IF_COPY(hs, 0);
PG_FREE_IF_COPY(key,1); PG_FREE_IF_COPY(key, 1);
PG_RETURN_BOOL(entry); PG_RETURN_BOOL(entry);
} }
@ -76,18 +81,19 @@ exists(PG_FUNCTION_ARGS) {
PG_FUNCTION_INFO_V1(defined); PG_FUNCTION_INFO_V1(defined);
Datum defined(PG_FUNCTION_ARGS); Datum defined(PG_FUNCTION_ARGS);
Datum Datum
defined(PG_FUNCTION_ARGS) { defined(PG_FUNCTION_ARGS)
{
HStore *hs = PG_GETARG_HS(0); HStore *hs = PG_GETARG_HS(0);
text *key = PG_GETARG_TEXT_P(1); text *key = PG_GETARG_TEXT_P(1);
HEntry *entry; HEntry *entry;
bool res; bool res;
entry=findkey(hs,VARDATA(key), VARSIZE(key)-VARHDRSZ); entry = findkey(hs, VARDATA(key), VARSIZE(key) - VARHDRSZ);
res = ( entry && !entry->valisnull ) ? true : false; res = (entry && !entry->valisnull) ? true : false;
PG_FREE_IF_COPY(hs,0); PG_FREE_IF_COPY(hs, 0);
PG_FREE_IF_COPY(key,1); PG_FREE_IF_COPY(key, 1);
PG_RETURN_BOOL(res); PG_RETURN_BOOL(res);
} }
@ -95,46 +101,53 @@ defined(PG_FUNCTION_ARGS) {
PG_FUNCTION_INFO_V1(delete); PG_FUNCTION_INFO_V1(delete);
Datum delete(PG_FUNCTION_ARGS); Datum delete(PG_FUNCTION_ARGS);
Datum Datum
delete(PG_FUNCTION_ARGS) { delete(PG_FUNCTION_ARGS)
{
HStore *hs = PG_GETARG_HS(0); HStore *hs = PG_GETARG_HS(0);
text *key = PG_GETARG_TEXT_P(1); text *key = PG_GETARG_TEXT_P(1);
HStore *out = palloc(hs->len); HStore *out = palloc(hs->len);
char *ptrs, *ptrd; char *ptrs,
HEntry *es, *ed; *ptrd;
HEntry *es,
*ed;
out->len=hs->len; out->len = hs->len;
out->size=hs->size; /* temprorary! */ out->size = hs->size; /* temprorary! */
ptrs=STRPTR(hs); ptrs = STRPTR(hs);
es =ARRPTR(hs); es = ARRPTR(hs);
ptrd=STRPTR(out); ptrd = STRPTR(out);
ed =ARRPTR(out); ed = ARRPTR(out);
while( es - ARRPTR(hs) < hs->size ) { while (es - ARRPTR(hs) < hs->size)
if ( !(es->keylen == VARSIZE(key) - VARHDRSZ && strncmp(ptrs, VARDATA(key), es->keylen)==0) ) { {
memcpy( ed, es, sizeof(HEntry) ); if (!(es->keylen == VARSIZE(key) - VARHDRSZ && strncmp(ptrs, VARDATA(key), es->keylen) == 0))
memcpy( ptrd, ptrs, es->keylen + ( (es->valisnull) ? 0 : es->vallen ) ); {
memcpy(ed, es, sizeof(HEntry));
memcpy(ptrd, ptrs, es->keylen + ((es->valisnull) ? 0 : es->vallen));
ed->pos = ptrd - STRPTR(out); ed->pos = ptrd - STRPTR(out);
ptrd += es->keylen + ( (es->valisnull) ? 0 : es->vallen ); ptrd += es->keylen + ((es->valisnull) ? 0 : es->vallen);
ed++; ed++;
} }
ptrs += es->keylen + ( (es->valisnull) ? 0 : es->vallen ); ptrs += es->keylen + ((es->valisnull) ? 0 : es->vallen);
es++; es++;
} }
if ( ed - ARRPTR(out) != out->size ) { if (ed - ARRPTR(out) != out->size)
int buflen=ptrd-STRPTR(out); {
int buflen = ptrd - STRPTR(out);
ptrd = STRPTR(out); ptrd = STRPTR(out);
out->size = ed - ARRPTR(out); out->size = ed - ARRPTR(out);
memmove( STRPTR(out), ptrd, buflen); memmove(STRPTR(out), ptrd, buflen);
out->len = CALCDATASIZE(out->size, buflen); out->len = CALCDATASIZE(out->size, buflen);
} }
PG_FREE_IF_COPY(hs,0); PG_FREE_IF_COPY(hs, 0);
PG_FREE_IF_COPY(key,1); PG_FREE_IF_COPY(key, 1);
PG_RETURN_POINTER(out); PG_RETURN_POINTER(out);
} }
@ -142,96 +155,112 @@ delete(PG_FUNCTION_ARGS) {
PG_FUNCTION_INFO_V1(hs_concat); PG_FUNCTION_INFO_V1(hs_concat);
Datum hs_concat(PG_FUNCTION_ARGS); Datum hs_concat(PG_FUNCTION_ARGS);
Datum Datum
hs_concat(PG_FUNCTION_ARGS) { hs_concat(PG_FUNCTION_ARGS)
{
HStore *s1 = PG_GETARG_HS(0); HStore *s1 = PG_GETARG_HS(0);
HStore *s2 = PG_GETARG_HS(1); HStore *s2 = PG_GETARG_HS(1);
HStore *out = palloc( s1->len + s2->len ); HStore *out = palloc(s1->len + s2->len);
char *ps1, *ps2, *pd; char *ps1,
HEntry *es1, *es2, *ed; *ps2,
*pd;
HEntry *es1,
*es2,
*ed;
out->len = s1->len + s2->len; out->len = s1->len + s2->len;
out->size = s1->size + s2->size; out->size = s1->size + s2->size;
ps1=STRPTR(s1); ps1 = STRPTR(s1);
ps2=STRPTR(s2); ps2 = STRPTR(s2);
pd=STRPTR(out); pd = STRPTR(out);
es1=ARRPTR(s1); es1 = ARRPTR(s1);
es2=ARRPTR(s2); es2 = ARRPTR(s2);
ed=ARRPTR(out); 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; int difference;
if ( es1->keylen == es2->keylen )
difference=strncmp(ps1, ps2, es1->keylen); if (es1->keylen == es2->keylen)
difference = strncmp(ps1, ps2, es1->keylen);
else else
difference=(es1->keylen > es2->keylen) ? 1 : -1; 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 ) ); memcpy(ed, es2, sizeof(HEntry));
memcpy(pd, ps2, es2->keylen + ((es2->valisnull) ? 0 : es2->vallen));
ed->pos = pd - STRPTR(out); ed->pos = pd - STRPTR(out);
pd += es2->keylen + ( (es2->valisnull) ? 0 : es2->vallen ); pd += es2->keylen + ((es2->valisnull) ? 0 : es2->vallen);
ed++; ed++;
ps1 += es1->keylen + ( (es1->valisnull) ? 0 : es1->vallen ); ps1 += es1->keylen + ((es1->valisnull) ? 0 : es1->vallen);
es1++; es1++;
ps2 += es2->keylen + ( (es2->valisnull) ? 0 : es2->vallen ); ps2 += es2->keylen + ((es2->valisnull) ? 0 : es2->vallen);
es2++; es2++;
} else if ( difference > 0 ) { }
memcpy( ed, es2, sizeof(HEntry) ); else if (difference > 0)
memcpy( pd, ps2, es2->keylen + ( (es2->valisnull) ? 0 : es2->vallen ) ); {
memcpy(ed, es2, sizeof(HEntry));
memcpy(pd, ps2, es2->keylen + ((es2->valisnull) ? 0 : es2->vallen));
ed->pos = pd - STRPTR(out); ed->pos = pd - STRPTR(out);
pd += es2->keylen + ( (es2->valisnull) ? 0 : es2->vallen ); pd += es2->keylen + ((es2->valisnull) ? 0 : es2->vallen);
ed++; ed++;
ps2 += es2->keylen + ( (es2->valisnull) ? 0 : es2->vallen ); ps2 += es2->keylen + ((es2->valisnull) ? 0 : es2->vallen);
es2++; es2++;
} else { }
memcpy( ed, es1, sizeof(HEntry) ); else
memcpy( pd, ps1, es1->keylen + ( (es1->valisnull) ? 0 : es1->vallen ) ); {
memcpy(ed, es1, sizeof(HEntry));
memcpy(pd, ps1, es1->keylen + ((es1->valisnull) ? 0 : es1->vallen));
ed->pos = pd - STRPTR(out); ed->pos = pd - STRPTR(out);
pd += es1->keylen + ( (es1->valisnull) ? 0 : es1->vallen ); pd += es1->keylen + ((es1->valisnull) ? 0 : es1->vallen);
ed++; ed++;
ps1 += es1->keylen + ( (es1->valisnull) ? 0 : es1->vallen ); ps1 += es1->keylen + ((es1->valisnull) ? 0 : es1->vallen);
es1++; es1++;
} }
} }
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 ) ); memcpy(ed, es1, sizeof(HEntry));
memcpy(pd, ps1, es1->keylen + ((es1->valisnull) ? 0 : es1->vallen));
ed->pos = pd - STRPTR(out); ed->pos = pd - STRPTR(out);
pd += es1->keylen + ( (es1->valisnull) ? 0 : es1->vallen ); pd += es1->keylen + ((es1->valisnull) ? 0 : es1->vallen);
ed++; ed++;
ps1 += es1->keylen + ( (es1->valisnull) ? 0 : es1->vallen ); ps1 += es1->keylen + ((es1->valisnull) ? 0 : es1->vallen);
es1++; 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 ) ); memcpy(ed, es2, sizeof(HEntry));
memcpy(pd, ps2, es2->keylen + ((es2->valisnull) ? 0 : es2->vallen));
ed->pos = pd - STRPTR(out); ed->pos = pd - STRPTR(out);
pd += es2->keylen + ( (es2->valisnull) ? 0 : es2->vallen ); pd += es2->keylen + ((es2->valisnull) ? 0 : es2->vallen);
ed++; ed++;
ps2 += es2->keylen + ( (es2->valisnull) ? 0 : es2->vallen ); ps2 += es2->keylen + ((es2->valisnull) ? 0 : es2->vallen);
es2++; es2++;
} }
if ( ed - ARRPTR(out) != out->size ) { if (ed - ARRPTR(out) != out->size)
int buflen=pd-STRPTR(out); {
int buflen = pd - STRPTR(out);
pd = STRPTR(out); pd = STRPTR(out);
out->size = ed - ARRPTR(out); out->size = ed - ARRPTR(out);
memmove( STRPTR(out), pd, buflen); memmove(STRPTR(out), pd, buflen);
out->len = CALCDATASIZE(out->size, buflen); out->len = CALCDATASIZE(out->size, buflen);
} }
PG_FREE_IF_COPY(s1,0); PG_FREE_IF_COPY(s1, 0);
PG_FREE_IF_COPY(s2,1); PG_FREE_IF_COPY(s2, 1);
PG_RETURN_POINTER(out); PG_RETURN_POINTER(out);
} }
@ -239,27 +268,28 @@ hs_concat(PG_FUNCTION_ARGS) {
PG_FUNCTION_INFO_V1(tconvert); PG_FUNCTION_INFO_V1(tconvert);
Datum tconvert(PG_FUNCTION_ARGS); Datum tconvert(PG_FUNCTION_ARGS);
Datum Datum
tconvert(PG_FUNCTION_ARGS) { tconvert(PG_FUNCTION_ARGS)
{
text *key = PG_GETARG_TEXT_P(0); text *key = PG_GETARG_TEXT_P(0);
text *val = PG_GETARG_TEXT_P(1); text *val = PG_GETARG_TEXT_P(1);
int len; int len;
HStore *out; HStore *out;
len=CALCDATASIZE(1, VARSIZE(key) + VARSIZE(val) - 2*VARHDRSZ); len = CALCDATASIZE(1, VARSIZE(key) + VARSIZE(val) - 2 * VARHDRSZ);
out = palloc(len); out = palloc(len);
out->len=len; out->len = len;
out->size=1; out->size = 1;
ARRPTR(out)->keylen = VARSIZE(key) - VARHDRSZ; ARRPTR(out)->keylen = VARSIZE(key) - VARHDRSZ;
ARRPTR(out)->vallen = VARSIZE(val) - VARHDRSZ; ARRPTR(out)->vallen = VARSIZE(val) - VARHDRSZ;
ARRPTR(out)->valisnull = false; ARRPTR(out)->valisnull = false;
ARRPTR(out)->pos=0; ARRPTR(out)->pos = 0;
memcpy( STRPTR(out), VARDATA(key), ARRPTR(out)->keylen ); memcpy(STRPTR(out), VARDATA(key), ARRPTR(out)->keylen);
memcpy( STRPTR(out) + ARRPTR(out)->keylen, VARDATA(val), ARRPTR(out)->vallen ); memcpy(STRPTR(out) + ARRPTR(out)->keylen, VARDATA(val), ARRPTR(out)->vallen);
PG_FREE_IF_COPY(key,0); PG_FREE_IF_COPY(key, 0);
PG_FREE_IF_COPY(val,1); PG_FREE_IF_COPY(val, 1);
PG_RETURN_POINTER(out); PG_RETURN_POINTER(out);
} }
@ -267,19 +297,22 @@ tconvert(PG_FUNCTION_ARGS) {
PG_FUNCTION_INFO_V1(akeys); PG_FUNCTION_INFO_V1(akeys);
Datum akeys(PG_FUNCTION_ARGS); Datum akeys(PG_FUNCTION_ARGS);
Datum Datum
akeys(PG_FUNCTION_ARGS) { akeys(PG_FUNCTION_ARGS)
{
HStore *hs = PG_GETARG_HS(0); HStore *hs = PG_GETARG_HS(0);
Datum *d; Datum *d;
ArrayType *a; ArrayType *a;
HEntry *ptr=ARRPTR(hs); HEntry *ptr = ARRPTR(hs);
char *base=STRPTR(hs); char *base = STRPTR(hs);
d=(Datum*)palloc(sizeof(Datum)*(hs->size+1)); 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; text *item = (text *) palloc(VARHDRSZ + ptr->keylen);
VARATT_SIZEP(item) = VARHDRSZ + ptr->keylen;
memcpy(VARDATA(item), base + ptr->pos, ptr->keylen); memcpy(VARDATA(item), base + ptr->pos, ptr->keylen);
d[ ptr-ARRPTR(hs) ] = PointerGetDatum(item); d[ptr - ARRPTR(hs)] = PointerGetDatum(item);
ptr++; ptr++;
} }
@ -292,14 +325,15 @@ akeys(PG_FUNCTION_ARGS) {
'i' 'i'
); );
ptr=ARRPTR(hs); ptr = ARRPTR(hs);
while( ptr-ARRPTR(hs) < hs->size ) { while (ptr - ARRPTR(hs) < hs->size)
pfree(DatumGetPointer(d[ ptr-ARRPTR(hs) ])); {
pfree(DatumGetPointer(d[ptr - ARRPTR(hs)]));
ptr++; ptr++;
} }
pfree(d); pfree(d);
PG_FREE_IF_COPY(hs,0); PG_FREE_IF_COPY(hs, 0);
PG_RETURN_POINTER(a); PG_RETURN_POINTER(a);
} }
@ -307,20 +341,23 @@ akeys(PG_FUNCTION_ARGS) {
PG_FUNCTION_INFO_V1(avals); PG_FUNCTION_INFO_V1(avals);
Datum avals(PG_FUNCTION_ARGS); Datum avals(PG_FUNCTION_ARGS);
Datum Datum
avals(PG_FUNCTION_ARGS) { avals(PG_FUNCTION_ARGS)
{
HStore *hs = PG_GETARG_HS(0); HStore *hs = PG_GETARG_HS(0);
Datum *d; Datum *d;
ArrayType *a; ArrayType *a;
HEntry *ptr=ARRPTR(hs); HEntry *ptr = ARRPTR(hs);
char *base=STRPTR(hs); char *base = STRPTR(hs);
d=(Datum*)palloc(sizeof(Datum)*(hs->size+1)); 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; int vallen = (ptr->valisnull) ? 0 : ptr->vallen;
text *item=(text*)palloc(VARHDRSZ + vallen); text *item = (text *) palloc(VARHDRSZ + vallen);
VARATT_SIZEP(item) = VARHDRSZ+vallen;
VARATT_SIZEP(item) = VARHDRSZ + vallen;
memcpy(VARDATA(item), base + ptr->pos + ptr->keylen, vallen); memcpy(VARDATA(item), base + ptr->pos + ptr->keylen, vallen);
d[ ptr-ARRPTR(hs) ] = PointerGetDatum(item); d[ptr - ARRPTR(hs)] = PointerGetDatum(item);
ptr++; ptr++;
} }
@ -333,69 +370,76 @@ avals(PG_FUNCTION_ARGS) {
'i' 'i'
); );
ptr=ARRPTR(hs); ptr = ARRPTR(hs);
while( ptr-ARRPTR(hs) < hs->size ) { while (ptr - ARRPTR(hs) < hs->size)
pfree(DatumGetPointer(d[ ptr-ARRPTR(hs) ])); {
pfree(DatumGetPointer(d[ptr - ARRPTR(hs)]));
ptr++; ptr++;
} }
pfree(d); pfree(d);
PG_FREE_IF_COPY(hs,0); PG_FREE_IF_COPY(hs, 0);
PG_RETURN_POINTER(a); PG_RETURN_POINTER(a);
} }
typedef struct { typedef struct
{
HStore *hs; HStore *hs;
int i; int i;
} AKStore; } AKStore;
static void static void
setup_firstcall(FuncCallContext *funcctx, HStore *hs) { setup_firstcall(FuncCallContext *funcctx, HStore * hs)
{
MemoryContext oldcontext; MemoryContext oldcontext;
AKStore *st; AKStore *st;
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
st=(AKStore*)palloc( sizeof(AKStore) ); st = (AKStore *) palloc(sizeof(AKStore));
st->i=0; st->i = 0;
st->hs = (HStore*)palloc(hs->len); st->hs = (HStore *) palloc(hs->len);
memcpy( st->hs, hs, hs->len ); memcpy(st->hs, hs, hs->len);
funcctx->user_fctx = (void*)st; funcctx->user_fctx = (void *) st;
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
} }
PG_FUNCTION_INFO_V1(skeys); PG_FUNCTION_INFO_V1(skeys);
Datum skeys(PG_FUNCTION_ARGS); Datum skeys(PG_FUNCTION_ARGS);
Datum Datum
skeys(PG_FUNCTION_ARGS) { skeys(PG_FUNCTION_ARGS)
{
FuncCallContext *funcctx; FuncCallContext *funcctx;
AKStore *st; AKStore *st;
if (SRF_IS_FIRSTCALL()) { if (SRF_IS_FIRSTCALL())
{
HStore *hs = PG_GETARG_HS(0); HStore *hs = PG_GETARG_HS(0);
funcctx = SRF_FIRSTCALL_INIT(); funcctx = SRF_FIRSTCALL_INIT();
setup_firstcall(funcctx, hs); setup_firstcall(funcctx, hs);
PG_FREE_IF_COPY(hs,0); PG_FREE_IF_COPY(hs, 0);
} }
funcctx = SRF_PERCALL_SETUP(); funcctx = SRF_PERCALL_SETUP();
st = (AKStore*)funcctx->user_fctx; st = (AKStore *) funcctx->user_fctx;
if ( st->i < st->hs->size ) { if (st->i < st->hs->size)
{
HEntry *ptr = &(ARRPTR(st->hs)[st->i]); HEntry *ptr = &(ARRPTR(st->hs)[st->i]);
text *item=(text*)palloc(VARHDRSZ + ptr->keylen); text *item = (text *) palloc(VARHDRSZ + ptr->keylen);
VARATT_SIZEP(item) = VARHDRSZ+ptr->keylen; VARATT_SIZEP(item) = VARHDRSZ + ptr->keylen;
memcpy(VARDATA(item), STRPTR(st->hs) + ptr->pos, ptr->keylen); memcpy(VARDATA(item), STRPTR(st->hs) + ptr->pos, ptr->keylen);
st->i++; st->i++;
SRF_RETURN_NEXT(funcctx, PointerGetDatum(item)); SRF_RETURN_NEXT(funcctx, PointerGetDatum(item));
} }
pfree( st->hs ); pfree(st->hs);
pfree( st ); pfree(st);
SRF_RETURN_DONE(funcctx); SRF_RETURN_DONE(funcctx);
} }
@ -403,24 +447,29 @@ skeys(PG_FUNCTION_ARGS) {
PG_FUNCTION_INFO_V1(svals); PG_FUNCTION_INFO_V1(svals);
Datum svals(PG_FUNCTION_ARGS); Datum svals(PG_FUNCTION_ARGS);
Datum Datum
svals(PG_FUNCTION_ARGS) { svals(PG_FUNCTION_ARGS)
{
FuncCallContext *funcctx; FuncCallContext *funcctx;
AKStore *st; AKStore *st;
if (SRF_IS_FIRSTCALL()) { if (SRF_IS_FIRSTCALL())
{
HStore *hs = PG_GETARG_HS(0); HStore *hs = PG_GETARG_HS(0);
funcctx = SRF_FIRSTCALL_INIT(); funcctx = SRF_FIRSTCALL_INIT();
setup_firstcall(funcctx, hs); setup_firstcall(funcctx, hs);
PG_FREE_IF_COPY(hs,0); PG_FREE_IF_COPY(hs, 0);
} }
funcctx = SRF_PERCALL_SETUP(); funcctx = SRF_PERCALL_SETUP();
st = (AKStore*)funcctx->user_fctx; st = (AKStore *) funcctx->user_fctx;
if ( st->i < st->hs->size ) { if (st->i < st->hs->size)
{
HEntry *ptr = &(ARRPTR(st->hs)[st->i]); HEntry *ptr = &(ARRPTR(st->hs)[st->i]);
if ( ptr->valisnull ) { if (ptr->valisnull)
{
ReturnSetInfo *rsi; ReturnSetInfo *rsi;
st->i++; st->i++;
@ -428,11 +477,13 @@ svals(PG_FUNCTION_ARGS) {
rsi = (ReturnSetInfo *) fcinfo->resultinfo; rsi = (ReturnSetInfo *) fcinfo->resultinfo;
rsi->isDone = ExprMultipleResult; rsi->isDone = ExprMultipleResult;
PG_RETURN_NULL(); PG_RETURN_NULL();
} else { }
else
{
int vallen = ptr->vallen; int vallen = ptr->vallen;
text *item=(text*)palloc(VARHDRSZ + vallen); text *item = (text *) palloc(VARHDRSZ + vallen);
VARATT_SIZEP(item) = VARHDRSZ+vallen; VARATT_SIZEP(item) = VARHDRSZ + vallen;
memcpy(VARDATA(item), STRPTR(st->hs) + ptr->pos + ptr->keylen, vallen); memcpy(VARDATA(item), STRPTR(st->hs) + ptr->pos + ptr->keylen, vallen);
st->i++; st->i++;
@ -440,8 +491,8 @@ svals(PG_FUNCTION_ARGS) {
} }
} }
pfree( st->hs ); pfree(st->hs);
pfree( st ); pfree(st);
SRF_RETURN_DONE(funcctx); SRF_RETURN_DONE(funcctx);
} }
@ -449,7 +500,8 @@ svals(PG_FUNCTION_ARGS) {
PG_FUNCTION_INFO_V1(hs_contains); PG_FUNCTION_INFO_V1(hs_contains);
Datum hs_contains(PG_FUNCTION_ARGS); Datum hs_contains(PG_FUNCTION_ARGS);
Datum Datum
hs_contains(PG_FUNCTION_ARGS) { hs_contains(PG_FUNCTION_ARGS)
{
HStore *val = PG_GETARG_HS(0); HStore *val = PG_GETARG_HS(0);
HStore *tmpl = PG_GETARG_HS(1); HStore *tmpl = PG_GETARG_HS(1);
bool res = true; bool res = true;
@ -457,26 +509,31 @@ hs_contains(PG_FUNCTION_ARGS) {
char *vv = STRPTR(val); char *vv = STRPTR(val);
char *tv = STRPTR(tmpl); 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); HEntry *entry = findkey(val, tv + te->pos, te->keylen);
if ( entry ) {
if ( ! te->valisnull ) { if (entry)
if ( entry->valisnull || !( {
te->vallen==entry->vallen && if (!te->valisnull)
{
if (entry->valisnull || !(
te->vallen == entry->vallen &&
strncmp( strncmp(
vv + entry->pos + entry->keylen, vv + entry->pos + entry->keylen,
tv + te->pos + te->keylen, tv + te->pos + te->keylen,
te->vallen ) == 0 te->vallen) == 0
) ) ))
res=false; res = false;
} }
} else }
else
res = false; res = false;
te++; te++;
} }
PG_FREE_IF_COPY(val,0); PG_FREE_IF_COPY(val, 0);
PG_FREE_IF_COPY(tmpl,1); PG_FREE_IF_COPY(tmpl, 1);
PG_RETURN_BOOL(res); PG_RETURN_BOOL(res);
} }
@ -484,8 +541,9 @@ hs_contains(PG_FUNCTION_ARGS) {
PG_FUNCTION_INFO_V1(hs_contained); PG_FUNCTION_INFO_V1(hs_contained);
Datum hs_contained(PG_FUNCTION_ARGS); Datum hs_contained(PG_FUNCTION_ARGS);
Datum Datum
hs_contained(PG_FUNCTION_ARGS) { hs_contained(PG_FUNCTION_ARGS)
PG_RETURN_DATUM( DirectFunctionCall2( {
PG_RETURN_DATUM(DirectFunctionCall2(
hs_contains, hs_contains,
PG_GETARG_DATUM(1), PG_GETARG_DATUM(1),
PG_GETARG_DATUM(0) PG_GETARG_DATUM(0)
@ -495,54 +553,61 @@ hs_contained(PG_FUNCTION_ARGS) {
PG_FUNCTION_INFO_V1(each); PG_FUNCTION_INFO_V1(each);
Datum each(PG_FUNCTION_ARGS); Datum each(PG_FUNCTION_ARGS);
Datum Datum
each(PG_FUNCTION_ARGS) { each(PG_FUNCTION_ARGS)
{
FuncCallContext *funcctx; FuncCallContext *funcctx;
AKStore *st; AKStore *st;
if (SRF_IS_FIRSTCALL()) { if (SRF_IS_FIRSTCALL())
{
TupleDesc tupdesc; TupleDesc tupdesc;
MemoryContext oldcontext; MemoryContext oldcontext;
HStore *hs = PG_GETARG_HS(0); HStore *hs = PG_GETARG_HS(0);
funcctx = SRF_FIRSTCALL_INIT(); funcctx = SRF_FIRSTCALL_INIT();
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
st=(AKStore*)palloc( sizeof(AKStore) ); st = (AKStore *) palloc(sizeof(AKStore));
st->i=0; st->i = 0;
st->hs = (HStore*)palloc(hs->len); st->hs = (HStore *) palloc(hs->len);
memcpy( st->hs, hs, hs->len ); memcpy(st->hs, hs, hs->len);
funcctx->user_fctx = (void*)st; funcctx->user_fctx = (void *) st;
tupdesc = RelationNameGetTupleDesc("hs_each"); tupdesc = RelationNameGetTupleDesc("hs_each");
funcctx->slot = TupleDescGetSlot(tupdesc); funcctx->slot = TupleDescGetSlot(tupdesc);
funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc); funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
PG_FREE_IF_COPY(hs,0); PG_FREE_IF_COPY(hs, 0);
} }
funcctx = SRF_PERCALL_SETUP(); funcctx = SRF_PERCALL_SETUP();
st = (AKStore*)funcctx->user_fctx; st = (AKStore *) funcctx->user_fctx;
if ( st->i < st->hs->size ) { if (st->i < st->hs->size)
{
HEntry *ptr = &(ARRPTR(st->hs)[st->i]); HEntry *ptr = &(ARRPTR(st->hs)[st->i]);
Datum res, dvalues[2]; Datum res,
dvalues[2];
char nulls[] = {' ', ' '}; char nulls[] = {' ', ' '};
text *item; text *item;
HeapTuple tuple; HeapTuple tuple;
item=(text*)palloc(VARHDRSZ + ptr->keylen); item = (text *) palloc(VARHDRSZ + ptr->keylen);
VARATT_SIZEP(item) = VARHDRSZ+ptr->keylen; VARATT_SIZEP(item) = VARHDRSZ + ptr->keylen;
memcpy(VARDATA(item), STRPTR(st->hs) + ptr->pos, ptr->keylen); memcpy(VARDATA(item), STRPTR(st->hs) + ptr->pos, ptr->keylen);
dvalues[0] = PointerGetDatum(item); dvalues[0] = PointerGetDatum(item);
if ( ptr->valisnull ) { if (ptr->valisnull)
dvalues[1]=(Datum)0; {
nulls[1]='n'; dvalues[1] = (Datum) 0;
} else { nulls[1] = 'n';
}
else
{
int vallen = ptr->vallen; int vallen = ptr->vallen;
item=(text*)palloc(VARHDRSZ + vallen); item = (text *) palloc(VARHDRSZ + vallen);
VARATT_SIZEP(item) = VARHDRSZ+vallen; VARATT_SIZEP(item) = VARHDRSZ + vallen;
memcpy(VARDATA(item), STRPTR(st->hs) + ptr->pos + ptr->keylen, vallen); memcpy(VARDATA(item), STRPTR(st->hs) + ptr->pos + ptr->keylen, vallen);
dvalues[1] = PointerGetDatum(item); dvalues[1] = PointerGetDatum(item);
} }
@ -551,17 +616,15 @@ each(PG_FUNCTION_ARGS) {
tuple = heap_formtuple(funcctx->attinmeta->tupdesc, dvalues, nulls); tuple = heap_formtuple(funcctx->attinmeta->tupdesc, dvalues, nulls);
res = TupleGetDatum(funcctx->slot, tuple); res = TupleGetDatum(funcctx->slot, tuple);
pfree( DatumGetPointer(dvalues[0]) ); pfree(DatumGetPointer(dvalues[0]));
if ( nulls[1] != 'n' ) if (nulls[1] != 'n')
pfree( DatumGetPointer(dvalues[1]) ); pfree(DatumGetPointer(dvalues[1]));
SRF_RETURN_NEXT(funcctx, PointerGetDatum(res)); SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
} }
pfree( st->hs ); pfree(st->hs);
pfree( st ); pfree(st);
SRF_RETURN_DONE(funcctx); SRF_RETURN_DONE(funcctx);
} }

View File

@ -232,7 +232,7 @@ typedef struct
* is there value 'val' in array or not ? * is there value 'val' in array or not ?
*/ */
static bool static bool
checkcondition_arr(void *checkval, ITEM *item) checkcondition_arr(void *checkval, ITEM * item)
{ {
int4 *StopLow = ((CHKVAL *) checkval)->arrb; int4 *StopLow = ((CHKVAL *) checkval)->arrb;
int4 *StopHigh = ((CHKVAL *) checkval)->arre; int4 *StopHigh = ((CHKVAL *) checkval)->arre;
@ -254,7 +254,7 @@ checkcondition_arr(void *checkval, ITEM *item)
} }
static bool static bool
checkcondition_bit(void *checkval, ITEM *item) checkcondition_bit(void *checkval, ITEM * item)
{ {
return GETBIT(checkval, HASHVAL(item->val)); return GETBIT(checkval, HASHVAL(item->val));
} }
@ -263,7 +263,7 @@ checkcondition_bit(void *checkval, ITEM *item)
* check for boolean condition * check for boolean condition
*/ */
static bool static bool
execute(ITEM * curitem, void *checkval, bool calcnot, bool (*chkcond) (void *checkval, ITEM *item)) execute(ITEM * curitem, void *checkval, bool calcnot, bool (*chkcond) (void *checkval, ITEM * item))
{ {
if (curitem->type == VAL) if (curitem->type == VAL)
@ -319,32 +319,36 @@ execconsistent(QUERYTYPE * query, ArrayType *array, bool calcnot)
); );
} }
typedef struct { typedef struct
{
ITEM *first; ITEM *first;
bool *mapped_check; bool *mapped_check;
} GinChkVal; } GinChkVal;
static bool static bool
checkcondition_gin(void *checkval, ITEM *item) { checkcondition_gin(void *checkval, ITEM * item)
GinChkVal *gcv = (GinChkVal*)checkval; {
GinChkVal *gcv = (GinChkVal *) checkval;
return gcv->mapped_check[ item - gcv->first ]; return gcv->mapped_check[item - gcv->first];
} }
bool bool
ginconsistent(QUERYTYPE * query, bool *check) { ginconsistent(QUERYTYPE * query, bool *check)
{
GinChkVal gcv; GinChkVal gcv;
ITEM *items = GETQUERY(query); ITEM *items = GETQUERY(query);
int i, j=0; int i,
j = 0;
if ( query->size < 0 ) if (query->size < 0)
return FALSE; return FALSE;
gcv.first = items; gcv.first = items;
gcv.mapped_check = (bool*)palloc( sizeof(bool)*query->size ); gcv.mapped_check = (bool *) palloc(sizeof(bool) * query->size);
for(i=0; i<query->size; i++) for (i = 0; i < query->size; i++)
if ( items[i].type == VAL ) if (items[i].type == VAL)
gcv.mapped_check[ i ] = check[ j++ ]; gcv.mapped_check[i] = check[j++];
return execute( return execute(
GETQUERY(query) + query->size - 1, GETQUERY(query) + query->size - 1,

View File

@ -4,68 +4,79 @@ PG_FUNCTION_INFO_V1(ginint4_queryextract);
Datum ginint4_queryextract(PG_FUNCTION_ARGS); Datum ginint4_queryextract(PG_FUNCTION_ARGS);
Datum Datum
ginint4_queryextract(PG_FUNCTION_ARGS) { ginint4_queryextract(PG_FUNCTION_ARGS)
uint32 *nentries = (uint32*)PG_GETARG_POINTER(1); {
uint32 *nentries = (uint32 *) PG_GETARG_POINTER(1);
StrategyNumber strategy = PG_GETARG_UINT16(2); StrategyNumber strategy = PG_GETARG_UINT16(2);
Datum *res = NULL; Datum *res = NULL;
*nentries = 0; *nentries = 0;
if ( strategy == BooleanSearchStrategy ) { if (strategy == BooleanSearchStrategy)
QUERYTYPE *query = (QUERYTYPE*)PG_DETOAST_DATUM_COPY(PG_GETARG_POINTER(0)); {
QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM_COPY(PG_GETARG_POINTER(0));
ITEM *items = GETQUERY(query); ITEM *items = GETQUERY(query);
int i; int i;
if (query->size == 0) if (query->size == 0)
PG_RETURN_POINTER(NULL); PG_RETURN_POINTER(NULL);
if ( shorterquery(items, query->size) == 0 ) if (shorterquery(items, query->size) == 0)
elog(ERROR,"Query requires full scan, GIN doesn't support it"); elog(ERROR, "Query requires full scan, GIN doesn't support it");
pfree( query ); pfree(query);
query = (QUERYTYPE*)PG_DETOAST_DATUM(PG_GETARG_POINTER(0)); query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_POINTER(0));
items = GETQUERY(query); items = GETQUERY(query);
res = (Datum*)palloc(sizeof(Datum) * query->size); res = (Datum *) palloc(sizeof(Datum) * query->size);
*nentries = 0; *nentries = 0;
for(i=0;i<query->size;i++) for (i = 0; i < query->size; i++)
if ( items[i].type == VAL ) { if (items[i].type == VAL)
res[*nentries] = Int32GetDatum( items[i].val ); {
res[*nentries] = Int32GetDatum(items[i].val);
(*nentries)++; (*nentries)++;
} }
} else { }
else
{
ArrayType *query = PG_GETARG_ARRAYTYPE_P(0); ArrayType *query = PG_GETARG_ARRAYTYPE_P(0);
int4 *arr; int4 *arr;
uint32 i; uint32 i;
CHECKARRVALID(query); CHECKARRVALID(query);
*nentries=ARRNELEMS(query); *nentries = ARRNELEMS(query);
if ( *nentries > 0 ) { if (*nentries > 0)
res = (Datum*)palloc(sizeof(Datum) * (*nentries)); {
res = (Datum *) palloc(sizeof(Datum) * (*nentries));
arr=ARRPTR(query); arr = ARRPTR(query);
for(i=0;i<*nentries;i++) for (i = 0; i < *nentries; i++)
res[i] = Int32GetDatum( arr[i] ); res[i] = Int32GetDatum(arr[i]);
} }
} }
PG_RETURN_POINTER( res ); PG_RETURN_POINTER(res);
} }
PG_FUNCTION_INFO_V1(ginint4_consistent); PG_FUNCTION_INFO_V1(ginint4_consistent);
Datum ginint4_consistent(PG_FUNCTION_ARGS); Datum ginint4_consistent(PG_FUNCTION_ARGS);
Datum Datum
ginint4_consistent(PG_FUNCTION_ARGS) { ginint4_consistent(PG_FUNCTION_ARGS)
bool *check = (bool*)PG_GETARG_POINTER(0); {
bool *check = (bool *) PG_GETARG_POINTER(0);
StrategyNumber strategy = PG_GETARG_UINT16(1); StrategyNumber strategy = PG_GETARG_UINT16(1);
int res=FALSE; 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 RTOverlapStrategyNumber:
case RTContainedByStrategyNumber: case RTContainedByStrategyNumber:
case RTOldContainedByStrategyNumber: case RTOldContainedByStrategyNumber:
@ -77,22 +88,27 @@ ginint4_consistent(PG_FUNCTION_ARGS) {
case RTContainsStrategyNumber: case RTContainsStrategyNumber:
case RTOldContainsStrategyNumber: case RTOldContainsStrategyNumber:
res = TRUE; res = TRUE;
do { do
{
ArrayType *query = PG_GETARG_ARRAYTYPE_P(2); ArrayType *query = PG_GETARG_ARRAYTYPE_P(2);
int i, nentries=ARRNELEMS(query); int i,
nentries = ARRNELEMS(query);
for(i=0;i<nentries;i++) for (i = 0; i < nentries; i++)
if ( !check[i] ) { if (!check[i])
{
res = FALSE; res = FALSE;
break; break;
} }
} while(0); } while (0);
break; break;
case BooleanSearchStrategy: case BooleanSearchStrategy:
do { do
QUERYTYPE *query = (QUERYTYPE*)PG_DETOAST_DATUM(PG_GETARG_POINTER(2)); {
res = ginconsistent( query, check ); QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_POINTER(2));
} while(0);
res = ginconsistent(query, check);
} while (0);
break; break;
default: default:
elog(ERROR, "ginint4_consistent: unknown strategy number: %d", strategy); elog(ERROR, "ginint4_consistent: unknown strategy number: %d", strategy);

View File

@ -36,19 +36,21 @@ g_int_consistent(PG_FUNCTION_ARGS)
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
bool retval; bool retval;
if (strategy == BooleanSearchStrategy) { if (strategy == BooleanSearchStrategy)
{
retval = execconsistent((QUERYTYPE *) query, retval = execconsistent((QUERYTYPE *) query,
(ArrayType *) DatumGetPointer(entry->key), (ArrayType *) DatumGetPointer(entry->key),
GIST_LEAF(entry)); GIST_LEAF(entry));
pfree( query ); pfree(query);
PG_RETURN_BOOL(retval); PG_RETURN_BOOL(retval);
} }
/* sort query for fast search, key is already sorted */ /* sort query for fast search, key is already sorted */
CHECKARRVALID(query); CHECKARRVALID(query);
if (ARRISVOID(query)) { if (ARRISVOID(query))
pfree( query ); {
pfree(query);
PG_RETURN_BOOL(false); PG_RETURN_BOOL(false);
} }
PREPAREARR(query); PREPAREARR(query);
@ -88,7 +90,7 @@ g_int_consistent(PG_FUNCTION_ARGS)
default: default:
retval = FALSE; retval = FALSE;
} }
pfree( query ); pfree(query);
PG_RETURN_BOOL(retval); PG_RETURN_BOOL(retval);
} }

View File

@ -93,18 +93,23 @@ inner_int_union(ArrayType *a, ArrayType *b)
nb = ARRNELEMS(b); nb = ARRNELEMS(b);
int *da = ARRPTR(a), int *da = ARRPTR(a),
*db = ARRPTR(b); *db = ARRPTR(b);
int i,j, *dr; int i,
j,
*dr;
r = new_intArrayType(na + nb); r = new_intArrayType(na + nb);
dr = ARRPTR(r); dr = ARRPTR(r);
/* union */ /* union */
i = j = 0; i = j = 0;
while (i < na && j < nb) { while (i < na && j < nb)
if (da[i] == db[j]) { {
if (da[i] == db[j])
{
*dr++ = da[i++]; *dr++ = da[i++];
j++; j++;
} else if (da[i] < db[j]) }
else if (da[i] < db[j])
*dr++ = da[i++]; *dr++ = da[i++];
else else
*dr++ = db[j++]; *dr++ = db[j++];
@ -115,7 +120,7 @@ inner_int_union(ArrayType *a, ArrayType *b)
while (j < nb) while (j < nb)
*dr++ = db[j++]; *dr++ = db[j++];
r = resize_intArrayType(r, dr-ARRPTR(r)); r = resize_intArrayType(r, dr - ARRPTR(r));
} }
if (ARRNELEMS(r) > 1) if (ARRNELEMS(r) > 1)

View File

@ -506,16 +506,17 @@ g_intbig_consistent(PG_FUNCTION_ARGS)
if (strategy == BooleanSearchStrategy) if (strategy == BooleanSearchStrategy)
{ {
retval =signconsistent((QUERYTYPE *) query, retval = signconsistent((QUERYTYPE *) query,
GETSIGN(DatumGetPointer(entry->key)), GETSIGN(DatumGetPointer(entry->key)),
false); false);
PG_FREE_IF_COPY( query, 1 ); PG_FREE_IF_COPY(query, 1);
PG_RETURN_BOOL(retval); PG_RETURN_BOOL(retval);
} }
CHECKARRVALID(query); CHECKARRVALID(query);
if (ARRISVOID(query)) { if (ARRISVOID(query))
PG_FREE_IF_COPY( query, 1 ); {
PG_FREE_IF_COPY(query, 1);
PG_RETURN_BOOL(FALSE); PG_RETURN_BOOL(FALSE);
} }
@ -602,6 +603,6 @@ g_intbig_consistent(PG_FUNCTION_ARGS)
default: default:
retval = FALSE; retval = FALSE;
} }
PG_FREE_IF_COPY( query, 1 ); PG_FREE_IF_COPY(query, 1);
PG_RETURN_BOOL(retval); PG_RETURN_BOOL(retval);
} }

View File

@ -6,7 +6,7 @@
* http://www.gs1.org/productssolutions/idkeys/support/prefix_list.html * http://www.gs1.org/productssolutions/idkeys/support/prefix_list.html
* *
* IDENTIFICATION * 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 */ {"958", "958"}, /* GS1 Macau */
{"977", "977"}, /* Serial publications (ISSN) */ {"977", "977"}, /* Serial publications (ISSN) */
{"978", "978"}, /* Bookland (ISBN) */ {"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 */ {"980", "980"}, /* Refund receipts */
{"981", "982"}, /* Common Currency Coupons */ {"981", "982"}, /* Common Currency Coupons */
{"990", "999"}, /* Coupons */ {"990", "999"}, /* Coupons */

View File

@ -7,7 +7,7 @@
* http://www.isbn.org/ * http://www.isbn.org/
* *
* IDENTIFICATION * 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 * 0-393-04002-X => 039304002(X) <=> 039304002 <=> (978)039304002 <=> 978039304002(9) <=> 978-0-393-04002-9
* *

View File

@ -6,7 +6,7 @@
* http://www.ismn-international.org * http://www.ismn-international.org
* *
* IDENTIFICATION * 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 * M-3452-4680-5 <=> (0)-3452-4680-5 <=> 0345246805 <=> 9790345246805 <=> 979-0-3452-4680-5
* *

View File

@ -6,7 +6,7 @@
* http://www.issn.org/ * http://www.issn.org/
* *
* IDENTIFICATION * 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 * 1144-875X <=> 1144875(X) <=> 1144875 <=> (977)1144875 <=> 9771144875(00) <=> 977114487500(7) <=> 977-1144-875-00-7
* *

View File

@ -6,7 +6,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*/ */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
* *
* IDENTIFICATION * 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,9 +29,12 @@ PG_MODULE_MAGIC;
#define MAXEAN13LEN 18 #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" }; static const char *isn_names[] = {"EAN13/UPC/ISxN", "EAN13/UPC/ISxN", "EAN13", "ISBN", "ISMN", "ISSN", "UPC"};
static bool g_weak = false; static bool g_weak = false;
static bool g_initialized = false; static bool g_initialized = false;
@ -60,14 +63,25 @@ static bool g_initialized = false;
*/ */
#ifdef ISN_DEBUG #ifdef ISN_DEBUG
static 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; const char *aux1,
int a, b, x=0, y=-1, i=0, j, cnt=0, init=0; *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]; aux1 = TABLE[i][0];
aux2 = TABLE[i][1]; aux2 = TABLE[i][1];
@ -78,7 +92,8 @@ bool check_table(const char *(*TABLE)[2], const unsigned TABLE_index[10][2])
b = *aux2 - '0'; b = *aux2 - '0';
/* must always have the same format and length: */ /* must always have the same format and length: */
while(*aux1 && *aux2) { while (*aux1 && *aux2)
{
if (!(isdigit((unsigned char) *aux1) && if (!(isdigit((unsigned char) *aux1) &&
isdigit((unsigned char) *aux2)) && isdigit((unsigned char) *aux2)) &&
(*aux1 != *aux2 || *aux1 != '-')) (*aux1 != *aux2 || *aux1 != '-'))
@ -86,14 +101,19 @@ bool check_table(const char *(*TABLE)[2], const unsigned TABLE_index[10][2])
aux1++; aux1++;
aux2++; aux2++;
} }
if(*aux1!=*aux2) goto invalidtable; if (*aux1 != *aux2)
goto invalidtable;
/* found a new range */ /* found a new range */
if(a>y) { if (a > y)
{
/* check current range in the index: */ /* check current range in the index: */
for(j=x;j<=y;j++) { for (j = x; j <= y; j++)
if(TABLE_index[j][0] != init) goto invalidindex; {
if(TABLE_index[j][1] != i-init) goto invalidindex; if (TABLE_index[j][0] != init)
goto invalidindex;
if (TABLE_index[j][1] != i - init)
goto invalidindex;
} }
init = i; init = i;
x = a; x = a;
@ -101,7 +121,8 @@ bool check_table(const char *(*TABLE)[2], const unsigned TABLE_index[10][2])
/* Always get the new limit */ /* Always get the new limit */
y = b; y = b;
if(y<x) goto invalidtable; if (y < x)
goto invalidtable;
i++; i++;
} }
@ -123,11 +144,15 @@ invalidindex:
*---------------------------------------------------------*/ *---------------------------------------------------------*/
static static
unsigned dehyphenate(char *bufO, char *bufI) unsigned
dehyphenate(char *bufO, char *bufI)
{ {
unsigned ret = 0; unsigned ret = 0;
while(*bufI) {
if(isdigit((unsigned char) *bufI)) { while (*bufI)
{
if (isdigit((unsigned char) *bufI))
{
*bufO++ = *bufI; *bufO++ = *bufI;
ret++; ret++;
} }
@ -145,22 +170,33 @@ unsigned dehyphenate(char *bufO, char *bufI)
* Returns the number of characters acctually hyphenated. * Returns the number of characters acctually hyphenated.
*/ */
static 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; unsigned ret = 0;
const char *ean_aux1, *ean_aux2, *ean_p; const char *ean_aux1,
char *firstdig, *aux1, *aux2; *ean_aux2,
unsigned search, upper, lower, step; *ean_p;
bool ean_in1, ean_in2; char *firstdig,
*aux1,
*aux2;
unsigned search,
upper,
lower,
step;
bool ean_in1,
ean_in2;
/* just compress the string if no further hyphenation is required */ /* just compress the string if no further hyphenation is required */
if(TABLE == NULL || TABLE_index == NULL) { if (TABLE == NULL || TABLE_index == NULL)
while(*bufI) { {
while (*bufI)
{
*bufO++ = *bufI++; *bufO++ = *bufI++;
ret++; ret++;
} }
*bufO = '\0'; *bufO = '\0';
return (ret+1); return (ret + 1);
} }
/* add remaining hyphenations */ /* add remaining hyphenations */
@ -171,26 +207,41 @@ unsigned hyphenate(char *bufO, char *bufI, const char *(*TABLE)[2], const unsign
lower--; lower--;
step = (upper - lower) / 2; step = (upper - lower) / 2;
if(step == 0) return 0; if (step == 0)
return 0;
search = lower + step; search = lower + step;
firstdig = bufI; firstdig = bufI;
ean_in1 = ean_in2 = false; ean_in1 = ean_in2 = false;
ean_aux1 = TABLE[search][0]; ean_aux1 = TABLE[search][0];
ean_aux2 = TABLE[search][1]; ean_aux2 = TABLE[search][1];
do { do
if((ean_in1 || *firstdig>=*ean_aux1) && (ean_in2 || *firstdig<=*ean_aux2)) { {
if(*firstdig > *ean_aux1) ean_in1 = true; if ((ean_in1 || *firstdig >= *ean_aux1) && (ean_in2 || *firstdig <= *ean_aux2))
if(*firstdig < *ean_aux2) ean_in2 = true; {
if(ean_in1 && ean_in2) break; 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++; firstdig++, ean_aux1++, ean_aux2++;
if(!(*ean_aux1 && *ean_aux2 && *firstdig)) break; if (!(*ean_aux1 && *ean_aux2 && *firstdig))
if(!isdigit((unsigned char) *ean_aux1)) ean_aux1++, ean_aux2++; break;
} else { if (!isdigit((unsigned char) *ean_aux1))
/* check in what direction we should go and move the pointer accordingly */ ean_aux1++, ean_aux2++;
if(*firstdig < *ean_aux1 && !ean_in1) upper = search; }
else lower = search; 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; step = (upper - lower) / 2;
search = lower + step; search = lower + step;
@ -201,20 +252,24 @@ unsigned hyphenate(char *bufO, char *bufI, const char *(*TABLE)[2], const unsign
ean_aux1 = TABLE[search][0]; ean_aux1 = TABLE[search][0];
ean_aux2 = TABLE[search][1]; ean_aux2 = TABLE[search][1];
} }
} while(step); } while (step);
if(step) { if (step)
{
aux1 = bufO; aux1 = bufO;
aux2 = bufI; aux2 = bufI;
ean_p = TABLE[search][0]; ean_p = TABLE[search][0];
while(*ean_p && *aux2) { while (*ean_p && *aux2)
if(*ean_p++!='-') *aux1++ = *aux2++; {
else *aux1++ = '-'; if (*ean_p++ != '-')
*aux1++ = *aux2++;
else
*aux1++ = '-';
ret++; ret++;
} }
*aux1++='-'; *aux1++ = '-';
*aux1 = *aux2; /* add a lookahead char */ *aux1 = *aux2; /* add a lookahead char */
return (ret+1); return (ret + 1);
} }
return ret; return ret;
} }
@ -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) * Returns the weight of the number (the check digit value, 0-10)
*/ */
static static
unsigned weight_checkdig(char *isn, unsigned size) unsigned
weight_checkdig(char *isn, unsigned size)
{ {
unsigned weight = 0; 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'); weight += size-- * (*isn - '0');
} }
isn++; isn++;
} }
weight = weight % 11; weight = weight % 11;
if(weight != 0) weight = 11 - weight; if (weight != 0)
weight = 11 - weight;
return weight; return weight;
} }
@ -248,24 +308,33 @@ unsigned weight_checkdig(char *isn, unsigned size)
* Returns the check digit value (0-9) * Returns the check digit value (0-9)
*/ */
static 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; unsigned pos = 0;
if(*num == 'M') { /* ISMN start with 'M' */
if (*num == 'M')
{ /* ISMN start with 'M' */
check3 = 3; check3 = 3;
pos = 1; pos = 1;
} }
while(*num && size>1) { while (*num && size > 1)
if(isdigit((unsigned char) *num)) { {
if(pos++%2) check3 += *num - '0'; if (isdigit((unsigned char) *num))
else check += *num - '0'; {
if (pos++ % 2)
check3 += *num - '0';
else
check += *num - '0';
size--; size--;
} }
num++; num++;
} }
check = (check + 3*check3) % 10; check = (check + 3 * check3) % 10;
if(check != 0) check = 10 - check; if (check != 0)
check = 10 - check;
return check; return check;
} }
@ -277,59 +346,79 @@ unsigned checkdig(char *num, unsigned size)
* If errorOK is true, just return "false" for bad input. * If errorOK is true, just return "false" for bad input.
*/ */
static 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; enum isn_type type = INVALID;
char buf[MAXEAN13LEN + 1]; char buf[MAXEAN13LEN + 1];
char *firstdig, *aux; char *firstdig,
*aux;
unsigned digval; unsigned digval;
unsigned search; unsigned search;
ean13 ret = ean; ean13 ret = ean;
ean >>= 1; ean >>= 1;
/* verify it's in the EAN13 range */ /* verify it's in the EAN13 range */
if(ean > UINT64CONST(9999999999999)) if (ean > UINT64CONST(9999999999999))
goto eantoobig; goto eantoobig;
/* convert the number */ /* convert the number */
search = 0; search = 0;
firstdig = aux = buf + 13; firstdig = aux = buf + 13;
*aux = '\0'; /* terminate string; aux points to last digit */ *aux = '\0'; /* terminate string; aux points to last digit */
do { do
digval = (unsigned)(ean % 10); /* get the decimal value */ {
digval = (unsigned) (ean % 10); /* get the decimal value */
ean /= 10; /* get next digit */ ean /= 10; /* get next digit */
*--aux = (char)(digval + '0'); /* convert to ascii and store */ *--aux = (char) (digval + '0'); /* convert to ascii and store */
} while(ean && search++<12); } 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: */ /* find out the data type: */
if(!strncmp("978", buf, 3)) { /* ISBN */ if (!strncmp("978", buf, 3))
{ /* ISBN */
type = ISBN; type = ISBN;
} else if(!strncmp("977", buf, 3)) { /* ISSN */ }
else if (!strncmp("977", buf, 3))
{ /* ISSN */
type = ISSN; type = ISSN;
} else if(!strncmp("9790", buf, 4)) { /* ISMN */ }
else if (!strncmp("9790", buf, 4))
{ /* ISMN */
type = ISMN; type = ISMN;
} else if(!strncmp("979", buf, 3)) { /* ISBN-13 */ }
else if (!strncmp("979", buf, 3))
{ /* ISBN-13 */
type = ISBN; type = ISBN;
} else if(*buf == '0') { /* UPC */ }
else if (*buf == '0')
{ /* UPC */
type = UPC; type = UPC;
} else { }
else
{
type = EAN13; type = EAN13;
} }
if(accept != ANY && accept != EAN13 && accept != type) goto eanwrongtype; if (accept != ANY && accept != EAN13 && accept != type)
goto eanwrongtype;
*result = ret; *result = ret;
return true; return true;
eanwrongtype: eanwrongtype:
if(!errorOK) { if (!errorOK)
if(type!=EAN13) { {
if (type != EAN13)
{
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("cannot cast EAN13(%s) to %s for number: \"%s\"", errmsg("cannot cast EAN13(%s) to %s for number: \"%s\"",
isn_names[type], isn_names[accept], buf))); isn_names[type], isn_names[accept], buf)));
} else { }
else
{
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("cannot cast %s to %s for number: \"%s\"", errmsg("cannot cast %s to %s for number: \"%s\"",
@ -339,12 +428,13 @@ eanwrongtype:
return false; return false;
eantoobig: eantoobig:
if(!errorOK) { if (!errorOK)
{
char eanbuf[64]; char eanbuf[64];
/* /*
* Format the number separately to keep the machine-dependent * Format the number separately to keep the machine-dependent format
* format code out of the translatable message text * code out of the translatable message text
*/ */
snprintf(eanbuf, sizeof(eanbuf), EAN13_FORMAT, ean); snprintf(eanbuf, sizeof(eanbuf), EAN13_FORMAT, ean);
ereport(ERROR, ereport(ERROR,
@ -360,45 +450,55 @@ eantoobig:
* UPC/ISxN string number. Assumes the input string is normalized. * UPC/ISxN string number. Assumes the input string is normalized.
*/ */
static inline static inline
void ean2ISBN(char *isn) void
ean2ISBN(char *isn)
{ {
char *aux; char *aux;
unsigned check; unsigned check;
/* the number should come in this format: 978-0-000-00000-0 */ /* the number should come in this format: 978-0-000-00000-0 */
/* Strip the first part and calculate the new check digit */ /* Strip the first part and calculate the new check digit */
hyphenate(isn, isn+4, NULL, NULL); hyphenate(isn, isn + 4, NULL, NULL);
check = weight_checkdig(isn, 10); check = weight_checkdig(isn, 10);
aux = strchr(isn, '\0'); aux = strchr(isn, '\0');
while(!isdigit((unsigned char) *--aux)); while (!isdigit((unsigned char) *--aux));
if(check == 10) *aux = 'X'; if (check == 10)
else *aux = check + '0'; *aux = 'X';
else
*aux = check + '0';
} }
static inline static inline
void ean2ISMN(char *isn) void
ean2ISMN(char *isn)
{ {
/* the number should come in this format: 979-0-000-00000-0 */ /* 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' */ /* Just strip the first part and change the first digit ('0') to 'M' */
hyphenate(isn, isn+4, NULL, NULL); hyphenate(isn, isn + 4, NULL, NULL);
isn[0] = 'M'; isn[0] = 'M';
} }
static inline static inline
void ean2ISSN(char *isn) void
ean2ISSN(char *isn)
{ {
unsigned check; unsigned check;
/* the number should come in this format: 977-0000-000-00-0 */ /* the number should come in this format: 977-0000-000-00-0 */
/* Strip the first part, crop, and calculate the new check digit */ /* Strip the first part, crop, and calculate the new check digit */
hyphenate(isn, isn+4, NULL, NULL); hyphenate(isn, isn + 4, NULL, NULL);
check = weight_checkdig(isn, 8); check = weight_checkdig(isn, 8);
if(check == 10) isn[8] = 'X'; if (check == 10)
else isn[8] = check + '0'; isn[8] = 'X';
else
isn[8] = check + '0';
isn[9] = '\0'; isn[9] = '\0';
} }
static inline static inline
void ean2UPC(char *isn) void
ean2UPC(char *isn)
{ {
/* the number should come in this format: 000-000000000-0 */ /* the number should come in this format: 000-000000000-0 */
/* Strip the first part, crop, and dehyphenate */ /* Strip the first part, crop, and dehyphenate */
dehyphenate(isn, isn+1); dehyphenate(isn, isn + 1);
isn[12] = '\0'; isn[12] = '\0';
} }
@ -410,14 +510,18 @@ void ean2UPC(char *isn)
* Returns the ean13 value of the string. * Returns the ean13 value of the string.
*/ */
static static
ean13 str2ean(const char *num) ean13
str2ean(const char *num)
{ {
ean13 ean = 0; /* current ean */ 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++; num++;
} }
return (ean<<1); /* also give room to a flag */ return (ean << 1); /* also give room to a flag */
} }
/* /*
@ -431,69 +535,87 @@ ean13 str2ean(const char *num)
* If errorOK is true, just return "false" for bad input. * If errorOK is true, just return "false" for bad input.
*/ */
static 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 char *(*TABLE)[2];
const unsigned (*TABLE_index)[2]; const unsigned (*TABLE_index)[2];
enum isn_type type = INVALID; enum isn_type type = INVALID;
char *firstdig, *aux; char *firstdig,
*aux;
unsigned digval; unsigned digval;
unsigned search; 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; TABLE_index = ISBN_index;
if((ean & 1)!=0) valid = '!'; if ((ean & 1) != 0)
valid = '!';
ean >>= 1; ean >>= 1;
/* verify it's in the EAN13 range */ /* verify it's in the EAN13 range */
if(ean > UINT64CONST(9999999999999)) if (ean > UINT64CONST(9999999999999))
goto eantoobig; goto eantoobig;
/* convert the number */ /* convert the number */
search = 0; search = 0;
firstdig = aux = result + MAXEAN13LEN; firstdig = aux = result + MAXEAN13LEN;
*aux = '\0'; /* terminate string; aux points to last digit */ *aux = '\0'; /* terminate string; aux points to last digit */
*--aux = valid; /* append '!' for numbers with invalid but corrected check digit */ *--aux = valid; /* append '!' for numbers with invalid but
do { * corrected check digit */
digval = (unsigned)(ean % 10); /* get the decimal value */ do
{
digval = (unsigned) (ean % 10); /* get the decimal value */
ean /= 10; /* get next digit */ ean /= 10; /* get next digit */
*--aux = (char)(digval + '0'); /* convert to ascii and store */ *--aux = (char) (digval + '0'); /* convert to ascii and store */
if(search == 0) *--aux = '-'; /* the check digit is always there */ if (search == 0)
} while(ean && search++<13); *--aux = '-'; /* the check digit is always there */
while(search++<13) *--aux = '0'; /* fill the remaining EAN13 with '0' */ } while (ean && search++ < 13);
while (search++ < 13)
*--aux = '0'; /* fill the remaining EAN13 with '0' */
/* The string should be in this form: ???DDDDDDDDDDDD-D" */ /* The string should be in this form: ???DDDDDDDDDDDD-D" */
search = hyphenate(result, result+3, EAN13_range, EAN13_index); search = hyphenate(result, result + 3, EAN13_range, EAN13_index);
/* verify it's a logically valid EAN13 */ /* verify it's a logically valid EAN13 */
if(search == 0) { if (search == 0)
search = hyphenate(result, result+3, NULL, NULL); {
search = hyphenate(result, result + 3, NULL, NULL);
goto okay; goto okay;
} }
/* find out what type of hyphenation is needed: */ /* 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" */ /* The string should be in this form: 978-??000000000-0" */
type = ISBN; type = ISBN;
TABLE = ISBN_range; TABLE = ISBN_range;
TABLE_index = ISBN_index; 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" */ /* The string should be in this form: 977-??000000000-0" */
type = ISSN; type = ISSN;
TABLE = ISSN_range; TABLE = ISSN_range;
TABLE_index = ISSN_index; 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" */ /* The string should be in this form: 979-0?000000000-0" */
type = ISMN; type = ISMN;
TABLE = ISMN_range; TABLE = ISMN_range;
TABLE_index = ISMN_index; TABLE_index = ISMN_index;
} else if(*result == '0') { /* UPC */ }
else if (*result == '0')
{ /* UPC */
/* The string should be in this form: 000-00000000000-0" */ /* The string should be in this form: 000-00000000000-0" */
type = UPC; type = UPC;
TABLE = UPC_range; TABLE = UPC_range;
TABLE_index = UPC_index; TABLE_index = UPC_index;
} else { }
else
{
type = EAN13; type = EAN13;
TABLE = NULL; TABLE = NULL;
TABLE_index = NULL; TABLE_index = NULL;
@ -501,18 +623,20 @@ bool ean2string(ean13 ean, bool errorOK, char *result, bool shortType)
/* verify it's a logically valid EAN13/UPC/ISxN */ /* verify it's a logically valid EAN13/UPC/ISxN */
digval = search; digval = search;
search = hyphenate(result+digval, result+digval+2, TABLE, TABLE_index); search = hyphenate(result + digval, result + digval + 2, TABLE, TABLE_index);
/* verify it's a valid EAN13 */ /* verify it's a valid EAN13 */
if(search == 0) { if (search == 0)
search = hyphenate(result+digval, result+digval+2, NULL, NULL); {
search = hyphenate(result + digval, result + digval + 2, NULL, NULL);
goto okay; goto okay;
} }
okay: okay:
/* convert to the old short type: */ /* convert to the old short type: */
if(shortType) if (shortType)
switch(type) { switch (type)
{
case ISBN: case ISBN:
ean2ISBN(result); ean2ISBN(result);
break; break;
@ -531,13 +655,13 @@ okay:
return true; return true;
eantoobig: eantoobig:
if(!errorOK) if (!errorOK)
{ {
char eanbuf[64]; char eanbuf[64];
/* /*
* Format the number separately to keep the machine-dependent * Format the number separately to keep the machine-dependent format
* format code out of the translatable message text * code out of the translatable message text
*/ */
snprintf(eanbuf, sizeof(eanbuf), EAN13_FORMAT, ean); snprintf(eanbuf, sizeof(eanbuf), EAN13_FORMAT, ean);
ereport(ERROR, ereport(ERROR,
@ -558,157 +682,222 @@ eantoobig:
* (even if the check digit is valid) * (even if the check digit is valid)
*/ */
static static
bool string2ean(const char *str, bool errorOK, ean13 *result, bool
string2ean(const char *str, bool errorOK, ean13 * result,
enum isn_type accept) enum isn_type accept)
{ {
bool digit, last; bool digit,
last;
char buf[17] = " "; 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; const char *aux2 = str;
enum isn_type type = INVALID; enum isn_type type = INVALID;
unsigned check = 0, rcheck = (unsigned)-1; unsigned check = 0,
rcheck = (unsigned) -1;
unsigned length = 0; unsigned length = 0;
bool magic = false, valid = true; bool magic = false,
valid = true;
/* recognize and validate the number: */ /* 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? */ last = (*(aux2 + 1) == '!' || *(aux2 + 1) == '\0'); /* is the last character */
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; magic = digit = true;
if(length == 0 && (*aux2=='M' || *aux2=='m')) { if (length == 0 && (*aux2 == 'M' || *aux2 == 'm'))
{
/* only ISMN can be here */ /* only ISMN can be here */
if(type != INVALID) goto eaninvalid; if (type != INVALID)
goto eaninvalid;
type = ISMN; type = ISMN;
*aux1++ = 'M'; *aux1++ = 'M';
length++; 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 */ /* only ISSN can be here */
if(type != INVALID) goto eaninvalid; if (type != INVALID)
goto eaninvalid;
type = ISSN; type = ISSN;
*aux1++ = toupper((unsigned char) *aux2); *aux1++ = toupper((unsigned char) *aux2);
length++; 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 */ /* only ISBN and ISMN can be here */
if(type != INVALID && type != ISMN) goto eaninvalid; if (type != INVALID && type != ISMN)
if(type == INVALID) type = ISBN; /* ISMN must start with 'M' */ goto eaninvalid;
if (type == INVALID)
type = ISBN; /* ISMN must start with 'M' */
*aux1++ = toupper((unsigned char) *aux2); *aux1++ = toupper((unsigned char) *aux2);
length++; length++;
} else if(length == 11 && digit && last) { }
else if (length == 11 && digit && last)
{
/* only UPC can be here */ /* only UPC can be here */
if(type != INVALID) goto eaninvalid; if (type != INVALID)
goto eaninvalid;
type = UPC; type = UPC;
*aux1++ = *aux2; *aux1++ = *aux2;
length++; length++;
} else if(*aux2 == '-' || *aux2 == ' ') { }
else if (*aux2 == '-' || *aux2 == ' ')
{
/* skip, we could validate but I think it's worthless */ /* 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 */ /* the invalid check digit sufix was found, set it */
if(!magic) valid = false; if (!magic)
valid = false;
magic = true; magic = true;
} else if(!digit) { }
else if (!digit)
{
goto eaninvalid; goto eaninvalid;
} else { }
else
{
*aux1++ = *aux2; *aux1++ = *aux2;
if(++length > 13) goto eantoobig; if (++length > 13)
goto eantoobig;
} }
aux2++; aux2++;
} }
*aux1 = '\0'; /* terminate the string */ *aux1 = '\0'; /* terminate the string */
/* find the current check digit value */ /* find the current check digit value */
if(length == 13) { if (length == 13)
{
/* only EAN13 can be here */ /* only EAN13 can be here */
if(type != INVALID) goto eaninvalid; if (type != INVALID)
goto eaninvalid;
type = EAN13; type = EAN13;
check = buf[15]-'0'; check = buf[15] - '0';
} else if(length == 12) { }
else if (length == 12)
{
/* only UPC can be here */ /* only UPC can be here */
if(type != UPC) goto eaninvalid; if (type != UPC)
check = buf[14]-'0'; goto eaninvalid;
} else if(length == 10) { check = buf[14] - '0';
if(type != ISBN && type != ISMN) goto eaninvalid; }
if(buf[12] == 'X') check = 10; else if (length == 10)
else check = buf[12]-'0'; {
} else if(length == 8) { if (type != ISBN && type != ISMN)
if(type != INVALID && type != ISSN) goto eaninvalid; 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; type = ISSN;
if(buf[10] == 'X') check = 10; if (buf[10] == 'X')
else check = buf[10]-'0'; check = 10;
} else goto eaninvalid; 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: */ /* obtain the real check digit value, validate, and convert to ean13: */
if(accept == EAN13 && type != accept) goto eanwrongtype; if (accept == EAN13 && type != accept)
if(accept != ANY && type != EAN13 && type != accept) goto eanwrongtype; goto eanwrongtype;
switch(type) { if (accept != ANY && type != EAN13 && type != accept)
goto eanwrongtype;
switch (type)
{
case EAN13: case EAN13:
valid = (valid && ((rcheck=checkdig(buf+3, 13)) == check || magic)); valid = (valid && ((rcheck = checkdig(buf + 3, 13)) == check || magic));
/* now get the subtype of EAN13: */ /* now get the subtype of EAN13: */
if(buf[3] == '0') type = UPC; if (buf[3] == '0')
else if(!strncmp("977", buf+3, 3)) type = ISSN; type = UPC;
else if(!strncmp("978", buf+3, 3)) type = ISBN; else if (!strncmp("977", buf + 3, 3))
else if(!strncmp("9790", buf+3, 4)) type = ISMN; type = ISSN;
else if(!strncmp("979", buf+3, 3)) type = ISBN; else if (!strncmp("978", buf + 3, 3))
if(accept != EAN13 && accept != ANY && type != accept) goto eanwrongtype; 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; break;
case ISMN: 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
valid = (valid && ((rcheck=checkdig(buf+3, 10)) == check || magic)); * ISMN it's only 9790 */
valid = (valid && ((rcheck = checkdig(buf + 3, 10)) == check || magic));
break; break;
case ISBN: case ISBN:
strncpy(buf, "978", 3); strncpy(buf, "978", 3);
valid = (valid && ((rcheck=weight_checkdig(buf+3, 10)) == check || magic)); valid = (valid && ((rcheck = weight_checkdig(buf + 3, 10)) == check || magic));
break; break;
case ISSN: 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); strncpy(buf, "977", 3);
valid = (valid && ((rcheck=weight_checkdig(buf+3, 8)) == check || magic)); valid = (valid && ((rcheck = weight_checkdig(buf + 3, 8)) == check || magic));
break; break;
case UPC: case UPC:
buf[2] = '0'; buf[2] = '0';
valid = (valid && ((rcheck=checkdig(buf+2, 13)) == check || magic)); valid = (valid && ((rcheck = checkdig(buf + 2, 13)) == check || magic));
default: default:
break; break;
} }
/* fix the check digit: */ /* fix the check digit: */
for(aux1 = buf; *aux1 && *aux1 <= ' '; aux1++); for (aux1 = buf; *aux1 && *aux1 <= ' '; aux1++);
aux1[12] = checkdig(aux1, 13) + '0'; aux1[12] = checkdig(aux1, 13) + '0';
aux1[13] = '\0'; aux1[13] = '\0';
if(!valid && !magic) goto eanbadcheck; if (!valid && !magic)
goto eanbadcheck;
*result = str2ean(aux1); *result = str2ean(aux1);
*result |= valid?0:1; *result |= valid ? 0 : 1;
return true; return true;
eanbadcheck: 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 */ /* set the "invalid-check-digit-on-input" flag */
*result = str2ean(aux1); *result = str2ean(aux1);
*result |= 1; *result |= 1;
return true; return true;
} }
if(!errorOK) { if (!errorOK)
if(rcheck == (unsigned)-1) { {
if (rcheck == (unsigned) -1)
{
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid %s number: \"%s\"", errmsg("invalid %s number: \"%s\"",
isn_names[accept], str))); isn_names[accept], str)));
} else { }
else
{
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid check digit for %s number: \"%s\", should be %c", errmsg("invalid check digit for %s number: \"%s\", should be %c",
isn_names[accept], str, (rcheck==10)?('X'):(rcheck+'0')))); isn_names[accept], str, (rcheck == 10) ? ('X') : (rcheck + '0'))));
} }
} }
return false; return false;
eaninvalid: eaninvalid:
if(!errorOK) if (!errorOK)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for %s number: \"%s\"", errmsg("invalid input syntax for %s number: \"%s\"",
@ -716,7 +905,7 @@ eaninvalid:
return false; return false;
eanwrongtype: eanwrongtype:
if(!errorOK) if (!errorOK)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("cannot cast %s to %s for number: \"%s\"", errmsg("cannot cast %s to %s for number: \"%s\"",
@ -724,7 +913,7 @@ eanwrongtype:
return false; return false;
eantoobig: eantoobig:
if(!errorOK) if (!errorOK)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("value \"%s\" is out of range for %s type", errmsg("value \"%s\" is out of range for %s type",
@ -736,18 +925,19 @@ eantoobig:
* Exported routines. * Exported routines.
*---------------------------------------------------------*/ *---------------------------------------------------------*/
void initialize(void) void
initialize(void)
{ {
#ifdef ISN_DEBUG #ifdef ISN_DEBUG
if(!check_table(EAN13, EAN13_index)) if (!check_table(EAN13, EAN13_index))
elog(LOG, "EAN13 failed check"); elog(LOG, "EAN13 failed check");
if(!check_table(ISBN, ISBN_index)) if (!check_table(ISBN, ISBN_index))
elog(LOG, "ISBN failed check"); elog(LOG, "ISBN failed check");
if(!check_table(ISMN, ISMN_index)) if (!check_table(ISMN, ISMN_index))
elog(LOG, "ISMN failed check"); elog(LOG, "ISMN failed check");
if(!check_table(ISSN, ISSN_index)) if (!check_table(ISSN, ISSN_index))
elog(LOG, "ISSN failed check"); elog(LOG, "ISSN failed check");
if(!check_table(UPC, UPC_index)) if (!check_table(UPC, UPC_index))
elog(LOG, "UPC failed check"); elog(LOG, "UPC failed check");
#endif #endif
g_initialized = true; g_initialized = true;
@ -987,6 +1177,7 @@ Datum
is_valid(PG_FUNCTION_ARGS) is_valid(PG_FUNCTION_ARGS)
{ {
ean13 val = PG_GETARG_EAN13(0); ean13 val = PG_GETARG_EAN13(0);
PG_RETURN_BOOL((val & 1) == 0); PG_RETURN_BOOL((val & 1) == 0);
} }
@ -997,6 +1188,7 @@ Datum
make_valid(PG_FUNCTION_ARGS) make_valid(PG_FUNCTION_ARGS)
{ {
ean13 val = PG_GETARG_EAN13(0); ean13 val = PG_GETARG_EAN13(0);
val &= ~((ean13) 1); val &= ~((ean13) 1);
PG_RETURN_EAN13(val); PG_RETURN_EAN13(val);
} }

View File

@ -580,6 +580,6 @@ _ltree_consistent(PG_FUNCTION_ARGS)
/* internal error */ /* internal error */
elog(ERROR, "unrecognized StrategyNumber: %d", strategy); elog(ERROR, "unrecognized StrategyNumber: %d", strategy);
} }
PG_FREE_IF_COPY(query,1); PG_FREE_IF_COPY(query, 1);
PG_RETURN_BOOL(res); PG_RETURN_BOOL(res);
} }

View File

@ -1,7 +1,7 @@
/* /*
* op function for ltree and lquery * op function for ltree and lquery
* Teodor Sigaev <teodor@stack.net> * 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" #include "ltree.h"
@ -46,7 +46,7 @@ getlexeme(char *start, char *end, int *len)
} }
bool bool
compare_subnode(ltree_level * t, char *qn, int len, int (*cmpptr) (const char *, const char *, size_t), bool anyend) compare_subnode(ltree_level * t, char *qn, int len, int (*cmpptr) (const char *, const char *, size_t), bool anyend)
{ {
char *endt = t->name + t->len; char *endt = t->name + t->len;
char *endq = qn + len; char *endq = qn + len;

View File

@ -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__ #ifndef __LTREE_H__
#define __LTREE_H__ #define __LTREE_H__

View File

@ -1,7 +1,7 @@
/* /*
* GiST support for ltree * GiST support for ltree
* Teodor Sigaev <teodor@stack.net> * 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" #include "ltree.h"
@ -457,8 +457,10 @@ gist_isparent(ltree_gist * key, ltree * query)
} }
static ltree * static ltree *
copy_ltree( ltree *src ) { copy_ltree(ltree * src)
ltree *dst = (ltree*)palloc(src->len); {
ltree *dst = (ltree *) palloc(src->len);
memcpy(dst, src, src->len); memcpy(dst, src, src->len);
return dst; return dst;
} }
@ -711,6 +713,6 @@ ltree_consistent(PG_FUNCTION_ARGS)
elog(ERROR, "unrecognized StrategyNumber: %d", strategy); elog(ERROR, "unrecognized StrategyNumber: %d", strategy);
} }
PG_FREE_IF_COPY(query,1); PG_FREE_IF_COPY(query, 1);
PG_RETURN_BOOL(res); PG_RETURN_BOOL(res);
} }

View File

@ -1,7 +1,7 @@
/* /*
* op function for ltree * op function for ltree
* Teodor Sigaev <teodor@stack.net> * 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" #include "ltree.h"
@ -620,8 +620,8 @@ ltreeparentsel(PG_FUNCTION_ARGS)
/* /*
* If the histogram is large enough, see what fraction of it the * If the histogram is large enough, see what fraction of it the
* constant is "<@" to, and assume that's representative of the * constant is "<@" to, and assume that's representative of the
* non-MCV population. Otherwise use the default selectivity for * non-MCV population. Otherwise use the default selectivity for the
* the non-MCV population. * non-MCV population.
*/ */
selec = histogram_selectivity(&vardata, &contproc, selec = histogram_selectivity(&vardata, &contproc,
constval, varonleft, constval, varonleft,

View File

@ -3,7 +3,7 @@
* pg_buffercache_pages.c * pg_buffercache_pages.c
* display some contents of the buffer cache * 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" #include "postgres.h"
@ -123,9 +123,9 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
/* /*
* To get a consistent picture of the buffer state, we must lock * To get a consistent picture of the buffer state, we must lock all
* all partitions of the buffer map. Needless to say, this is * partitions of the buffer map. Needless to say, this is horrible
* horrible for concurrency... * for concurrency...
*/ */
for (i = 0; i < NUM_BUFFER_PARTITIONS; i++) for (i = 0; i < NUM_BUFFER_PARTITIONS; i++)
LWLockAcquire(FirstBufMappingLock + i, LW_SHARED); LWLockAcquire(FirstBufMappingLock + i, LW_SHARED);

View File

@ -3,7 +3,7 @@
* pg_freespacemap.c * pg_freespacemap.c
* display some contents of the free space relation and page maps. * 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" #include "postgres.h"
@ -138,8 +138,8 @@ pg_freespacemap_pages(PG_FUNCTION_ARGS)
fctx->tupdesc = BlessTupleDesc(tupledesc); fctx->tupdesc = BlessTupleDesc(tupledesc);
/* /*
* Allocate numPages worth of FreeSpacePagesRec records, this is * Allocate numPages worth of FreeSpacePagesRec records, this is an
* an upper bound. * upper bound.
*/ */
fctx->record = (FreeSpacePagesRec *) palloc(sizeof(FreeSpacePagesRec) * numPages); fctx->record = (FreeSpacePagesRec *) palloc(sizeof(FreeSpacePagesRec) * numPages);
@ -147,8 +147,8 @@ pg_freespacemap_pages(PG_FUNCTION_ARGS)
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
/* /*
* Lock free space map and scan though all the relations. * Lock free space map and scan though all the relations. For each
* For each relation, gets all its mapped pages. * relation, gets all its mapped pages.
*/ */
LWLockAcquire(FreeSpaceLock, LW_EXCLUSIVE); LWLockAcquire(FreeSpaceLock, LW_EXCLUSIVE);
@ -313,8 +313,8 @@ pg_freespacemap_relations(PG_FUNCTION_ARGS)
fctx->tupdesc = BlessTupleDesc(tupledesc); fctx->tupdesc = BlessTupleDesc(tupledesc);
/* /*
* Allocate numRelations worth of FreeSpaceRelationsRec records, * Allocate numRelations worth of FreeSpaceRelationsRec records, this
* this is also an upper bound. * is also an upper bound.
*/ */
fctx->record = (FreeSpaceRelationsRec *) palloc(sizeof(FreeSpaceRelationsRec) * numRelations); fctx->record = (FreeSpaceRelationsRec *) palloc(sizeof(FreeSpaceRelationsRec) * numRelations);
@ -333,7 +333,7 @@ pg_freespacemap_relations(PG_FUNCTION_ARGS)
fctx->record[i].reltablespace = fsmrel->key.spcNode; fctx->record[i].reltablespace = fsmrel->key.spcNode;
fctx->record[i].reldatabase = fsmrel->key.dbNode; fctx->record[i].reldatabase = fsmrel->key.dbNode;
fctx->record[i].relfilenode = fsmrel->key.relNode; fctx->record[i].relfilenode = fsmrel->key.relNode;
fctx->record[i].avgrequest = (int64)fsmrel->avgRequest; fctx->record[i].avgrequest = (int64) fsmrel->avgRequest;
fctx->record[i].interestingpages = fsmrel->interestingPages; fctx->record[i].interestingpages = fsmrel->interestingPages;
fctx->record[i].storedpages = fsmrel->storedPages; fctx->record[i].storedpages = fsmrel->storedPages;
fctx->record[i].nextpage = fsmrel->nextPage; fctx->record[i].nextpage = fsmrel->nextPage;
@ -368,6 +368,7 @@ pg_freespacemap_relations(PG_FUNCTION_ARGS)
nulls[1] = false; nulls[1] = false;
values[2] = ObjectIdGetDatum(record->relfilenode); values[2] = ObjectIdGetDatum(record->relfilenode);
nulls[2] = false; nulls[2] = false;
/* /*
* avgrequest isn't meaningful for an index * avgrequest isn't meaningful for an index
*/ */

View File

@ -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 * pgbench: a simple benchmark program for PostgreSQL
* written by Tatsuo Ishii * written by Tatsuo Ishii
@ -1009,14 +1009,16 @@ process_file(char *filename)
while (isspace((unsigned char) buf[i])) while (isspace((unsigned char) buf[i]))
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]); commands = process_commands(&buf[i]);
if (commands == NULL) if (commands == NULL)
{ {
fclose(fd); fclose(fd);
return false; return false;
} }
} else }
else
continue; continue;
my_commands[lineno] = commands; my_commands[lineno] = commands;

View File

@ -2,7 +2,7 @@
* Written by Solar Designer and placed in the public domain. * Written by Solar Designer and placed in the public domain.
* See crypt_blowfish.c for more information. * 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 * This file contains salt generation functions for the traditional and
* other common crypt(3) algorithms, except for bcrypt which is defined * other common crypt(3) algorithms, except for bcrypt which is defined
@ -64,9 +64,9 @@ _crypt_gensalt_extended_rn(unsigned long count,
output[2] = _crypt_itoa64[(count >> 6) & 0x3f]; output[2] = _crypt_itoa64[(count >> 6) & 0x3f];
output[3] = _crypt_itoa64[(count >> 12) & 0x3f]; output[3] = _crypt_itoa64[(count >> 12) & 0x3f];
output[4] = _crypt_itoa64[(count >> 18) & 0x3f]; output[4] = _crypt_itoa64[(count >> 18) & 0x3f];
value = (unsigned long)(unsigned char) input[0] | value = (unsigned long) (unsigned char) input[0] |
((unsigned long)(unsigned char) input[1] << 8) | ((unsigned long) (unsigned char) input[1] << 8) |
((unsigned long)(unsigned char) input[2] << 16); ((unsigned long) (unsigned char) input[2] << 16);
output[5] = _crypt_itoa64[value & 0x3f]; output[5] = _crypt_itoa64[value & 0x3f];
output[6] = _crypt_itoa64[(value >> 6) & 0x3f]; output[6] = _crypt_itoa64[(value >> 6) & 0x3f];
output[7] = _crypt_itoa64[(value >> 12) & 0x3f]; output[7] = _crypt_itoa64[(value >> 12) & 0x3f];
@ -92,9 +92,9 @@ _crypt_gensalt_md5_rn(unsigned long count,
output[0] = '$'; output[0] = '$';
output[1] = '1'; output[1] = '1';
output[2] = '$'; output[2] = '$';
value = (unsigned long)(unsigned char) input[0] | value = (unsigned long) (unsigned char) input[0] |
((unsigned long)(unsigned char) input[1] << 8) | ((unsigned long) (unsigned char) input[1] << 8) |
((unsigned long)(unsigned char) input[2] << 16); ((unsigned long) (unsigned char) input[2] << 16);
output[3] = _crypt_itoa64[value & 0x3f]; output[3] = _crypt_itoa64[value & 0x3f];
output[4] = _crypt_itoa64[(value >> 6) & 0x3f]; output[4] = _crypt_itoa64[(value >> 6) & 0x3f];
output[5] = _crypt_itoa64[(value >> 12) & 0x3f]; output[5] = _crypt_itoa64[(value >> 12) & 0x3f];
@ -103,9 +103,9 @@ _crypt_gensalt_md5_rn(unsigned long count,
if (size >= 6 && output_size >= 3 + 4 + 4 + 1) if (size >= 6 && output_size >= 3 + 4 + 4 + 1)
{ {
value = (unsigned long)(unsigned char) input[3] | value = (unsigned long) (unsigned char) input[3] |
((unsigned long)(unsigned char) input[4] << 8) | ((unsigned long) (unsigned char) input[4] << 8) |
((unsigned long)(unsigned char) input[5] << 16); ((unsigned long) (unsigned char) input[5] << 16);
output[7] = _crypt_itoa64[value & 0x3f]; output[7] = _crypt_itoa64[value & 0x3f];
output[8] = _crypt_itoa64[(value >> 6) & 0x3f]; output[8] = _crypt_itoa64[(value >> 6) & 0x3f];
output[9] = _crypt_itoa64[(value >> 12) & 0x3f]; output[9] = _crypt_itoa64[(value >> 12) & 0x3f];

View File

@ -8,7 +8,7 @@
* *
* $FreeBSD: src/lib/libcrypt/crypt-md5.c,v 1.5 1999/12/17 20:21:45 peter Exp $ * $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" #include "postgres.h"

View File

@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * 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" #include "postgres.h"

File diff suppressed because it is too large Load Diff

View File

@ -26,7 +26,7 @@
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. 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_ #ifndef IMATH_H_
#define IMATH_H_ #define IMATH_H_
@ -39,19 +39,23 @@
typedef unsigned char mp_sign; typedef unsigned char mp_sign;
typedef unsigned int mp_size; typedef unsigned int mp_size;
typedef int mp_result; typedef int mp_result;
#ifdef USE_LONG_LONG #ifdef USE_LONG_LONG
typedef uint32 mp_digit; typedef uint32 mp_digit;
typedef uint64 mp_word; typedef uint64 mp_word;
#define MP_DIGIT_MAX 0xFFFFFFFFULL #define MP_DIGIT_MAX 0xFFFFFFFFULL
#define MP_WORD_MAX 0xFFFFFFFFFFFFFFFFULL #define MP_WORD_MAX 0xFFFFFFFFFFFFFFFFULL
#else #else
typedef uint16 mp_digit; typedef uint16 mp_digit;
typedef uint32 mp_word; typedef uint32 mp_word;
#define MP_DIGIT_MAX 0xFFFFUL #define MP_DIGIT_MAX 0xFFFFUL
#define MP_WORD_MAX 0xFFFFFFFFUL #define MP_WORD_MAX 0xFFFFFFFFUL
#endif #endif
typedef struct mpz { typedef struct mpz
{
mp_digit *digits; mp_digit *digits;
mp_size alloc; mp_size alloc;
mp_size used; 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_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_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_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_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_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_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 */ 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)) #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(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 */ 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 */ /* Returns k >= 0 such that z = 2^k, if one exists; otherwise < 0 */
int mp_int_is_pow2(mp_int z); 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_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_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_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 m, mp_int mu,
mp_int c); /* c = a^b (mod m) */ mp_int c); /* c = a^b (mod m) */
mp_result mp_int_redux_const(mp_int m, mp_int c); 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_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_int x, mp_int y); /* c = ax + by */
mp_result mp_int_sqrt(mp_int a, mp_int c); /* c = floor(sqrt(q)) */ mp_result mp_int_sqrt(mp_int a, mp_int c); /* c = floor(sqrt(q)) */
@ -196,7 +209,7 @@ const char *mp_error_string(mp_result res);
#if 0 #if 0
void s_print(char *tag, mp_int z); void s_print(char *tag, mp_int z);
void s_print_buf(char *tag, mp_digit *buf, mp_size num); void s_print_buf(char *tag, mp_digit * buf, mp_size num);
#endif #endif
#endif /* end IMATH_H_ */ #endif /* end IMATH_H_ */

View File

@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * 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" #include "postgres.h"
@ -314,4 +314,3 @@ init_sha512(PX_MD * md)
md->reset(md); md->reset(md);
} }

View File

@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * 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" #include "postgres.h"

View File

@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * 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" #include "postgres.h"
@ -58,7 +58,6 @@
*/ */
#include <openssl/aes.h> #include <openssl/aes.h>
#else /* old OPENSSL */ #else /* old OPENSSL */
/* /*
@ -121,29 +120,32 @@
* Emulate newer digest API. * 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)); 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)); memset(ctx, 0, sizeof(*ctx));
return 1; 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); EVP_DigestInit(ctx, md);
return 1; 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); EVP_DigestFinal(ctx, res, len);
return 1; return 1;
} }
#endif /* old OpenSSL */ #endif /* old OpenSSL */
/* /*
@ -154,9 +156,10 @@ static int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *res, unsigned int
#include "sha2.c" #include "sha2.c"
#include "internal-sha2.c" #include "internal-sha2.c"
typedef void (*init_f)(PX_MD *md); 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; init_f init = NULL;
@ -175,7 +178,6 @@ static int compat_find_digest(const char *name, PX_MD **res)
init(*res); init(*res);
return 0; return 0;
} }
#else #else
#define compat_find_digest(name, res) (PXE_NO_HASH) #define compat_find_digest(name, res) (PXE_NO_HASH)
#endif #endif
@ -184,7 +186,8 @@ static int compat_find_digest(const char *name, PX_MD **res)
* Hashes * Hashes
*/ */
typedef struct OSSLDigest { typedef struct OSSLDigest
{
const EVP_MD *algo; const EVP_MD *algo;
EVP_MD_CTX ctx; EVP_MD_CTX ctx;
} OSSLDigest; } OSSLDigest;
@ -192,21 +195,23 @@ typedef struct OSSLDigest {
static unsigned static unsigned
digest_result_size(PX_MD * h) digest_result_size(PX_MD * h)
{ {
OSSLDigest *digest = (OSSLDigest *)h->p.ptr; OSSLDigest *digest = (OSSLDigest *) h->p.ptr;
return EVP_MD_CTX_size(&digest->ctx); return EVP_MD_CTX_size(&digest->ctx);
} }
static unsigned static unsigned
digest_block_size(PX_MD * h) digest_block_size(PX_MD * h)
{ {
OSSLDigest *digest = (OSSLDigest *)h->p.ptr; OSSLDigest *digest = (OSSLDigest *) h->p.ptr;
return EVP_MD_CTX_block_size(&digest->ctx); return EVP_MD_CTX_block_size(&digest->ctx);
} }
static void static void
digest_reset(PX_MD * h) digest_reset(PX_MD * h)
{ {
OSSLDigest *digest = (OSSLDigest *)h->p.ptr; OSSLDigest *digest = (OSSLDigest *) h->p.ptr;
EVP_DigestInit_ex(&digest->ctx, digest->algo, NULL); EVP_DigestInit_ex(&digest->ctx, digest->algo, NULL);
} }
@ -214,7 +219,7 @@ digest_reset(PX_MD * h)
static void static void
digest_update(PX_MD * h, const uint8 *data, unsigned dlen) digest_update(PX_MD * h, const uint8 *data, unsigned dlen)
{ {
OSSLDigest *digest = (OSSLDigest *)h->p.ptr; OSSLDigest *digest = (OSSLDigest *) h->p.ptr;
EVP_DigestUpdate(&digest->ctx, data, dlen); EVP_DigestUpdate(&digest->ctx, data, dlen);
} }
@ -222,7 +227,7 @@ digest_update(PX_MD * h, const uint8 *data, unsigned dlen)
static void static void
digest_finish(PX_MD * h, uint8 *dst) digest_finish(PX_MD * h, uint8 *dst)
{ {
OSSLDigest *digest = (OSSLDigest *)h->p.ptr; OSSLDigest *digest = (OSSLDigest *) h->p.ptr;
EVP_DigestFinal_ex(&digest->ctx, dst, NULL); EVP_DigestFinal_ex(&digest->ctx, dst, NULL);
} }
@ -230,7 +235,7 @@ digest_finish(PX_MD * h, uint8 *dst)
static void static void
digest_free(PX_MD * h) digest_free(PX_MD * h)
{ {
OSSLDigest *digest = (OSSLDigest *)h->p.ptr; OSSLDigest *digest = (OSSLDigest *) h->p.ptr;
EVP_MD_CTX_cleanup(&digest->ctx); EVP_MD_CTX_cleanup(&digest->ctx);
@ -560,7 +565,7 @@ ossl_des3_ecb_encrypt(PX_Cipher * c, const uint8 *data, unsigned dlen,
ossldata *od = c->ptr; ossldata *od = c->ptr;
for (i = 0; i < dlen / bs; i++) for (i = 0; i < dlen / bs; i++)
DES_ecb3_encrypt((void *)(data + i * bs), (void *)(res + i * bs), DES_ecb3_encrypt((void *) (data + i * bs), (void *) (res + i * bs),
&od->u.des3.k1, &od->u.des3.k2, &od->u.des3.k3, 1); &od->u.des3.k1, &od->u.des3.k2, &od->u.des3.k3, 1);
return 0; return 0;
} }
@ -574,7 +579,7 @@ ossl_des3_ecb_decrypt(PX_Cipher * c, const uint8 *data, unsigned dlen,
ossldata *od = c->ptr; ossldata *od = c->ptr;
for (i = 0; i < dlen / bs; i++) for (i = 0; i < dlen / bs; i++)
DES_ecb3_encrypt((void *)(data + i * bs), (void *)(res + i * bs), DES_ecb3_encrypt((void *) (data + i * bs), (void *) (res + i * bs),
&od->u.des3.k1, &od->u.des3.k2, &od->u.des3.k3, 0); &od->u.des3.k1, &od->u.des3.k2, &od->u.des3.k3, 0);
return 0; return 0;
} }

View File

@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * 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" #include "postgres.h"
@ -504,7 +504,7 @@ pg_random_bytes(PG_FUNCTION_ARGS)
VARATT_SIZEP(res) = VARHDRSZ + len; VARATT_SIZEP(res) = VARHDRSZ + len;
/* generate result */ /* generate result */
err = px_get_random_bytes((uint8*)VARDATA(res), len); err = px_get_random_bytes((uint8 *) VARDATA(res), len);
if (err < 0) if (err < 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),

View File

@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * 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" #include "postgres.h"
@ -36,14 +36,17 @@
#include "mbuf.h" #include "mbuf.h"
#include "pgp.h" #include "pgp.h"
static mpz_t *mp_new() static mpz_t *
mp_new()
{ {
mpz_t *mp = mp_int_alloc(); mpz_t *mp = mp_int_alloc();
mp_int_init_size(mp, 256); mp_int_init_size(mp, 256);
return mp; return mp;
} }
static void mp_clear_free(mpz_t *a) static void
mp_clear_free(mpz_t * a)
{ {
if (!a) if (!a)
return; 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; int err;
unsigned bytes = (bits + 7) / 8; unsigned bytes = (bits + 7) / 8;
@ -61,16 +65,19 @@ static int mp_px_rand(uint32 bits, mpz_t *res)
buf = px_alloc(bytes); buf = px_alloc(bytes);
err = px_get_random_bytes(buf, bytes); err = px_get_random_bytes(buf, bytes);
if (err < 0) { if (err < 0)
{
px_free(buf); px_free(buf);
return err; return err;
} }
/* clear unnecessary bits and set last bit to one */ /* clear unnecessary bits and set last bit to one */
if (last_bits) { if (last_bits)
{
buf[0] >>= 8 - last_bits; buf[0] >>= 8 - last_bits;
buf[0] |= 1 << (last_bits - 1); buf[0] |= 1 << (last_bits - 1);
} else }
else
buf[0] |= 1 << 7; buf[0] |= 1 << 7;
mp_int_read_unsigned(res, buf, bytes); mp_int_read_unsigned(res, buf, bytes);
@ -80,9 +87,11 @@ static int mp_px_rand(uint32 bits, mpz_t *res)
return 0; 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(); mpz_t *tmp = mp_new();
mp_int_mul(a, b, tmp); mp_int_mul(a, b, tmp);
mp_int_mod(tmp, p, res); mp_int_mod(tmp, p, res);
mp_clear_free(tmp); mp_clear_free(tmp);
@ -92,6 +101,7 @@ static mpz_t *
mpi_to_bn(PGP_MPI * n) mpi_to_bn(PGP_MPI * n)
{ {
mpz_t *bn = mp_new(); mpz_t *bn = mp_new();
mp_int_read_unsigned(bn, n->data, n->bytes); mp_int_read_unsigned(bn, n->data, n->bytes);
if (!bn) if (!bn)
@ -107,7 +117,7 @@ mpi_to_bn(PGP_MPI * n)
} }
static PGP_MPI * static PGP_MPI *
bn_to_mpi(mpz_t *bn) bn_to_mpi(mpz_t * bn)
{ {
int res; int res;
PGP_MPI *n; PGP_MPI *n;

View File

@ -33,7 +33,7 @@
* *
* $From: sha2.c,v 1.1 2001/11/08 00:01:51 adg Exp adg $ * $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" #include "postgres.h"
@ -534,7 +534,7 @@ SHA256_Update(SHA256_CTX * context, const uint8 *data, size_t len)
} }
static void static void
SHA256_Last(SHA256_CTX *context) SHA256_Last(SHA256_CTX * context)
{ {
unsigned int usedspace; unsigned int usedspace;
@ -1023,4 +1023,3 @@ SHA224_Final(uint8 digest[], SHA224_CTX * context)
/* Clean up state data: */ /* Clean up state data: */
memset(context, 0, sizeof(*context)); memset(context, 0, sizeof(*context));
} }

View File

@ -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 * Copyright (c) 2005-2006 Tatsuo Ishii
* *
@ -63,7 +63,8 @@ extern Datum pgrowlocks(PG_FUNCTION_ARGS);
*/ */
#undef MAKERANGEVARFROMNAMELIST_HAS_TWO_ARGS #undef MAKERANGEVARFROMNAMELIST_HAS_TWO_ARGS
typedef struct { typedef struct
{
Relation rel; Relation rel;
HeapScanDesc scan; HeapScanDesc scan;
int ncolumns; int ncolumns;
@ -97,7 +98,6 @@ pgrowlocks(PG_FUNCTION_ARGS)
relname = PG_GETARG_TEXT_P(0); relname = PG_GETARG_TEXT_P(0);
#ifdef MAKERANGEVARFROMNAMELIST_HAS_TWO_ARGS #ifdef MAKERANGEVARFROMNAMELIST_HAS_TWO_ARGS
relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname, "pgrowlocks")); relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname, "pgrowlocks"));
#else #else
relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
#endif #endif
@ -114,7 +114,7 @@ pgrowlocks(PG_FUNCTION_ARGS)
funcctx = SRF_PERCALL_SETUP(); funcctx = SRF_PERCALL_SETUP();
attinmeta = funcctx->attinmeta; attinmeta = funcctx->attinmeta;
mydata = (MyData *)funcctx->user_fctx; mydata = (MyData *) funcctx->user_fctx;
scan = mydata->scan; scan = mydata->scan;
/* scan the relation */ /* scan the relation */
@ -133,7 +133,7 @@ pgrowlocks(PG_FUNCTION_ARGS)
values = (char **) palloc(mydata->ncolumns * sizeof(char *)); values = (char **) palloc(mydata->ncolumns * sizeof(char *));
i = 0; i = 0;
values[i++] = (char *)DirectFunctionCall1(tidout, PointerGetDatum(&tuple->t_self)); values[i++] = (char *) DirectFunctionCall1(tidout, PointerGetDatum(&tuple->t_self));
#ifdef HEAP_XMAX_SHARED_LOCK #ifdef HEAP_XMAX_SHARED_LOCK
if (tuple->t_data->t_infomask & HEAP_XMAX_SHARED_LOCK) if (tuple->t_data->t_infomask & HEAP_XMAX_SHARED_LOCK)
@ -143,7 +143,7 @@ pgrowlocks(PG_FUNCTION_ARGS)
#else #else
values[i++] = pstrdup("Exclusive"); values[i++] = pstrdup("Exclusive");
#endif #endif
values[i] = palloc(NCHARS*sizeof(char)); values[i] = palloc(NCHARS * sizeof(char));
snprintf(values[i++], NCHARS, "%d", HeapTupleHeaderGetXmax(tuple->t_data)); snprintf(values[i++], NCHARS, "%d", HeapTupleHeaderGetXmax(tuple->t_data));
#ifdef HEAP_XMAX_SHARED_LOCK #ifdef HEAP_XMAX_SHARED_LOCK
if (tuple->t_data->t_infomask & HEAP_XMAX_IS_MULTI) if (tuple->t_data->t_infomask & HEAP_XMAX_IS_MULTI)
@ -160,12 +160,12 @@ pgrowlocks(PG_FUNCTION_ARGS)
elog(ERROR, "GetMultiXactIdMembers returns error"); elog(ERROR, "GetMultiXactIdMembers returns error");
} }
values[i] = palloc(NCHARS*nxids); values[i] = palloc(NCHARS * nxids);
values[i+1] = palloc(NCHARS*nxids); values[i + 1] = palloc(NCHARS * nxids);
strcpy(values[i], "{"); strcpy(values[i], "{");
strcpy(values[i+1], "{"); strcpy(values[i + 1], "{");
for (j=0;j<nxids;j++) for (j = 0; j < nxids; j++)
{ {
char buf[NCHARS]; char buf[NCHARS];
@ -174,31 +174,30 @@ pgrowlocks(PG_FUNCTION_ARGS)
if (isValidXid) if (isValidXid)
{ {
strcat(values[i], ","); strcat(values[i], ",");
strcat(values[i+1], ","); strcat(values[i + 1], ",");
} }
snprintf(buf, NCHARS, "%d", xids[j]); snprintf(buf, NCHARS, "%d", xids[j]);
strcat(values[i], buf); strcat(values[i], buf);
snprintf(buf, NCHARS, "%d", BackendXidGetPid(xids[j])); snprintf(buf, NCHARS, "%d", BackendXidGetPid(xids[j]));
strcat(values[i+1], buf); strcat(values[i + 1], buf);
isValidXid = 1; isValidXid = 1;
} }
} }
strcat(values[i], "}"); strcat(values[i], "}");
strcat(values[i+1], "}"); strcat(values[i + 1], "}");
i++; i++;
} }
else else
{ {
values[i++] = pstrdup("false"); values[i++] = pstrdup("false");
values[i] = palloc(NCHARS*sizeof(char)); values[i] = palloc(NCHARS * sizeof(char));
snprintf(values[i++], NCHARS, "{%d}", HeapTupleHeaderGetXmax(tuple->t_data)); snprintf(values[i++], NCHARS, "{%d}", HeapTupleHeaderGetXmax(tuple->t_data));
values[i] = palloc(NCHARS*sizeof(char)); values[i] = palloc(NCHARS * sizeof(char));
snprintf(values[i++], NCHARS, "{%d}", BackendXidGetPid(HeapTupleHeaderGetXmax(tuple->t_data))); snprintf(values[i++], NCHARS, "{%d}", BackendXidGetPid(HeapTupleHeaderGetXmax(tuple->t_data)));
} }
#else #else
values[i++] = pstrdup("false"); values[i++] = pstrdup("false");
values[i++] = pstrdup("{}"); values[i++] = pstrdup("{}");

View File

@ -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 * Copyright (c) 2001,2002 Tatsuo Ishii
* *
@ -59,28 +59,28 @@ typedef struct pgstattuple_type
uint64 free_space; /* free/reusable space in bytes */ uint64 free_space; /* free/reusable space in bytes */
} pgstattuple_type; } pgstattuple_type;
typedef void (*pgstat_page)(pgstattuple_type *, Relation, BlockNumber); typedef void (*pgstat_page) (pgstattuple_type *, Relation, BlockNumber);
static Datum build_pgstattuple_type(pgstattuple_type *stat, static Datum build_pgstattuple_type(pgstattuple_type * stat,
FunctionCallInfo fcinfo); FunctionCallInfo fcinfo);
static Datum pgstat_relation(Relation rel, FunctionCallInfo fcinfo); static Datum pgstat_relation(Relation rel, FunctionCallInfo fcinfo);
static Datum pgstat_heap(Relation rel, FunctionCallInfo fcinfo); static Datum pgstat_heap(Relation rel, FunctionCallInfo fcinfo);
static void pgstat_btree_page(pgstattuple_type *stat, static void pgstat_btree_page(pgstattuple_type * stat,
Relation rel, BlockNumber blkno); Relation rel, BlockNumber blkno);
static void pgstat_hash_page(pgstattuple_type *stat, static void pgstat_hash_page(pgstattuple_type * stat,
Relation rel, BlockNumber blkno); Relation rel, BlockNumber blkno);
static void pgstat_gist_page(pgstattuple_type *stat, static void pgstat_gist_page(pgstattuple_type * stat,
Relation rel, BlockNumber blkno); Relation rel, BlockNumber blkno);
static Datum pgstat_index(Relation rel, BlockNumber start, static Datum pgstat_index(Relation rel, BlockNumber start,
pgstat_page pagefn, FunctionCallInfo fcinfo); pgstat_page pagefn, FunctionCallInfo fcinfo);
static void pgstat_index_page(pgstattuple_type *stat, Page page, static void pgstat_index_page(pgstattuple_type * stat, Page page,
OffsetNumber minoff, OffsetNumber maxoff); OffsetNumber minoff, OffsetNumber maxoff);
/* /*
* build_pgstattuple_type -- build a pgstattuple_type tuple * build_pgstattuple_type -- build a pgstattuple_type tuple
*/ */
static Datum static Datum
build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo) build_pgstattuple_type(pgstattuple_type * stat, FunctionCallInfo fcinfo)
{ {
#define NCOLUMNS 9 #define NCOLUMNS 9
#define NCHARS 32 #define NCHARS 32
@ -190,7 +190,7 @@ pgstat_relation(Relation rel, FunctionCallInfo fcinfo)
{ {
const char *err; const char *err;
switch(rel->rd_rel->relkind) switch (rel->rd_rel->relkind)
{ {
case RELKIND_RELATION: case RELKIND_RELATION:
case RELKIND_TOASTVALUE: case RELKIND_TOASTVALUE:
@ -198,7 +198,7 @@ pgstat_relation(Relation rel, FunctionCallInfo fcinfo)
case RELKIND_SEQUENCE: case RELKIND_SEQUENCE:
return pgstat_heap(rel, fcinfo); return pgstat_heap(rel, fcinfo);
case RELKIND_INDEX: case RELKIND_INDEX:
switch(rel->rd_rel->relam) switch (rel->rd_rel->relam)
{ {
case BTREE_AM_OID: case BTREE_AM_OID:
return pgstat_index(rel, BTREE_METAPAGE + 1, return pgstat_index(rel, BTREE_METAPAGE + 1,
@ -247,7 +247,7 @@ pgstat_heap(Relation rel, FunctionCallInfo fcinfo)
BlockNumber block = 0; /* next block to count free space in */ BlockNumber block = 0; /* next block to count free space in */
BlockNumber tupblock; BlockNumber tupblock;
Buffer buffer; Buffer buffer;
pgstattuple_type stat = { 0 }; pgstattuple_type stat = {0};
scan = heap_beginscan(rel, SnapshotAny, 0, NULL); scan = heap_beginscan(rel, SnapshotAny, 0, NULL);
@ -302,7 +302,7 @@ pgstat_heap(Relation rel, FunctionCallInfo fcinfo)
relation_close(rel, AccessShareLock); relation_close(rel, AccessShareLock);
stat.table_len = (uint64) nblocks * BLCKSZ; stat.table_len = (uint64) nblocks *BLCKSZ;
return build_pgstattuple_type(&stat, fcinfo); return build_pgstattuple_type(&stat, fcinfo);
} }
@ -311,7 +311,7 @@ pgstat_heap(Relation rel, FunctionCallInfo fcinfo)
* pgstat_btree_page -- check tuples in a btree page * pgstat_btree_page -- check tuples in a btree page
*/ */
static void static void
pgstat_btree_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno) pgstat_btree_page(pgstattuple_type * stat, Relation rel, BlockNumber blkno)
{ {
Buffer buf; Buffer buf;
Page page; Page page;
@ -329,6 +329,7 @@ pgstat_btree_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno)
else else
{ {
BTPageOpaque opaque; BTPageOpaque opaque;
opaque = (BTPageOpaque) PageGetSpecialPointer(page); opaque = (BTPageOpaque) PageGetSpecialPointer(page);
if (opaque->btpo_flags & (BTP_DELETED | BTP_HALF_DEAD)) if (opaque->btpo_flags & (BTP_DELETED | BTP_HALF_DEAD))
{ {
@ -353,7 +354,7 @@ pgstat_btree_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno)
* pgstat_hash_page -- check tuples in a hash page * pgstat_hash_page -- check tuples in a hash page
*/ */
static void static void
pgstat_hash_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno) pgstat_hash_page(pgstattuple_type * stat, Relation rel, BlockNumber blkno)
{ {
Buffer buf; Buffer buf;
Page page; Page page;
@ -365,6 +366,7 @@ pgstat_hash_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno)
if (PageGetSpecialSize(page) == MAXALIGN(sizeof(HashPageOpaqueData))) if (PageGetSpecialSize(page) == MAXALIGN(sizeof(HashPageOpaqueData)))
{ {
HashPageOpaque opaque; HashPageOpaque opaque;
opaque = (HashPageOpaque) PageGetSpecialPointer(page); opaque = (HashPageOpaque) PageGetSpecialPointer(page);
switch (opaque->hasho_flag) switch (opaque->hasho_flag)
{ {
@ -395,7 +397,7 @@ pgstat_hash_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno)
* pgstat_gist_page -- check tuples in a gist page * pgstat_gist_page -- check tuples in a gist page
*/ */
static void static void
pgstat_gist_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno) pgstat_gist_page(pgstattuple_type * stat, Relation rel, BlockNumber blkno)
{ {
Buffer buf; Buffer buf;
Page page; Page page;
@ -427,7 +429,7 @@ pgstat_index(Relation rel, BlockNumber start, pgstat_page pagefn,
{ {
BlockNumber nblocks; BlockNumber nblocks;
BlockNumber blkno; BlockNumber blkno;
pgstattuple_type stat = { 0 }; pgstattuple_type stat = {0};
blkno = start; blkno = start;
for (;;) for (;;)
@ -440,7 +442,8 @@ pgstat_index(Relation rel, BlockNumber start, pgstat_page pagefn,
/* Quit if we've scanned the whole relation */ /* Quit if we've scanned the whole relation */
if (blkno >= nblocks) if (blkno >= nblocks)
{ {
stat.table_len = (uint64) nblocks * BLCKSZ; stat.table_len = (uint64) nblocks *BLCKSZ;
break; break;
} }
@ -457,7 +460,7 @@ pgstat_index(Relation rel, BlockNumber start, pgstat_page pagefn,
* pgstat_index_page -- for generic index page * pgstat_index_page -- for generic index page
*/ */
static void static void
pgstat_index_page(pgstattuple_type *stat, Page page, pgstat_index_page(pgstattuple_type * stat, Page page,
OffsetNumber minoff, OffsetNumber maxoff) OffsetNumber minoff, OffsetNumber maxoff)
{ {
OffsetNumber i; OffsetNumber i;

View File

@ -4,7 +4,7 @@
* Written by Victor B. Wagner <vitus@cryptocom.ru>, Cryptocom LTD * Written by Victor B. Wagner <vitus@cryptocom.ru>, Cryptocom LTD
* This file is distributed under BSD-style license. * 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" #include "postgres.h"
@ -41,9 +41,10 @@ Datum ASN1_STRING_to_text(ASN1_STRING *str);
* is SSL session and false if it is local or non-ssl session. * is SSL session and false if it is local or non-ssl session.
*/ */
PG_FUNCTION_INFO_V1(ssl_is_used); 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); 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. * is SSL session and client certificate is verified, otherwise false.
*/ */
PG_FUNCTION_INFO_V1(ssl_client_cert_present); 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); 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. * SSL connection is established without sending client certificate.
*/ */
PG_FUNCTION_INFO_V1(ssl_client_serial); PG_FUNCTION_INFO_V1(ssl_client_serial);
Datum ssl_client_serial(PG_FUNCTION_ARGS) Datum
ssl_client_serial(PG_FUNCTION_ARGS)
{ {
Datum result; Datum result;
Port *port = MyProcPort; Port *port = MyProcPort;
@ -83,6 +86,7 @@ Datum ssl_client_serial(PG_FUNCTION_ARGS)
serial = X509_get_serialNumber(peer); serial = X509_get_serialNumber(peer);
b = ASN1_INTEGER_to_BN(serial, NULL); b = ASN1_INTEGER_to_BN(serial, NULL);
decimal = BN_bn2dec(b); decimal = BN_bn2dec(b);
BN_free(b); BN_free(b);
result = DirectFunctionCall3(numeric_in, result = DirectFunctionCall3(numeric_in,
CStringGetDatum(decimal), CStringGetDatum(decimal),
@ -106,17 +110,19 @@ Datum ssl_client_serial(PG_FUNCTION_ARGS)
* Returns Datum, which can be directly returned from a C language SQL * Returns Datum, which can be directly returned from a C language SQL
* function. * function.
*/ */
Datum ASN1_STRING_to_text(ASN1_STRING *str) Datum
ASN1_STRING_to_text(ASN1_STRING *str)
{ {
BIO *membuf = NULL; BIO *membuf = NULL;
size_t size, outlen; size_t size,
outlen;
char *sp; char *sp;
char *dp; char *dp;
text *result; text *result;
membuf = BIO_new(BIO_s_mem()); membuf = BIO_new(BIO_s_mem());
(void) BIO_set_close(membuf, BIO_CLOSE); (void) BIO_set_close(membuf, BIO_CLOSE);
ASN1_STRING_print_ex(membuf,str, ASN1_STRING_print_ex(membuf, str,
((ASN1_STRFLGS_RFC2253 & ~ASN1_STRFLGS_ESC_MSB) ((ASN1_STRFLGS_RFC2253 & ~ASN1_STRFLGS_ESC_MSB)
| ASN1_STRFLGS_UTF8_CONVERT)); | ASN1_STRFLGS_UTF8_CONVERT));
@ -124,7 +130,7 @@ Datum ASN1_STRING_to_text(ASN1_STRING *str)
BIO_write(membuf, &outlen, 1); BIO_write(membuf, &outlen, 1);
size = BIO_get_mem_data(membuf, &sp); size = BIO_get_mem_data(membuf, &sp);
dp = (char *) pg_do_encoding_conversion((unsigned char *) sp, dp = (char *) pg_do_encoding_conversion((unsigned char *) sp,
size-1, size - 1,
PG_UTF8, PG_UTF8,
GetDatabaseEncoding()); GetDatabaseEncoding());
outlen = strlen(dp); outlen = strlen(dp);
@ -151,13 +157,16 @@ Datum ASN1_STRING_to_text(ASN1_STRING *str)
* Returns result of ASN1_STRING_to_text applied to appropriate * Returns result of ASN1_STRING_to_text applied to appropriate
* part of name * 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 *sp;
char *string_fieldname; char *string_fieldname;
char *dp; char *dp;
size_t name_len = VARSIZE(fieldName) - VARHDRSZ; size_t name_len = VARSIZE(fieldName) - VARHDRSZ;
int nid, index, i; int nid,
index,
i;
ASN1_STRING *data; ASN1_STRING *data;
string_fieldname = palloc(name_len + 1); string_fieldname = palloc(name_len + 1);
@ -175,7 +184,7 @@ Datum X509_NAME_field_to_text(X509_NAME *name, text *fieldName)
pfree(string_fieldname); pfree(string_fieldname);
index = X509_NAME_get_index_by_NID(name, nid, -1); index = X509_NAME_get_index_by_NID(name, nid, -1);
if (index < 0) if (index < 0)
return (Datum)0; return (Datum) 0;
data = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, index)); data = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, index));
return ASN1_STRING_to_text(data); return ASN1_STRING_to_text(data);
} }
@ -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. * there is no field with such name in the certificate.
*/ */
PG_FUNCTION_INFO_V1(ssl_client_dn_field); 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); text *fieldname = PG_GETARG_TEXT_P(0);
Datum result; Datum result;
@ -232,7 +242,8 @@ Datum ssl_client_dn_field(PG_FUNCTION_ARGS)
* there is no field with such name in the certificate. * there is no field with such name in the certificate.
*/ */
PG_FUNCTION_INFO_V1(ssl_issuer_field); 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); text *fieldname = PG_GETARG_TEXT_P(0);
Datum result; Datum result;
@ -260,21 +271,25 @@ Datum ssl_issuer_field(PG_FUNCTION_ARGS)
* Returns: text datum which contains string representation of * Returns: text datum which contains string representation of
* X509_NAME * 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()); 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; X509_NAME_ENTRY *e;
ASN1_STRING *v; ASN1_STRING *v;
const char *field_name; const char *field_name;
size_t size,outlen; size_t size,
outlen;
char *sp; char *sp;
char *dp; char *dp;
text *result; text *result;
(void) BIO_set_close(membuf, BIO_CLOSE); (void) BIO_set_close(membuf, BIO_CLOSE);
for (i=0; i<count; i++) for (i = 0; i < count; i++)
{ {
e = X509_NAME_get_entry(name, i); e = X509_NAME_get_entry(name, i);
nid = OBJ_obj2nid(X509_NAME_ENTRY_get_object(e)); nid = OBJ_obj2nid(X509_NAME_ENTRY_get_object(e));
@ -283,17 +298,17 @@ Datum X509_NAME_to_text(X509_NAME *name)
if (!field_name) if (!field_name)
field_name = OBJ_nid2ln(nid); field_name = OBJ_nid2ln(nid);
BIO_printf(membuf, "/%s=", field_name); BIO_printf(membuf, "/%s=", field_name);
ASN1_STRING_print_ex(membuf,v, ASN1_STRING_print_ex(membuf, v,
((ASN1_STRFLGS_RFC2253 & ~ASN1_STRFLGS_ESC_MSB) ((ASN1_STRFLGS_RFC2253 & ~ASN1_STRFLGS_ESC_MSB)
| ASN1_STRFLGS_UTF8_CONVERT)); | ASN1_STRFLGS_UTF8_CONVERT));
} }
i=0; i = 0;
BIO_write(membuf, &i, 1); BIO_write(membuf, &i, 1);
size = BIO_get_mem_data(membuf, &sp); size = BIO_get_mem_data(membuf, &sp);
dp = (char *) pg_do_encoding_conversion((unsigned char *) sp, dp = (char *) pg_do_encoding_conversion((unsigned char *) sp,
size-1, size - 1,
PG_UTF8, PG_UTF8,
GetDatabaseEncoding()); GetDatabaseEncoding());
BIO_free(membuf); BIO_free(membuf);
@ -301,8 +316,10 @@ Datum X509_NAME_to_text(X509_NAME *name)
result = palloc(VARHDRSZ + outlen); result = palloc(VARHDRSZ + outlen);
memcpy(VARDATA(result), dp, 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) if (dp != sp)
pfree(dp); pfree(dp);
VARATT_SIZEP(result) = outlen + VARHDRSZ; VARATT_SIZEP(result) = outlen + VARHDRSZ;
@ -320,7 +337,8 @@ Datum X509_NAME_to_text(X509_NAME *name)
* Returns text datum. * Returns text datum.
*/ */
PG_FUNCTION_INFO_V1(ssl_client_dn); PG_FUNCTION_INFO_V1(ssl_client_dn);
Datum ssl_client_dn(PG_FUNCTION_ARGS) Datum
ssl_client_dn(PG_FUNCTION_ARGS)
{ {
if (!(MyProcPort->peer)) if (!(MyProcPort->peer))
PG_RETURN_NULL(); PG_RETURN_NULL();
@ -338,7 +356,8 @@ Datum ssl_client_dn(PG_FUNCTION_ARGS)
* Returns text datum. * Returns text datum.
*/ */
PG_FUNCTION_INFO_V1(ssl_issuer_dn); PG_FUNCTION_INFO_V1(ssl_issuer_dn);
Datum ssl_issuer_dn(PG_FUNCTION_ARGS) Datum
ssl_issuer_dn(PG_FUNCTION_ARGS)
{ {
if (!(MyProcPort->peer)) if (!(MyProcPort->peer))
PG_RETURN_NULL(); PG_RETURN_NULL();

View File

@ -166,10 +166,13 @@ get_oidnamespace(Oid funcoid)
/* if path is relative, take it as relative to share dir */ /* if path is relative, take it as relative to share dir */
char * char *
to_absfilename(char *filename) { to_absfilename(char *filename)
if (!is_absolute_path(filename)) { {
if (!is_absolute_path(filename))
{
char sharepath[MAXPGPATH]; char sharepath[MAXPGPATH];
char *absfn; char *absfn;
#ifdef WIN32 #ifdef WIN32
char delim = '\\'; char delim = '\\';
#else #else

View File

@ -14,7 +14,7 @@ text *mtextdup(text *in);
int text_cmp(text *a, text *b); int text_cmp(text *a, text *b);
char * to_absfilename(char *filename); char *to_absfilename(char *filename);
#define NEXTVAL(x) ( (text*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) ) #define NEXTVAL(x) ( (text*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) )
#define ARRNELEMS(x) ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x)) #define ARRNELEMS(x) ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x))

View File

@ -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 * interface functions to dictionary
@ -102,7 +102,8 @@ comparedict(const void *a, const void *b)
} }
static void static void
insertdict(Oid id) { insertdict(Oid id)
{
DictInfo newdict; DictInfo newdict;
if (DList.len == DList.reallen) if (DList.len == DList.reallen)
@ -201,7 +202,7 @@ lexize(PG_FUNCTION_ARGS)
*ptr; *ptr;
Datum *da; Datum *da;
ArrayType *a; ArrayType *a;
DictSubState dstate = { false, false, NULL }; DictSubState dstate = {false, false, NULL};
SET_FUNCOID(); SET_FUNCOID();
dict = finddict(PG_GETARG_OID(0)); dict = finddict(PG_GETARG_OID(0));
@ -215,7 +216,8 @@ lexize(PG_FUNCTION_ARGS)
) )
); );
if (dstate.getnext) { if (dstate.getnext)
{
dstate.isend = true; dstate.isend = true;
ptr = res = (TSLexeme *) DatumGetPointer( ptr = res = (TSLexeme *) DatumGetPointer(
FunctionCall4(&(dict->lexize_info), FunctionCall4(&(dict->lexize_info),

View File

@ -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__ #ifndef __DICT_H__
#define __DICT_H__ #define __DICT_H__
@ -30,10 +30,13 @@ DictInfo *finddict(Oid id);
Oid name2id_dict(text *name); Oid name2id_dict(text *name);
void reset_dict(void); void reset_dict(void);
typedef struct { typedef struct
bool isend; /* in: marks for lexize_info about text end is reached */ {
bool isend; /* in: marks for lexize_info about text end is
* reached */
bool getnext; /* out: dict wants next lexeme */ 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; } DictSubState;
/* simple parser of cfg string */ /* simple parser of cfg string */
@ -51,13 +54,8 @@ typedef struct
/* /*
* number of variant of split word , for example Word 'fotballklubber' * number of variant of split word , for example Word 'fotballklubber'
* (norwegian) has two varian to split: ( fotball, klubb ) and ( fot, * (norwegian) has two varian to split: ( fotball, klubb ) and ( fot,
* ball, klubb ). So, dictionary should return: * ball, klubb ). So, dictionary should return: nvariant lexeme 1
* nvariant lexeme * fotball 1 klubb 2 fot 2 ball 2 klubb
* 1 fotball
* 1 klubb
* 2 fot
* 2 ball
* 2 klubb
*/ */
uint16 nvariant; uint16 nvariant;
@ -74,7 +72,8 @@ typedef struct
* Lexize subsystem * Lexize subsystem
*/ */
typedef struct ParsedLex { typedef struct ParsedLex
{
int type; int type;
char *lemm; char *lemm;
int lenlemm; int lenlemm;
@ -82,12 +81,14 @@ typedef struct ParsedLex {
struct ParsedLex *next; struct ParsedLex *next;
} ParsedLex; } ParsedLex;
typedef struct ListParsedLex { typedef struct ListParsedLex
{
ParsedLex *head; ParsedLex *head;
ParsedLex *tail; ParsedLex *tail;
} ListParsedLex; } ListParsedLex;
typedef struct { typedef struct
{
TSCfgInfo *cfg; TSCfgInfo *cfg;
Oid curDictId; Oid curDictId;
int posDict; int posDict;
@ -96,16 +97,18 @@ typedef struct {
ListParsedLex towork; /* current list to work */ ListParsedLex towork; /* current list to work */
ListParsedLex waste; /* list of lexemes that already lexized */ 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; ParsedLex *lastRes;
TSLexeme *tmpRes; TSLexeme *tmpRes;
} LexizeData; } LexizeData;
void LexizeInit(LexizeData *ld, TSCfgInfo *cfg); void LexizeInit(LexizeData * ld, TSCfgInfo * cfg);
void LexizeAddLemm(LexizeData *ld, int type, char *lemm, int lenlemm); void LexizeAddLemm(LexizeData * ld, int type, char *lemm, int lenlemm);
TSLexeme* LexizeExec(LexizeData *ld, ParsedLex **correspondLexem); TSLexeme *LexizeExec(LexizeData * ld, ParsedLex ** correspondLexem);
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -18,26 +18,29 @@ PG_FUNCTION_INFO_V1(gin_extract_tsvector);
Datum gin_extract_tsvector(PG_FUNCTION_ARGS); Datum gin_extract_tsvector(PG_FUNCTION_ARGS);
Datum Datum
gin_extract_tsvector(PG_FUNCTION_ARGS) { gin_extract_tsvector(PG_FUNCTION_ARGS)
{
tsvector *vector = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); tsvector *vector = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
uint32 *nentries = (uint32*)PG_GETARG_POINTER(1); uint32 *nentries = (uint32 *) PG_GETARG_POINTER(1);
Datum *entries = NULL; Datum *entries = NULL;
*nentries = 0; *nentries = 0;
if ( vector->size > 0 ) { if (vector->size > 0)
{
int i; int i;
WordEntry *we = ARRPTR( vector ); WordEntry *we = ARRPTR(vector);
*nentries = (uint32)vector->size; *nentries = (uint32) vector->size;
entries = (Datum*)palloc( sizeof(Datum) * 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 ); {
text *txt = (text *) palloc(VARHDRSZ + we->len);
VARATT_SIZEP(txt) = VARHDRSZ + we->len; VARATT_SIZEP(txt) = VARHDRSZ + we->len;
memcpy( VARDATA(txt), STRPTR( vector ) + we->pos, we->len ); memcpy(VARDATA(txt), STRPTR(vector) + we->pos, we->len);
entries[i] = PointerGetDatum( txt ); entries[i] = PointerGetDatum(txt);
we++; we++;
} }
@ -52,42 +55,47 @@ PG_FUNCTION_INFO_V1(gin_extract_tsquery);
Datum gin_extract_tsquery(PG_FUNCTION_ARGS); Datum gin_extract_tsquery(PG_FUNCTION_ARGS);
Datum 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); QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
StrategyNumber strategy = DatumGetUInt16( PG_GETARG_DATUM(2) ); uint32 *nentries = (uint32 *) PG_GETARG_POINTER(1);
StrategyNumber strategy = DatumGetUInt16(PG_GETARG_DATUM(2));
Datum *entries = NULL; Datum *entries = NULL;
*nentries = 0; *nentries = 0;
if ( query->size > 0 ) { if (query->size > 0)
int4 i, j=0, len; {
int4 i,
j = 0,
len;
ITEM *item; ITEM *item;
item = clean_NOT_v2(GETQUERY(query), &len); item = clean_NOT_v2(GETQUERY(query), &len);
if ( !item ) if (!item)
elog(ERROR,"Query requires full scan, GIN doesn't support it"); elog(ERROR, "Query requires full scan, GIN doesn't support it");
item = GETQUERY(query); item = GETQUERY(query);
for(i=0; i<query->size; i++) for (i = 0; i < query->size; i++)
if ( item[i].type == VAL ) if (item[i].type == VAL)
(*nentries)++; (*nentries)++;
entries = (Datum*)palloc( sizeof(Datum) * (*nentries) ); entries = (Datum *) palloc(sizeof(Datum) * (*nentries));
for(i=0; i<query->size; i++) for (i = 0; i < query->size; i++)
if ( item[i].type == VAL ) { if (item[i].type == VAL)
{
text *txt; text *txt;
txt = (text*)palloc( VARHDRSZ + item[i].length ); txt = (text *) palloc(VARHDRSZ + item[i].length);
VARATT_SIZEP(txt) = VARHDRSZ + item[i].length; VARATT_SIZEP(txt) = VARHDRSZ + item[i].length;
memcpy( VARDATA(txt), GETOPERAND( query ) + item[i].distance, item[i].length ); memcpy(VARDATA(txt), GETOPERAND(query) + item[i].distance, item[i].length);
entries[j++] = PointerGetDatum( txt ); entries[j++] = PointerGetDatum(txt);
if ( strategy == 1 && item[i].weight != 0 ) if (strategy == 1 && item[i].weight != 0)
elog(ERROR,"With class of lexeme restrictions use @@@ operation"); elog(ERROR, "With class of lexeme restrictions use @@@ operation");
} }
} }
@ -96,38 +104,43 @@ gin_extract_tsquery(PG_FUNCTION_ARGS) {
PG_RETURN_POINTER(entries); PG_RETURN_POINTER(entries);
} }
typedef struct { typedef struct
{
ITEM *frst; ITEM *frst;
bool *mapped_check; bool *mapped_check;
} GinChkVal; } GinChkVal;
static bool static bool
checkcondition_gin(void *checkval, ITEM * val) { checkcondition_gin(void *checkval, ITEM * val)
GinChkVal *gcv = (GinChkVal*)checkval; {
GinChkVal *gcv = (GinChkVal *) checkval;
return gcv->mapped_check[ val - gcv->frst ]; return gcv->mapped_check[val - gcv->frst];
} }
PG_FUNCTION_INFO_V1(gin_ts_consistent); PG_FUNCTION_INFO_V1(gin_ts_consistent);
Datum gin_ts_consistent(PG_FUNCTION_ARGS); Datum gin_ts_consistent(PG_FUNCTION_ARGS);
Datum 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 *check = (bool *) PG_GETARG_POINTER(0);
QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_DATUM(2));
bool res = FALSE; bool res = FALSE;
if ( query->size > 0 ) { if (query->size > 0)
int4 i, j=0; {
int4 i,
j = 0;
ITEM *item; ITEM *item;
GinChkVal gcv; GinChkVal gcv;
gcv.frst = item = GETQUERY(query); gcv.frst = item = GETQUERY(query);
gcv.mapped_check= (bool*)palloc( sizeof(bool) * query->size ); gcv.mapped_check = (bool *) palloc(sizeof(bool) * query->size);
for(i=0; i<query->size; i++) for (i = 0; i < query->size; i++)
if ( item[i].type == VAL ) if (item[i].type == VAL)
gcv.mapped_check[ i ] = check[ j++ ]; gcv.mapped_check[i] = check[j++];
res = TS_execute( res = TS_execute(
@ -142,5 +155,3 @@ gin_ts_consistent(PG_FUNCTION_ARGS) {
PG_FREE_IF_COPY(query, 2); PG_FREE_IF_COPY(query, 2);
PG_RETURN_BOOL(res); PG_RETURN_BOOL(res);
} }

View File

@ -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" #include "postgres.h"

View File

@ -9,7 +9,7 @@ RS_isRegis(const char *str)
{ {
if (t_isalpha(str) || if (t_isalpha(str) ||
t_iseq(str, '[') || t_iseq(str, '[') ||
t_iseq(str,']') || t_iseq(str, ']') ||
t_iseq(str, '^')) t_iseq(str, '^'))
str += pg_mblen(str); str += pg_mblen(str);
else else
@ -42,13 +42,13 @@ RS_compile(Regis * r, bool issuffix, char *str)
{ {
int len = strlen(str); int len = strlen(str);
int state = RS_IN_WAIT; int state = RS_IN_WAIT;
char *c = (char*)str; char *c = (char *) str;
RegisNode *ptr = NULL; RegisNode *ptr = NULL;
memset(r, 0, sizeof(Regis)); memset(r, 0, sizeof(Regis));
r->issuffix = (issuffix) ? 1 : 0; r->issuffix = (issuffix) ? 1 : 0;
while(*c) while (*c)
{ {
if (state == RS_IN_WAIT) if (state == RS_IN_WAIT)
{ {
@ -62,7 +62,7 @@ RS_compile(Regis * r, bool issuffix, char *str)
ptr->type = RSF_ONEOF; ptr->type = RSF_ONEOF;
ptr->len = pg_mblen(c); ptr->len = pg_mblen(c);
} }
else if (t_iseq(c,'[')) else if (t_iseq(c, '['))
{ {
if (ptr) if (ptr)
ptr = newRegisNode(ptr, len); ptr = newRegisNode(ptr, len);
@ -72,11 +72,11 @@ RS_compile(Regis * r, bool issuffix, char *str)
state = RS_IN_ONEOF; state = RS_IN_ONEOF;
} }
else else
ts_error(ERROR, "Error in regis: %s", str ); ts_error(ERROR, "Error in regis: %s", str);
} }
else if (state == RS_IN_ONEOF) else if (state == RS_IN_ONEOF)
{ {
if (t_iseq(c,'^')) if (t_iseq(c, '^'))
{ {
ptr->type = RSF_NONEOF; ptr->type = RSF_NONEOF;
state = RS_IN_NONEOF; state = RS_IN_NONEOF;
@ -94,10 +94,10 @@ RS_compile(Regis * r, bool issuffix, char *str)
{ {
if (t_isalpha(c)) if (t_isalpha(c))
{ {
COPYCHAR(ptr->data+ptr->len, c); COPYCHAR(ptr->data + ptr->len, c);
ptr->len+=pg_mblen(c); ptr->len += pg_mblen(c);
} }
else if (t_iseq(c,']')) else if (t_iseq(c, ']'))
state = RS_IN_WAIT; state = RS_IN_WAIT;
else else
ts_error(ERROR, "Error in regis: %s", str); ts_error(ERROR, "Error in regis: %s", str);
@ -133,19 +133,25 @@ RS_free(Regis * r)
#ifdef TS_USE_WIDE #ifdef TS_USE_WIDE
static bool static bool
mb_strchr(char *str, char *c) { mb_strchr(char *str, char *c)
int clen = pg_mblen(c), plen,i; {
char *ptr =str; int clen = pg_mblen(c),
bool res=false; plen,
i;
char *ptr = str;
bool res = false;
clen = pg_mblen(c); clen = pg_mblen(c);
while( *ptr && !res) { while (*ptr && !res)
{
plen = pg_mblen(ptr); plen = pg_mblen(ptr);
if ( plen == clen ) { if (plen == clen)
i=plen; {
i = plen;
res = true; res = true;
while(i--) while (i--)
if ( *(ptr+i) != *(c+i) ) { if (*(ptr + i) != *(c + i))
{
res = false; res = false;
break; break;
} }
@ -166,9 +172,10 @@ RS_execute(Regis * r, char *str)
{ {
RegisNode *ptr = r->node; RegisNode *ptr = r->node;
char *c = str; char *c = str;
int len=0; int len = 0;
while(*c) { while (*c)
{
len++; len++;
c += pg_mblen(c); c += pg_mblen(c);
} }
@ -177,9 +184,10 @@ RS_execute(Regis * r, char *str)
return 0; return 0;
c = str; c = str;
if (r->issuffix) { if (r->issuffix)
{
len -= r->nchar; len -= r->nchar;
while(len-- > 0) while (len-- > 0)
c += pg_mblen(c); c += pg_mblen(c);
} }
@ -189,18 +197,18 @@ RS_execute(Regis * r, char *str)
switch (ptr->type) switch (ptr->type)
{ {
case RSF_ONEOF: case RSF_ONEOF:
if ( mb_strchr((char *) ptr->data, c) != true ) if (mb_strchr((char *) ptr->data, c) != true)
return false; return false;
break; break;
case RSF_NONEOF: case RSF_NONEOF:
if ( mb_strchr((char *) ptr->data, c) == true ) if (mb_strchr((char *) ptr->data, c) == true)
return false; return false;
break; break;
default: default:
ts_error(ERROR, "RS_execute: Unknown type node: %d\n", ptr->type); ts_error(ERROR, "RS_execute: Unknown type node: %d\n", ptr->type);
} }
ptr = ptr->next; ptr = ptr->next;
c+=pg_mblen(c); c += pg_mblen(c);
} }
return true; return true;

View File

@ -41,11 +41,13 @@ strnduplicate(char *s, int len)
} }
static char * static char *
findchar(char *str, int c) { findchar(char *str, int c)
while( *str ) { {
if ( t_iseq(str, c) ) while (*str)
{
if (t_iseq(str, c))
return str; return str;
str+=pg_mblen(str); str += pg_mblen(str);
} }
return NULL; return NULL;
@ -126,16 +128,16 @@ NIAddSpell(IspellDict * Conf, const char *word, const char *flag)
if (Conf->mspell) if (Conf->mspell)
{ {
Conf->mspell += 1024 * 20; Conf->mspell += 1024 * 20;
Conf->Spell = (SPELL **) repalloc(Conf->Spell, Conf->mspell * sizeof(SPELL*)); Conf->Spell = (SPELL **) repalloc(Conf->Spell, Conf->mspell * sizeof(SPELL *));
} }
else else
{ {
Conf->mspell = 1024 * 20; Conf->mspell = 1024 * 20;
Conf->Spell = (SPELL **) palloc(Conf->mspell * sizeof(SPELL*)); Conf->Spell = (SPELL **) palloc(Conf->mspell * sizeof(SPELL *));
} }
} }
Conf->Spell[Conf->nspell] = (SPELL*)palloc(SPELLHDRSZ + strlen(word) + 1); Conf->Spell[Conf->nspell] = (SPELL *) palloc(SPELLHDRSZ + strlen(word) + 1);
strcpy( Conf->Spell[Conf->nspell]->word ,word ); strcpy(Conf->Spell[Conf->nspell]->word, word);
strncpy(Conf->Spell[Conf->nspell]->p.flag, flag, 16); strncpy(Conf->Spell[Conf->nspell]->p.flag, flag, 16);
Conf->nspell++; Conf->nspell++;
return (0); return (0);
@ -155,7 +157,7 @@ NIImportDictionary(IspellDict * Conf, const char *filename)
char *s; char *s;
const char *flag; const char *flag;
pg_verifymbstr( str, strlen(str), false); pg_verifymbstr(str, strlen(str), false);
flag = NULL; flag = NULL;
if ((s = findchar(str, '/'))) if ((s = findchar(str, '/')))
@ -181,11 +183,12 @@ NIImportDictionary(IspellDict * Conf, const char *filename)
s = str; s = str;
while (*s) while (*s)
{ {
if (t_isspace(s)) { if (t_isspace(s))
{
*s = '\0'; *s = '\0';
break; break;
} }
s+=pg_mblen(s); s += pg_mblen(s);
} }
lowerstr(str); lowerstr(str);
@ -269,6 +272,7 @@ NIAddAffix(IspellDict * Conf, int flag, char flagflags, const char *mask, const
else else
{ {
int masklen = strlen(mask); int masklen = strlen(mask);
Conf->Affix[Conf->naffixes].issimple = 0; Conf->Affix[Conf->naffixes].issimple = 0;
Conf->Affix[Conf->naffixes].isregis = 0; Conf->Affix[Conf->naffixes].isregis = 0;
Conf->Affix[Conf->naffixes].mask = (char *) malloc(masklen + 2); 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; Conf->Affix[Conf->naffixes].find = (find && *find) ? strdup(find) : VoidString;
MEMOUT(Conf->Affix[Conf->naffixes].find); 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); Conf->Affix[Conf->naffixes].repl = strdup(repl);
MEMOUT(Conf->Affix[Conf->naffixes].repl); MEMOUT(Conf->Affix[Conf->naffixes].repl);
} else }
else
Conf->Affix[Conf->naffixes].repl = VoidString; Conf->Affix[Conf->naffixes].repl = VoidString;
Conf->naffixes++; Conf->naffixes++;
return (0); return (0);
@ -303,66 +309,102 @@ NIAddAffix(IspellDict * Conf, int flag, char flagflags, const char *mask, const
#define PAE_INREPL 5 #define PAE_INREPL 5
static bool 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; int state = PAE_WAIT_MASK;
char *pmask=mask, *pfind=find, *prepl=repl; char *pmask = mask,
*pfind = find,
*prepl = repl;
*mask = *find = *repl = '\0'; *mask = *find = *repl = '\0';
while(*str) { while (*str)
if ( state == PAE_WAIT_MASK ) { {
if ( t_iseq(str,'#') ) if (state == PAE_WAIT_MASK)
{
if (t_iseq(str, '#'))
return false; return false;
else if (!t_isspace(str)) { else if (!t_isspace(str))
{
COPYCHAR(pmask, str); COPYCHAR(pmask, str);
pmask += pg_mblen(str); pmask += pg_mblen(str);
state = PAE_INMASK; state = PAE_INMASK;
} }
} else if ( state == PAE_INMASK ) { }
if ( t_iseq(str,'>') ) { else if (state == PAE_INMASK)
*pmask='\0'; {
if (t_iseq(str, '>'))
{
*pmask = '\0';
state = PAE_WAIT_FIND; state = PAE_WAIT_FIND;
} else if (!t_isspace(str)) { }
else if (!t_isspace(str))
{
COPYCHAR(pmask, str); COPYCHAR(pmask, str);
pmask += pg_mblen(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; state = PAE_INFIND;
} else if (t_isalpha(str) || t_iseq(str,'\'') /* english 's */) { }
COPYCHAR(prepl,str); else if (t_isalpha(str) || t_iseq(str, '\'') /* english 's */ )
{
COPYCHAR(prepl, str);
prepl += pg_mblen(str); prepl += pg_mblen(str);
state = PAE_INREPL; state = PAE_INREPL;
} else if (!t_isspace(str)) }
else if (!t_isspace(str))
ts_error(ERROR, "Affix parse error at %d line", line); ts_error(ERROR, "Affix parse error at %d line", line);
} else if ( state == PAE_INFIND ) { }
if ( t_iseq(str,',') ) { else if (state == PAE_INFIND)
*pfind='\0'; {
if (t_iseq(str, ','))
{
*pfind = '\0';
state = PAE_WAIT_REPL; state = PAE_WAIT_REPL;
} else if (t_isalpha(str)) { }
COPYCHAR(pfind,str); else if (t_isalpha(str))
{
COPYCHAR(pfind, str);
pfind += pg_mblen(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); 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 */ break; /* void repl */
} else if ( t_isalpha(str) ) { }
COPYCHAR(prepl,str); else if (t_isalpha(str))
{
COPYCHAR(prepl, str);
prepl += pg_mblen(str); prepl += pg_mblen(str);
state = PAE_INREPL; state = PAE_INREPL;
} else if (!t_isspace(str)) }
else if (!t_isspace(str))
ts_error(ERROR, "Affix parse error at %d line", line); 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'; *prepl = '\0';
break; break;
} else if ( t_isalpha(str) ) { }
COPYCHAR(prepl,str); else if (t_isalpha(str))
{
COPYCHAR(prepl, str);
prepl += pg_mblen(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); ts_error(ERROR, "Affix parse error at %d line", line);
} else }
else
ts_error(ERROR, "Unknown state in parse_affentry: %d", state); ts_error(ERROR, "Unknown state in parse_affentry: %d", state);
str += pg_mblen(str); str += pg_mblen(str);
@ -370,7 +412,7 @@ parse_affentry( char *str, char *mask, char *find, char *repl, int line ) {
*pmask = *pfind = *prepl = '\0'; *pmask = *pfind = *prepl = '\0';
return ( *mask && ( *find || *repl) ) ? true : false; return (*mask && (*find || *repl)) ? true : false;
} }
int int
@ -387,7 +429,7 @@ NIImportAffixes(IspellDict * Conf, const char *filename)
int flag = 0; int flag = 0;
char flagflags = 0; char flagflags = 0;
FILE *affix; FILE *affix;
int line=0; int line = 0;
int oldformat = 0; int oldformat = 0;
if (!(affix = fopen(filename, "r"))) if (!(affix = fopen(filename, "r")))
@ -397,18 +439,20 @@ NIImportAffixes(IspellDict * Conf, const char *filename)
while (fgets(str, sizeof(str), affix)) while (fgets(str, sizeof(str), affix))
{ {
line++; line++;
pg_verifymbstr( str, strlen(str), false); pg_verifymbstr(str, strlen(str), false);
memcpy(tmpstr, str, 32); /* compoundwords... */ memcpy(tmpstr, str, 32); /* compoundwords... */
tmpstr[32]='\0'; tmpstr[32] = '\0';
lowerstr(tmpstr); lowerstr(tmpstr);
if (STRNCMP(tmpstr, "compoundwords") == 0) if (STRNCMP(tmpstr, "compoundwords") == 0)
{ {
s = findchar(str, 'l'); s = findchar(str, 'l');
if (s) if (s)
{ {
while (*s && !t_isspace(s)) s++; while (*s && !t_isspace(s))
while (*s && t_isspace(s)) s++; s++;
if ( *s && pg_mblen(s) == 1 ) while (*s && t_isspace(s))
s++;
if (*s && pg_mblen(s) == 1)
Conf->compoundcontrol = *s; Conf->compoundcontrol = *s;
oldformat++; oldformat++;
continue; continue;
@ -433,12 +477,13 @@ NIImportAffixes(IspellDict * Conf, const char *filename)
s = str + 4; s = str + 4;
flagflags = 0; flagflags = 0;
while (*s && t_isspace(s)) s++; while (*s && t_isspace(s))
s++;
oldformat++; oldformat++;
/* allow only single-encoded flags */ /* allow only single-encoded flags */
if ( pg_mblen(s) != 1 ) if (pg_mblen(s) != 1)
elog(ERROR,"Multiencoded flag at line %d: %s", line, s); elog(ERROR, "Multiencoded flag at line %d: %s", line, s);
if (*s == '*') if (*s == '*')
{ {
@ -455,19 +500,21 @@ NIImportAffixes(IspellDict * Conf, const char *filename)
s++; s++;
/* allow only single-encoded flags */ /* allow only single-encoded flags */
if ( pg_mblen(s) != 1 ) { if (pg_mblen(s) != 1)
{
flagflags = 0; flagflags = 0;
elog(ERROR,"Multiencoded flag at line %d: %s", line, s); elog(ERROR, "Multiencoded flag at line %d: %s", line, s);
} }
flag = (unsigned char) *s; flag = (unsigned char) *s;
continue; continue;
} }
if ( STRNCMP(str, "COMPOUNDFLAG") == 0 || STRNCMP(str, "COMPOUNDMIN") == 0 || 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 ) if (oldformat)
elog(ERROR,"Wrong affix file format"); elog(ERROR, "Wrong affix file format");
fclose(affix); fclose(affix);
return NIImportOOAffixes(Conf, filename); return NIImportOOAffixes(Conf, filename);
@ -477,7 +524,7 @@ NIImportAffixes(IspellDict * Conf, const char *filename)
continue; continue;
lowerstr(str); lowerstr(str);
if ( !parse_affentry(str, mask, find, repl, line) ) if (!parse_affentry(str, mask, find, repl, line))
continue; continue;
NIAddAffix(Conf, flag, flagflags, mask, find, repl, suffixes ? FF_SUFFIX : FF_PREFIX); NIAddAffix(Conf, flag, flagflags, mask, find, repl, suffixes ? FF_SUFFIX : FF_PREFIX);
@ -488,7 +535,8 @@ NIImportAffixes(IspellDict * Conf, const char *filename)
} }
int int
NIImportOOAffixes(IspellDict * Conf, const char *filename) { NIImportOOAffixes(IspellDict * Conf, const char *filename)
{
char str[BUFSIZ]; char str[BUFSIZ];
char type[BUFSIZ]; char type[BUFSIZ];
char sflag[BUFSIZ]; char sflag[BUFSIZ];
@ -499,11 +547,11 @@ NIImportOOAffixes(IspellDict * Conf, const char *filename) {
int flag = 0; int flag = 0;
char flagflags = 0; char flagflags = 0;
FILE *affix; FILE *affix;
int line=0; int line = 0;
int scanread = 0; int scanread = 0;
char scanbuf[BUFSIZ]; char scanbuf[BUFSIZ];
sprintf(scanbuf,"%%6s %%%ds %%%ds %%%ds %%%ds", BUFSIZ/5, BUFSIZ/5, BUFSIZ/5, BUFSIZ/5); sprintf(scanbuf, "%%6s %%%ds %%%ds %%%ds %%%ds", BUFSIZ / 5, BUFSIZ / 5, BUFSIZ / 5, BUFSIZ / 5);
if (!(affix = fopen(filename, "r"))) if (!(affix = fopen(filename, "r")))
return (1); return (1);
@ -512,14 +560,17 @@ NIImportOOAffixes(IspellDict * Conf, const char *filename) {
while (fgets(str, sizeof(str), affix)) while (fgets(str, sizeof(str), affix))
{ {
line++; line++;
if ( *str == '\0' || t_isspace(str) || t_iseq(str,'#') ) if (*str == '\0' || t_isspace(str) || t_iseq(str, '#'))
continue; continue;
pg_verifymbstr( str, strlen(str), false); 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++; char *s = str + strlen("COMPOUNDFLAG");
if ( *s && pg_mblen(s) == 1 )
while (*s && t_isspace(s))
s++;
if (*s && pg_mblen(s) == 1)
Conf->compoundcontrol = *s; Conf->compoundcontrol = *s;
continue; continue;
} }
@ -527,28 +578,31 @@ NIImportOOAffixes(IspellDict * Conf, const char *filename) {
scanread = sscanf(str, scanbuf, type, sflag, find, repl, mask); scanread = sscanf(str, scanbuf, type, sflag, find, repl, mask);
lowerstr(type); lowerstr(type);
if ( scanread<4 || (STRNCMP(type,"sfx") && STRNCMP(type,"pfx")) ) if (scanread < 4 || (STRNCMP(type, "sfx") && STRNCMP(type, "pfx")))
continue; continue;
if ( scanread == 4 ) { if (scanread == 4)
if ( strlen(sflag) != 1 ) {
if (strlen(sflag) != 1)
continue; continue;
flag = *sflag; flag = *sflag;
isSuffix = (STRNCMP(type,"sfx")==0) ? true : false; isSuffix = (STRNCMP(type, "sfx") == 0) ? true : false;
lowerstr(find); lowerstr(find);
if ( t_iseq(find,'y') ) if (t_iseq(find, 'y'))
flagflags |= FF_CROSSPRODUCT; flagflags |= FF_CROSSPRODUCT;
else else
flagflags = 0; flagflags = 0;
} else { }
if ( strlen(sflag) != 1 || flag != *sflag || flag==0 ) else
{
if (strlen(sflag) != 1 || flag != *sflag || flag == 0)
continue; continue;
lowerstr(repl); lowerstr(repl);
lowerstr(find); lowerstr(find);
lowerstr(mask); lowerstr(mask);
if ( t_iseq(find,'0') ) if (t_iseq(find, '0'))
*find = '\0'; *find = '\0';
if ( t_iseq(repl,'0') ) if (t_iseq(repl, '0'))
*repl = '\0'; *repl = '\0';
NIAddAffix(Conf, flag, flagflags, mask, find, repl, isSuffix ? FF_SUFFIX : FF_PREFIX); NIAddAffix(Conf, flag, flagflags, mask, find, repl, isSuffix ? FF_SUFFIX : FF_PREFIX);
@ -658,7 +712,7 @@ NISortDictionary(IspellDict * Conf)
int naffix = 3; int naffix = 3;
/* compress affixes */ /* compress affixes */
qsort((void *) Conf->Spell, Conf->nspell, sizeof(SPELL*), cmpspellaffix); qsort((void *) Conf->Spell, Conf->nspell, sizeof(SPELL *), cmpspellaffix);
for (i = 1; i < Conf->nspell; i++) for (i = 1; i < Conf->nspell; i++)
if (strcmp(Conf->Spell[i]->p.flag, Conf->Spell[i - 1]->p.flag)) if (strcmp(Conf->Spell[i]->p.flag, Conf->Spell[i - 1]->p.flag))
naffix++; naffix++;
@ -685,7 +739,7 @@ NISortDictionary(IspellDict * Conf)
Conf->Spell[i]->p.d.len = strlen(Conf->Spell[i]->word); Conf->Spell[i]->p.d.len = strlen(Conf->Spell[i]->word);
} }
qsort((void *) Conf->Spell, Conf->nspell, sizeof(SPELL*), cmpspell); qsort((void *) Conf->Spell, Conf->nspell, sizeof(SPELL *), cmpspell);
Conf->Dictionary = mkSPNode(Conf, 0, Conf->nspell, 0); Conf->Dictionary = mkSPNode(Conf, 0, Conf->nspell, 0);
for (i = 0; i < Conf->nspell; i++) for (i = 0; i < Conf->nspell; i++)
@ -806,7 +860,7 @@ NISortAffixes(IspellDict * Conf)
CMPDAffix *ptr; CMPDAffix *ptr;
int firstsuffix = -1; int firstsuffix = -1;
if (Conf->naffixes==0) if (Conf->naffixes == 0)
return; return;
if (Conf->naffixes > 1) if (Conf->naffixes > 1)
@ -822,7 +876,7 @@ NISortAffixes(IspellDict * Conf)
{ {
if (firstsuffix < 0) if (firstsuffix < 0)
firstsuffix = i; firstsuffix = i;
if ((Affix->flagflags & FF_COMPOUNDONLYAFX) && Affix->replen>0 ) if ((Affix->flagflags & FF_COMPOUNDONLYAFX) && Affix->replen > 0)
{ {
if (ptr == Conf->CompoundAffix || if (ptr == Conf->CompoundAffix ||
strbncmp((const unsigned char *) (ptr - 1)->affix, strbncmp((const unsigned char *) (ptr - 1)->affix,
@ -907,14 +961,16 @@ CheckAffix(const char *word, size_t len, AFFIX * Affix, char flagflags, char *ne
{ {
strcpy(newword, word); strcpy(newword, word);
strcpy(newword + len - Affix->replen, Affix->find); strcpy(newword + len - Affix->replen, Affix->find);
if ( baselen ) /* store length of non-changed part of word */ if (baselen) /* store length of non-changed part of word */
*baselen = len - Affix->replen; *baselen = len - Affix->replen;
} }
else 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
if ( baselen && *baselen + strlen(Affix->find) <= Affix->replen ) * only prefix and suffix, so out
*/
if (baselen && *baselen + strlen(Affix->find) <= Affix->replen)
return NULL; return NULL;
strcpy(newword, Affix->find); strcpy(newword, Affix->find);
strcat(newword, word + Affix->replen); strcat(newword, word + Affix->replen);
@ -944,6 +1000,7 @@ CheckAffix(const char *word, size_t len, AFFIX * Affix, char flagflags, char *ne
int wmasklen, int wmasklen,
masklen = strlen(Affix->mask); masklen = strlen(Affix->mask);
pg_wchar *mask; pg_wchar *mask;
mask = (pg_wchar *) palloc((masklen + 1) * sizeof(pg_wchar)); mask = (pg_wchar *) palloc((masklen + 1) * sizeof(pg_wchar));
wmasklen = pg_mb2wchar_with_len(Affix->mask, mask, masklen); wmasklen = pg_mb2wchar_with_len(Affix->mask, mask, masklen);
@ -1040,7 +1097,7 @@ NormalizeSubWord(IspellDict * Conf, char *word, char flag)
*/ */
while (snode) while (snode)
{ {
int baselen=0; int baselen = 0;
/* find possible suffix */ /* find possible suffix */
suffix = FinfAffixes(snode, word, wrdlen, &slevel, FF_SUFFIX); suffix = FinfAffixes(snode, word, wrdlen, &slevel, FF_SUFFIX);
@ -1111,7 +1168,8 @@ typedef struct SplitVar
static int static int
CheckCompoundAffixes(CMPDAffix ** ptr, char *word, int len, bool CheckInPlace) CheckCompoundAffixes(CMPDAffix ** ptr, char *word, int len, bool CheckInPlace)
{ {
if ( CheckInPlace ) { if (CheckInPlace)
{
while ((*ptr)->affix) while ((*ptr)->affix)
{ {
if (len > (*ptr)->len && strncmp((*ptr)->affix, word, (*ptr)->len) == 0) if (len > (*ptr)->len && strncmp((*ptr)->affix, word, (*ptr)->len) == 0)
@ -1122,13 +1180,16 @@ CheckCompoundAffixes(CMPDAffix ** ptr, char *word, int len, bool CheckInPlace)
} }
(*ptr)++; (*ptr)++;
} }
} else { }
else
{
char *affbegin; char *affbegin;
while ((*ptr)->affix) while ((*ptr)->affix)
{ {
if (len > (*ptr)->len && (affbegin = strstr(word, (*ptr)->affix)) != NULL) if (len > (*ptr)->len && (affbegin = strstr(word, (*ptr)->affix)) != NULL)
{ {
len = (*ptr)->len + (affbegin-word); len = (*ptr)->len + (affbegin - word);
(*ptr)++; (*ptr)++;
return len; return len;
} }
@ -1227,7 +1288,7 @@ SplitToVariants(IspellDict * Conf, SPNode * snode, SplitVar * orig, char *word,
} }
} }
if ( !node ) if (!node)
break; break;
StopLow = node->data; StopLow = node->data;
@ -1243,7 +1304,8 @@ SplitToVariants(IspellDict * Conf, SPNode * snode, SplitVar * orig, char *word,
StopHigh = StopMiddle; StopHigh = StopMiddle;
} }
if (StopLow < StopHigh) { if (StopLow < StopHigh)
{
/* find infinitive */ /* find infinitive */
if (StopMiddle->isword && StopMiddle->compoundallow && notprobed[level]) if (StopMiddle->isword && StopMiddle->compoundallow && notprobed[level])
@ -1279,7 +1341,8 @@ SplitToVariants(IspellDict * Conf, SPNode * snode, SplitVar * orig, char *word,
} }
} }
node = StopMiddle->node; node = StopMiddle->node;
} else }
else
node = NULL; node = NULL;
level++; level++;
} }
@ -1436,9 +1499,12 @@ NIFree(IspellDict * Conf)
else else
pg_regfree(&(Affix[i].reg.regex)); pg_regfree(&(Affix[i].reg.regex));
} }
if ( Affix[i].mask != VoidString ) free(Affix[i].mask); if (Affix[i].mask != VoidString)
if ( Affix[i].find != VoidString ) free(Affix[i].find); free(Affix[i].mask);
if ( Affix[i].repl != VoidString ) free(Affix[i].repl); if (Affix[i].find != VoidString)
free(Affix[i].find);
if (Affix[i].repl != VoidString)
free(Affix[i].repl);
} }
if (Conf->Spell) if (Conf->Spell)
{ {

View File

@ -33,9 +33,9 @@ nstrdup(char *ptr, int len)
{ {
if (t_iseq(ptr, '\\')) if (t_iseq(ptr, '\\'))
ptr++; ptr++;
COPYCHAR( cptr, ptr ); COPYCHAR(cptr, ptr);
cptr+=pg_mblen(ptr); cptr += pg_mblen(ptr);
ptr+=pg_mblen(ptr); ptr += pg_mblen(ptr);
} }
*cptr = '\0'; *cptr = '\0';
@ -53,9 +53,9 @@ parse_cfgdict(text *in, Map ** m)
while (ptr - VARDATA(in) < VARSIZE(in) - VARHDRSZ) while (ptr - VARDATA(in) < VARSIZE(in) - VARHDRSZ)
{ {
if ( t_iseq(ptr, ',') ) if (t_iseq(ptr, ','))
num++; num++;
ptr+=pg_mblen(ptr); ptr += pg_mblen(ptr);
} }
*m = mptr = (Map *) palloc(sizeof(Map) * (num + 2)); *m = mptr = (Map *) palloc(sizeof(Map) * (num + 2));
@ -84,7 +84,7 @@ parse_cfgdict(text *in, Map ** m)
mptr->key = nstrdup(begin, ptr - begin); mptr->key = nstrdup(begin, ptr - begin);
state = CS_WAITEQ; state = CS_WAITEQ;
} }
else if (t_iseq(ptr,'=')) else if (t_iseq(ptr, '='))
{ {
mptr->key = nstrdup(begin, ptr - begin); mptr->key = nstrdup(begin, ptr - begin);
state = CS_WAITVALUE; state = CS_WAITVALUE;
@ -163,7 +163,7 @@ parse_cfgdict(text *in, Map ** m)
errmsg("bad parser state"), errmsg("bad parser state"),
errdetail("%d at position %d.", errdetail("%d at position %d.",
state, (int) (ptr - VARDATA(in))))); state, (int) (ptr - VARDATA(in)))));
ptr+=pg_mblen(ptr); ptr += pg_mblen(ptr);
} }
if (state == CS_IN2VALUE) if (state == CS_IN2VALUE)

View File

@ -108,11 +108,11 @@ get_weight(char *buf, int2 *weight)
{ {
*weight = 0; *weight = 0;
if ( !t_iseq(buf, ':') ) if (!t_iseq(buf, ':'))
return buf; return buf;
buf++; buf++;
while ( *buf && pg_mblen(buf) == 1 ) while (*buf && pg_mblen(buf) == 1)
{ {
switch (*buf) switch (*buf)
{ {
@ -153,25 +153,26 @@ gettoken_query(QPRS_STATE * state, int4 *val, int4 *lenval, char **strval, int2
{ {
case WAITFIRSTOPERAND: case WAITFIRSTOPERAND:
case WAITOPERAND: case WAITOPERAND:
if ( t_iseq(state->buf, '!') ) 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) '!'; *val = (int4) '!';
return OPR; return OPR;
} }
else if ( t_iseq(state->buf, '(') ) else if (t_iseq(state->buf, '('))
{ {
state->count++; state->count++;
(state->buf)++; (state->buf)++;
return OPEN; return OPEN;
} }
else if ( t_iseq(state->buf, ':') ) else if (t_iseq(state->buf, ':'))
{ {
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("error at start of operand"))); errmsg("error at start of operand")));
} }
else if ( !t_isspace(state->buf) ) else if (!t_isspace(state->buf))
{ {
state->valstate.prsbuf = state->buf; state->valstate.prsbuf = state->buf;
if (gettoken_tsvector(&(state->valstate))) if (gettoken_tsvector(&(state->valstate)))
@ -191,14 +192,14 @@ gettoken_query(QPRS_STATE * state, int4 *val, int4 *lenval, char **strval, int2
} }
break; break;
case WAITOPERATOR: case WAITOPERATOR:
if ( t_iseq(state->buf, '&') || t_iseq(state->buf, '|') ) if (t_iseq(state->buf, '&') || t_iseq(state->buf, '|'))
{ {
state->state = WAITOPERAND; state->state = WAITOPERAND;
*val = (int4) *(state->buf); *val = (int4) *(state->buf);
(state->buf)++; (state->buf)++;
return OPR; return OPR;
} }
else if ( t_iseq(state->buf, ')') ) else if (t_iseq(state->buf, ')'))
{ {
(state->buf)++; (state->buf)++;
state->count--; state->count--;
@ -206,7 +207,7 @@ gettoken_query(QPRS_STATE * state, int4 *val, int4 *lenval, char **strval, int2
} }
else if (*(state->buf) == '\0') else if (*(state->buf) == '\0')
return (state->count) ? ERR : END; return (state->count) ? ERR : END;
else if ( !t_isspace(state->buf) ) else if (!t_isspace(state->buf))
return ERR; return ERR;
break; break;
case WAITSINGLEOPERAND: case WAITSINGLEOPERAND:
@ -221,7 +222,7 @@ gettoken_query(QPRS_STATE * state, int4 *val, int4 *lenval, char **strval, int2
return ERR; return ERR;
break; break;
} }
state->buf+=pg_mblen(state->buf); state->buf += pg_mblen(state->buf);
} }
return END; return END;
} }
@ -604,7 +605,7 @@ findoprnd(ITEM * ptr, int4 *pos)
* input * input
*/ */
static QUERYTYPE * static QUERYTYPE *
queryin(char *buf, void (*pushval) (QPRS_STATE *, int, char *, int, int2), int cfg_id, bool isplain) queryin(char *buf, void (*pushval) (QPRS_STATE *, int, char *, int, int2), int cfg_id, bool isplain)
{ {
QPRS_STATE state; QPRS_STATE state;
int4 i; int4 i;
@ -701,8 +702,9 @@ queryin(char *buf, void (*pushval) (QPRS_STATE *, int, char *, int, int2), int c
Datum Datum
tsquery_in(PG_FUNCTION_ARGS) tsquery_in(PG_FUNCTION_ARGS)
{ {
char * in = (char*)PG_GETARG_POINTER(0); char *in = (char *) PG_GETARG_POINTER(0);
pg_verifymbstr( in, strlen(in), false);
pg_verifymbstr(in, strlen(in), false);
SET_FUNCOID(); SET_FUNCOID();
PG_RETURN_POINTER(queryin((char *) in, pushval_asis, 0, false)); PG_RETURN_POINTER(queryin((char *) in, pushval_asis, 0, false));
@ -741,21 +743,21 @@ infix(INFIX * in, bool first)
char *op = in->op + in->curpol->distance; char *op = in->op + in->curpol->distance;
int clen; int clen;
RESIZEBUF(in, in->curpol->length * (pg_database_encoding_max_length()+1) + 2 + 5); RESIZEBUF(in, in->curpol->length * (pg_database_encoding_max_length() + 1) + 2 + 5);
*(in->cur) = '\''; *(in->cur) = '\'';
in->cur++; in->cur++;
while (*op) while (*op)
{ {
if ( t_iseq(op, '\'') ) if (t_iseq(op, '\''))
{ {
*(in->cur) = '\''; *(in->cur) = '\'';
in->cur++; in->cur++;
} }
COPYCHAR(in->cur,op); COPYCHAR(in->cur, op);
clen = pg_mblen(op); clen = pg_mblen(op);
op+=clen; op += clen;
in->cur+=clen; in->cur += clen;
} }
*(in->cur) = '\''; *(in->cur) = '\'';
in->cur++; in->cur++;

View File

@ -48,7 +48,7 @@ typedef struct
#define CLOSE 5 #define CLOSE 5
#define VALSTOP 6 /* for stop words */ #define VALSTOP 6 /* for stop words */
bool TS_execute(ITEM *curitem, void *checkval, bool TS_execute(ITEM * curitem, void *checkval,
bool calcnot, bool (*chkcond) (void *checkval, ITEM *val)); bool calcnot, bool (*chkcond) (void *checkval, ITEM * val));
#endif #endif

View File

@ -3,7 +3,7 @@
#include "query.h" #include "query.h"
ITEM *clean_NOT_v2(ITEM *ptr, int4 *len); ITEM *clean_NOT_v2(ITEM * ptr, int4 *len);
ITEM *clean_fakeval_v2(ITEM *ptr, int4 *len); ITEM *clean_fakeval_v2(ITEM * ptr, int4 *len);
#endif #endif

View File

@ -29,7 +29,7 @@ makesign(QUERYTYPE * a)
for (i = 0; i < a->size; i++) for (i = 0; i < a->size; i++)
{ {
if (ptr->type == VAL) if (ptr->type == VAL)
sign |= ((TPQTGist)1) << (ptr->val % SIGLEN); sign |= ((TPQTGist) 1) << (ptr->val % SIGLEN);
ptr++; ptr++;
} }

View File

@ -334,19 +334,20 @@ calc_rank(float *w, tsvector * t, QUERYTYPE * q, int4 method)
if (res < 0) if (res < 0)
res = 1e-20; res = 1e-20;
if ( (method & RANK_NORM_LOGLENGTH) && t->size>0 ) if ((method & RANK_NORM_LOGLENGTH) && t->size > 0)
res /= log((double) (cnt_length(t) + 1)) / log(2.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); len = cnt_length(t);
if ( len>0 ) if (len > 0)
res /= (float) len; res /= (float) len;
} }
if ( (method & RANK_NORM_UNIQ) && t->size > 0 ) if ((method & RANK_NORM_UNIQ) && t->size > 0)
res /= (float)( t->size ); res /= (float) (t->size);
if ( (method & RANK_NORM_LOGUNIQ) && t->size > 0 ) if ((method & RANK_NORM_LOGUNIQ) && t->size > 0)
res /= log((double) (t->size + 1)) / log(2.0); res /= log((double) (t->size + 1)) / log(2.0);
return res; return res;
@ -457,7 +458,8 @@ reset_istrue_flag(QUERYTYPE * query)
} }
} }
typedef struct { typedef struct
{
int pos; int pos;
int p; int p;
int q; int q;
@ -467,7 +469,7 @@ typedef struct {
static bool static bool
Cover(DocRepresentation * doc, int len, QUERYTYPE * query, Extention *ext) Cover(DocRepresentation * doc, int len, QUERYTYPE * query, Extention * ext)
{ {
DocRepresentation *ptr; DocRepresentation *ptr;
int lastpos = ext->pos; int lastpos = ext->pos;
@ -513,7 +515,8 @@ Cover(DocRepresentation * doc, int len, QUERYTYPE * query, Extention *ext)
ptr->item[i]->istrue = 1; ptr->item[i]->istrue = 1;
if (TS_execute(GETQUERY(query), NULL, true, checkcondition_ITEM)) if (TS_execute(GETQUERY(query), NULL, true, checkcondition_ITEM))
{ {
if (ptr->pos < ext->p) { if (ptr->pos < ext->p)
{
ext->begin = ptr; ext->begin = ptr;
ext->p = ptr->pos; ext->p = ptr->pos;
} }
@ -629,7 +632,8 @@ get_docrep(tsvector * txt, QUERYTYPE * query, int *doclen)
} }
static float4 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; DocRepresentation *doc;
int len, int len,
i, i,
@ -637,61 +641,68 @@ calc_rank_cd(float4 *arrdata, tsvector *txt, QUERYTYPE *query, int method) {
Extention ext; Extention ext;
double Wdoc = 0.0; double Wdoc = 0.0;
double invws[lengthof(weights)]; double invws[lengthof(weights)];
double SumDist=0.0, PrevExtPos=0.0, CurExtPos=0.0; double SumDist = 0.0,
int NExtent=0; PrevExtPos = 0.0,
CurExtPos = 0.0;
int NExtent = 0;
for (i = 0; i < lengthof(weights); i++) for (i = 0; i < lengthof(weights); i++)
{ {
invws[i] = ((double)((arrdata[i] >= 0) ? arrdata[i] : weights[i])); invws[i] = ((double) ((arrdata[i] >= 0) ? arrdata[i] : weights[i]));
if (invws[i] > 1.0) if (invws[i] > 1.0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("weight out of range"))); errmsg("weight out of range")));
invws[i] = 1.0/invws[i]; invws[i] = 1.0 / invws[i];
} }
doc = get_docrep(txt, query, &doclen); doc = get_docrep(txt, query, &doclen);
if (!doc) if (!doc)
return 0.0; return 0.0;
MemSet( &ext, 0, sizeof(Extention) ); MemSet(&ext, 0, sizeof(Extention));
while (Cover(doc, doclen, query, &ext)) { while (Cover(doc, doclen, query, &ext))
{
double Cpos = 0.0; double Cpos = 0.0;
double InvSum = 0.0; double InvSum = 0.0;
DocRepresentation *ptr = ext.begin; DocRepresentation *ptr = ext.begin;
while ( ptr<=ext.end ) { while (ptr <= ext.end)
InvSum += invws[ ptr->wclass ]; {
InvSum += invws[ptr->wclass];
ptr++; ptr++;
} }
Cpos = ((double)( ext.end-ext.begin+1 )) / InvSum; Cpos = ((double) (ext.end - ext.begin + 1)) / InvSum;
Wdoc += Cpos / ( (double)(( 1 + (ext.q - ext.p) - (ext.end - ext.begin) )) ); Wdoc += Cpos / ((double) ((1 + (ext.q - ext.p) - (ext.end - ext.begin))));
CurExtPos = ((double)(ext.q + ext.p))/2.0; 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
SumDist += 1.0/( CurExtPos - PrevExtPos ); * zero in a case of
multiple lexize */ )
SumDist += 1.0 / (CurExtPos - PrevExtPos);
PrevExtPos = CurExtPos; PrevExtPos = CurExtPos;
NExtent++; NExtent++;
} }
if ( (method & RANK_NORM_LOGLENGTH) && txt->size > 0 ) if ((method & RANK_NORM_LOGLENGTH) && txt->size > 0)
Wdoc /= log((double) (cnt_length(txt) + 1)); Wdoc /= log((double) (cnt_length(txt) + 1));
if ( method & RANK_NORM_LENGTH ) { if (method & RANK_NORM_LENGTH)
{
len = cnt_length(txt); len = cnt_length(txt);
if ( len>0 ) if (len > 0)
Wdoc /= (double) len; Wdoc /= (double) len;
} }
if ( (method & RANK_NORM_EXTDIST) && SumDist > 0 ) if ((method & RANK_NORM_EXTDIST) && SumDist > 0)
Wdoc /= ((double)NExtent) / SumDist; Wdoc /= ((double) NExtent) / SumDist;
if ( (method & RANK_NORM_UNIQ) && txt->size > 0 ) if ((method & RANK_NORM_UNIQ) && txt->size > 0)
Wdoc /= (double)( txt->size ); Wdoc /= (double) (txt->size);
if ( (method & RANK_NORM_LOGUNIQ) && txt->size > 0 ) if ((method & RANK_NORM_LOGUNIQ) && txt->size > 0)
Wdoc /= log((double) (txt->size + 1)) / log(2.0); Wdoc /= log((double) (txt->size + 1)) / log(2.0);
for (i = 0; i < doclen; i++) for (i = 0; i < doclen; i++)
@ -699,7 +710,7 @@ calc_rank_cd(float4 *arrdata, tsvector *txt, QUERYTYPE *query, int method) {
pfree(doc[i].item); pfree(doc[i].item);
pfree(doc); pfree(doc);
return (float4)Wdoc; return (float4) Wdoc;
} }
Datum Datum
@ -729,7 +740,7 @@ rank_cd(PG_FUNCTION_ARGS)
if (PG_NARGS() == 4) if (PG_NARGS() == 4)
method = PG_GETARG_INT32(3); method = PG_GETARG_INT32(3);
res = calc_rank_cd( (float4 *) ARR_DATA_PTR(win), txt, query, method); res = calc_rank_cd((float4 *) ARR_DATA_PTR(win), txt, query, method);
PG_FREE_IF_COPY(win, 0); PG_FREE_IF_COPY(win, 0);
PG_FREE_IF_COPY(txt, 1); PG_FREE_IF_COPY(txt, 1);
@ -746,7 +757,7 @@ rank_cd_def(PG_FUNCTION_ARGS)
QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1)); QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1));
float4 res; float4 res;
res = calc_rank_cd( weights, txt, query, (PG_NARGS() == 3) ? PG_GETARG_DATUM(2) : DEF_NORM_METHOD); res = calc_rank_cd(weights, txt, query, (PG_NARGS() == 3) ? PG_GETARG_DATUM(2) : DEF_NORM_METHOD);
PG_FREE_IF_COPY(txt, 0); PG_FREE_IF_COPY(txt, 0);
PG_FREE_IF_COPY(query, 1); PG_FREE_IF_COPY(query, 1);
@ -833,7 +844,7 @@ get_covers(PG_FUNCTION_ARGS)
} }
qsort((void *) dw, dlen, sizeof(DocWord), compareDocWord); qsort((void *) dw, dlen, sizeof(DocWord), compareDocWord);
MemSet( &ext, 0, sizeof(Extention) ); MemSet(&ext, 0, sizeof(Extention));
while (Cover(doc, rlen, query, &ext)) while (Cover(doc, rlen, query, &ext))
{ {
dwptr = dw + olddwpos; dwptr = dw + olddwpos;

File diff suppressed because it is too large Load Diff

View File

@ -2,15 +2,16 @@
/* This file was generated automatically by the Snowball to ANSI C compiler */ /* This file was generated automatically by the Snowball to ANSI C compiler */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C"
{
#endif #endif
extern struct SN_env * russian_UTF_8_create_env(void); extern struct SN_env *russian_UTF_8_create_env(void);
extern void russian_UTF_8_close_env(struct SN_env * z); extern void russian_UTF_8_close_env(struct SN_env * z);
extern int russian_UTF_8_stem(struct SN_env * z); extern int russian_UTF_8_stem(struct SN_env * z);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif
#endif

View File

@ -48,7 +48,7 @@ readstoplist(text *in, StopList * s)
while (fgets(buf, STOPBUFLEN, hin)) while (fgets(buf, STOPBUFLEN, hin))
{ {
buf[strlen(buf) - 1] = '\0'; buf[strlen(buf) - 1] = '\0';
pg_verifymbstr( buf, strlen(buf), false ); pg_verifymbstr(buf, strlen(buf), false);
lowerstr(buf); lowerstr(buf);
if (*buf == '\0') if (*buf == '\0')
continue; continue;

View File

@ -301,14 +301,15 @@ parsetext_v2(TSCfgInfo * cfg, PRSTEXT * prs, char *buf, int4 buflen)
LexizeInit(&ldata, cfg); LexizeInit(&ldata, cfg);
do { do
{
type = DatumGetInt32(FunctionCall3( type = DatumGetInt32(FunctionCall3(
&(prsobj->getlexeme_info), &(prsobj->getlexeme_info),
PointerGetDatum(prsobj->prs), PointerGetDatum(prsobj->prs),
PointerGetDatum(&lemm), PointerGetDatum(&lemm),
PointerGetDatum(&lenlemm))); PointerGetDatum(&lenlemm)));
if (type>0 && lenlemm >= MAXSTRLEN) if (type > 0 && lenlemm >= MAXSTRLEN)
{ {
#ifdef IGNORE_LONGLEXEME #ifdef IGNORE_LONGLEXEME
ereport(NOTICE, ereport(NOTICE,
@ -324,7 +325,7 @@ parsetext_v2(TSCfgInfo * cfg, PRSTEXT * prs, char *buf, int4 buflen)
LexizeAddLemm(&ldata, type, lemm, lenlemm); LexizeAddLemm(&ldata, type, lemm, lenlemm);
while( (norms = LexizeExec(&ldata, NULL)) != NULL ) while ((norms = LexizeExec(&ldata, NULL)) != NULL)
{ {
TSLexeme *ptr = norms; TSLexeme *ptr = norms;
@ -338,7 +339,7 @@ parsetext_v2(TSCfgInfo * cfg, PRSTEXT * prs, char *buf, int4 buflen)
prs->words = (TSWORD *) repalloc((void *) prs->words, prs->lenwords * sizeof(TSWORD)); prs->words = (TSWORD *) repalloc((void *) prs->words, prs->lenwords * sizeof(TSWORD));
} }
if ( ptr->flags & TSL_ADDPOS ) if (ptr->flags & TSL_ADDPOS)
prs->pos++; prs->pos++;
prs->words[prs->curwords].len = strlen(ptr->lexeme); prs->words[prs->curwords].len = strlen(ptr->lexeme);
prs->words[prs->curwords].word = ptr->lexeme; prs->words[prs->curwords].word = ptr->lexeme;
@ -350,7 +351,7 @@ parsetext_v2(TSCfgInfo * cfg, PRSTEXT * prs, char *buf, int4 buflen)
} }
pfree(norms); pfree(norms);
} }
} while(type>0); } while (type > 0);
FunctionCall1( FunctionCall1(
&(prsobj->end_info), &(prsobj->end_info),
@ -407,30 +408,35 @@ hlfinditem(HLPRSTEXT * prs, QUERYTYPE * query, char *buf, int buflen)
} }
static void static void
addHLParsedLex(HLPRSTEXT *prs, QUERYTYPE * query, ParsedLex *lexs, TSLexeme *norms) { addHLParsedLex(HLPRSTEXT * prs, QUERYTYPE * query, ParsedLex * lexs, TSLexeme * norms)
{
ParsedLex *tmplexs; ParsedLex *tmplexs;
TSLexeme *ptr; TSLexeme *ptr;
while( lexs ) { while (lexs)
{
if ( lexs->type > 0 ) if (lexs->type > 0)
hladdword(prs, lexs->lemm, lexs->lenlemm, lexs->type); hladdword(prs, lexs->lemm, lexs->lenlemm, lexs->type);
ptr = norms; ptr = norms;
while( ptr && ptr->lexeme ) { while (ptr && ptr->lexeme)
{
hlfinditem(prs, query, ptr->lexeme, strlen(ptr->lexeme)); hlfinditem(prs, query, ptr->lexeme, strlen(ptr->lexeme));
ptr++; ptr++;
} }
tmplexs = lexs->next; tmplexs = lexs->next;
pfree( lexs ); pfree(lexs);
lexs = tmplexs; lexs = tmplexs;
} }
if ( norms ) { if (norms)
{
ptr = norms; ptr = norms;
while( ptr->lexeme ) { while (ptr->lexeme)
pfree( ptr->lexeme ); {
pfree(ptr->lexeme);
ptr++; ptr++;
} }
pfree(norms); pfree(norms);
@ -458,14 +464,15 @@ hlparsetext(TSCfgInfo * cfg, HLPRSTEXT * prs, QUERYTYPE * query, char *buf, int4
LexizeInit(&ldata, cfg); LexizeInit(&ldata, cfg);
do { do
{
type = DatumGetInt32(FunctionCall3( type = DatumGetInt32(FunctionCall3(
&(prsobj->getlexeme_info), &(prsobj->getlexeme_info),
PointerGetDatum(prsobj->prs), PointerGetDatum(prsobj->prs),
PointerGetDatum(&lemm), PointerGetDatum(&lemm),
PointerGetDatum(&lenlemm))); PointerGetDatum(&lenlemm)));
if (type>0 && lenlemm >= MAXSTRLEN) if (type > 0 && lenlemm >= MAXSTRLEN)
{ {
#ifdef IGNORE_LONGLEXEME #ifdef IGNORE_LONGLEXEME
ereport(NOTICE, ereport(NOTICE,
@ -481,14 +488,15 @@ hlparsetext(TSCfgInfo * cfg, HLPRSTEXT * prs, QUERYTYPE * query, char *buf, int4
LexizeAddLemm(&ldata, type, lemm, lenlemm); LexizeAddLemm(&ldata, type, lemm, lenlemm);
do { do
if ( (norms = LexizeExec(&ldata,&lexs)) != NULL ) {
if ((norms = LexizeExec(&ldata, &lexs)) != NULL)
addHLParsedLex(prs, query, lexs, norms); addHLParsedLex(prs, query, lexs, norms);
else else
addHLParsedLex(prs, query, lexs, NULL); addHLParsedLex(prs, query, lexs, NULL);
} while( norms ); } while (norms);
} while( type>0 ); } while (type > 0);
FunctionCall1( FunctionCall1(
&(prsobj->end_info), &(prsobj->end_info),

View File

@ -11,34 +11,39 @@
#include "dict.h" #include "dict.h"
void void
LexizeInit(LexizeData *ld, TSCfgInfo *cfg) { LexizeInit(LexizeData * ld, TSCfgInfo * cfg)
{
ld->cfg = cfg; ld->cfg = cfg;
ld->curDictId = InvalidOid; ld->curDictId = InvalidOid;
ld->posDict = 0; ld->posDict = 0;
ld->towork.head = ld->towork.tail = ld->curSub = NULL; ld->towork.head = ld->towork.tail = ld->curSub = NULL;
ld->waste.head = ld->waste.tail = NULL; ld->waste.head = ld->waste.tail = NULL;
ld->lastRes=NULL; ld->lastRes = NULL;
ld->tmpRes=NULL; ld->tmpRes = NULL;
} }
static void static void
LPLAddTail(ListParsedLex *list, ParsedLex *newpl) { LPLAddTail(ListParsedLex * list, ParsedLex * newpl)
if ( list->tail ) { {
if (list->tail)
{
list->tail->next = newpl; list->tail->next = newpl;
list->tail = newpl; list->tail = newpl;
} else }
else
list->head = list->tail = newpl; list->head = list->tail = newpl;
newpl->next = NULL; newpl->next = NULL;
} }
static ParsedLex* static ParsedLex *
LPLRemoveHead(ListParsedLex *list) { LPLRemoveHead(ListParsedLex * list)
{
ParsedLex *res = list->head; ParsedLex *res = list->head;
if ( list->head ) if (list->head)
list->head = list->head->next; list->head = list->head->next;
if ( list->head == NULL ) if (list->head == NULL)
list->tail = NULL; list->tail = NULL;
return res; return res;
@ -46,10 +51,11 @@ LPLRemoveHead(ListParsedLex *list) {
void 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) ); {
ParsedLex *newpl = (ParsedLex *) palloc(sizeof(ParsedLex));
newpl = (ParsedLex*)palloc( sizeof(ParsedLex) ); newpl = (ParsedLex *) palloc(sizeof(ParsedLex));
newpl->type = type; newpl->type = type;
newpl->lemm = lemm; newpl->lemm = lemm;
newpl->lenlemm = lenlemm; newpl->lenlemm = lenlemm;
@ -58,20 +64,27 @@ LexizeAddLemm(LexizeData *ld, int type, char *lemm, int lenlemm) {
} }
static void static void
RemoveHead(LexizeData *ld) { RemoveHead(LexizeData * ld)
{
LPLAddTail(&ld->waste, LPLRemoveHead(&ld->towork)); LPLAddTail(&ld->waste, LPLRemoveHead(&ld->towork));
ld->posDict = 0; ld->posDict = 0;
} }
static void static void
setCorrLex(LexizeData *ld, ParsedLex **correspondLexem) { setCorrLex(LexizeData * ld, ParsedLex ** correspondLexem)
if ( correspondLexem ) { {
if (correspondLexem)
{
*correspondLexem = ld->waste.head; *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; tmp = ptr->next;
pfree(ptr); pfree(ptr);
ptr = tmp; ptr = tmp;
@ -81,11 +94,14 @@ setCorrLex(LexizeData *ld, ParsedLex **correspondLexem) {
} }
static void static void
moveToWaste(LexizeData *ld, ParsedLex *stop) { moveToWaste(LexizeData * ld, ParsedLex * stop)
{
bool go = true; bool go = true;
while( ld->towork.head && go) { while (ld->towork.head && go)
if (ld->towork.head == stop) { {
if (ld->towork.head == stop)
{
ld->curSub = stop->next; ld->curSub = stop->next;
go = false; go = false;
} }
@ -94,48 +110,55 @@ moveToWaste(LexizeData *ld, ParsedLex *stop) {
} }
static void static void
setNewTmpRes(LexizeData *ld, ParsedLex *lex, TSLexeme *res) { setNewTmpRes(LexizeData * ld, ParsedLex * lex, TSLexeme * res)
if ( ld->tmpRes ) { {
if (ld->tmpRes)
{
TSLexeme *ptr; TSLexeme *ptr;
for( ptr=ld->tmpRes; ptr->lexeme; ptr++ )
pfree( ptr->lexeme ); for (ptr = ld->tmpRes; ptr->lexeme; ptr++)
pfree( ld->tmpRes ); pfree(ptr->lexeme);
pfree(ld->tmpRes);
} }
ld->tmpRes = res; ld->tmpRes = res;
ld->lastRes = lex; ld->lastRes = lex;
} }
TSLexeme* TSLexeme *
LexizeExec(LexizeData *ld, ParsedLex **correspondLexem) { LexizeExec(LexizeData * ld, ParsedLex ** correspondLexem)
{
int i; int i;
ListDictionary *map; ListDictionary *map;
DictInfo *dict; DictInfo *dict;
TSLexeme *res; TSLexeme *res;
if ( ld->curDictId == InvalidOid ) { if (ld->curDictId == InvalidOid)
{
/* /*
* usial mode: dictionary wants only one word, * usial mode: dictionary wants only one word, but we should keep in
* but we should keep in mind that we should go through * mind that we should go through all stack
* all stack
*/ */
while( ld->towork.head ) { while (ld->towork.head)
{
ParsedLex *curVal = ld->towork.head; ParsedLex *curVal = ld->towork.head;
map = ld->cfg->map + curVal->type; 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 */ /* skip this type of lexeme */
RemoveHead(ld); RemoveHead(ld);
continue; continue;
} }
for (i = ld->posDict; i < map->len; i++) { for (i = ld->posDict; i < map->len; i++)
{
dict = finddict(DatumGetObjectId(map->dict_id[i])); dict = finddict(DatumGetObjectId(map->dict_id[i]));
ld->dictState.isend = ld->dictState.getnext = false; ld->dictState.isend = ld->dictState.getnext = false;
ld->dictState.private = NULL; ld->dictState.private = NULL;
res = (TSLexeme *) DatumGetPointer( FunctionCall4( res = (TSLexeme *) DatumGetPointer(FunctionCall4(
&(dict->lexize_info), &(dict->lexize_info),
PointerGetDatum(dict->dictionary), PointerGetDatum(dict->dictionary),
PointerGetDatum(curVal->lemm), PointerGetDatum(curVal->lemm),
@ -143,16 +166,17 @@ LexizeExec(LexizeData *ld, ParsedLex **correspondLexem) {
PointerGetDatum(&ld->dictState) PointerGetDatum(&ld->dictState)
)); ));
if ( ld->dictState.getnext ) { if (ld->dictState.getnext)
{
/* /*
* dictinary wants next word, so setup and store * dictinary wants next word, so setup and store current
* current position and go to multiword mode * position and go to multiword mode
*/ */
ld->curDictId = DatumGetObjectId(map->dict_id[i]); ld->curDictId = DatumGetObjectId(map->dict_id[i]);
ld->posDict = i+1; ld->posDict = i + 1;
ld->curSub = curVal->next; ld->curSub = curVal->next;
if ( res ) if (res)
setNewTmpRes(ld, curVal, res); setNewTmpRes(ld, curVal, res);
return LexizeExec(ld, correspondLexem); return LexizeExec(ld, correspondLexem);
} }
@ -167,37 +191,43 @@ LexizeExec(LexizeData *ld, ParsedLex **correspondLexem) {
RemoveHead(ld); RemoveHead(ld);
} }
} else { /* curDictId is valid */ }
else
{ /* curDictId is valid */
dict = finddict(ld->curDictId); dict = finddict(ld->curDictId);
/* /*
* Dictionary ld->curDictId asks us about following words * Dictionary ld->curDictId asks us about following words
*/ */
while( ld->curSub ) { while (ld->curSub)
{
ParsedLex *curVal = ld->curSub; ParsedLex *curVal = ld->curSub;
map = ld->cfg->map + curVal->type; map = ld->cfg->map + curVal->type;
if (curVal->type != 0) { if (curVal->type != 0)
{
bool dictExists = false; 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 */ /* skip this type of lexeme */
ld->curSub = curVal->next; ld->curSub = curVal->next;
continue; continue;
} }
/* /*
* We should be sure that current type of lexeme is recognized by * We should be sure that current type of lexeme is recognized
* our dictinonary: we just check is it exist in * by our dictinonary: we just check is it exist in list of
* list of dictionaries ? * dictionaries ?
*/ */
for(i=0;i < map->len && !dictExists; i++) for (i = 0; i < map->len && !dictExists; i++)
if ( ld->curDictId == DatumGetObjectId(map->dict_id[i]) ) if (ld->curDictId == DatumGetObjectId(map->dict_id[i]))
dictExists = true; dictExists = true;
if ( !dictExists ) { if (!dictExists)
{
/* /*
* Dictionary can't work with current tpe of lexeme, * Dictionary can't work with current tpe of lexeme,
* return to basic mode and redo all stored lexemes * return to basic mode and redo all stored lexemes
@ -207,10 +237,10 @@ LexizeExec(LexizeData *ld, ParsedLex **correspondLexem) {
} }
} }
ld->dictState.isend = (curVal->type==0) ? true : false; ld->dictState.isend = (curVal->type == 0) ? true : false;
ld->dictState.getnext = false; ld->dictState.getnext = false;
res = (TSLexeme *) DatumGetPointer( FunctionCall4( res = (TSLexeme *) DatumGetPointer(FunctionCall4(
&(dict->lexize_info), &(dict->lexize_info),
PointerGetDatum(dict->dictionary), PointerGetDatum(dict->dictionary),
PointerGetDatum(curVal->lemm), PointerGetDatum(curVal->lemm),
@ -218,25 +248,30 @@ LexizeExec(LexizeData *ld, ParsedLex **correspondLexem) {
PointerGetDatum(&ld->dictState) PointerGetDatum(&ld->dictState)
)); ));
if ( ld->dictState.getnext ) { if (ld->dictState.getnext)
{
/* Dictionary wants one more */ /* Dictionary wants one more */
ld->curSub = curVal->next; ld->curSub = curVal->next;
if ( res ) if (res)
setNewTmpRes(ld, curVal, res); setNewTmpRes(ld, curVal, res);
continue; continue;
} }
if ( res || ld->tmpRes ) { if (res || ld->tmpRes)
{
/* /*
* Dictionary normalizes lexemes, * Dictionary normalizes lexemes, so we remove from stack all
* so we remove from stack all used lexemes , * used lexemes , return to basic mode and redo end of stack
* return to basic mode and redo end of stack (if it exists) * (if it exists)
*/ */
if ( res ) { if (res)
moveToWaste( ld, ld->curSub ); {
} else { moveToWaste(ld, ld->curSub);
}
else
{
res = ld->tmpRes; res = ld->tmpRes;
moveToWaste( ld, ld->lastRes ); moveToWaste(ld, ld->lastRes);
} }
/* reset to initial state */ /* reset to initial state */
@ -248,8 +283,10 @@ LexizeExec(LexizeData *ld, ParsedLex **correspondLexem) {
return res; 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; ld->curDictId = InvalidOid;
return LexizeExec(ld, correspondLexem); return LexizeExec(ld, correspondLexem);
} }
@ -258,4 +295,3 @@ LexizeExec(LexizeData *ld, ParsedLex **correspondLexem) {
setCorrLex(ld, correspondLexem); setCorrLex(ld, correspondLexem);
return NULL; return NULL;
} }

View File

@ -70,27 +70,27 @@ char2wchar(wchar_t *to, const char *from, size_t len)
return mbstowcs(to, from, len); return mbstowcs(to, from, len);
} }
#endif /* WIN32 */ #endif /* WIN32 */
int int
_t_isalpha( const char *ptr ) { _t_isalpha(const char *ptr)
{
wchar_t character; wchar_t character;
char2wchar(&character, ptr, 1); char2wchar(&character, ptr, 1);
return iswalpha( (wint_t)character ); return iswalpha((wint_t) character);
} }
int int
_t_isprint( const char *ptr ) { _t_isprint(const char *ptr)
{
wchar_t character; wchar_t character;
char2wchar(&character, ptr, 1); char2wchar(&character, ptr, 1);
return iswprint( (wint_t)character ); return iswprint((wint_t) character);
} }
#endif /* TS_USE_WIDE */ #endif /* TS_USE_WIDE */
char * char *
@ -99,25 +99,30 @@ lowerstr(char *str)
char *ptr = str; char *ptr = str;
#ifdef TS_USE_WIDE #ifdef TS_USE_WIDE
/* /*
* Use wide char code only when max encoding length > 1 and ctype != C. * 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. * 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 * Also, for a C locale there is no need to process as multibyte. From
* backend/utils/adt/oracle_compat.c Teodor * backend/utils/adt/oracle_compat.c Teodor
*/ */
if (pg_database_encoding_max_length() > 1 && !lc_ctype_is_c()) { if (pg_database_encoding_max_length() > 1 && !lc_ctype_is_c())
wchar_t *wstr, *wptr; {
wchar_t *wstr,
*wptr;
int len = strlen(str); int len = strlen(str);
wptr = wstr = (wchar_t *) palloc(sizeof(wchar_t) * (len+1)); wptr = wstr = (wchar_t *) palloc(sizeof(wchar_t) * (len + 1));
char2wchar(wstr, str, len+1); char2wchar(wstr, str, len + 1);
while (*wptr) { while (*wptr)
{
*wptr = towlower((wint_t) *wptr); *wptr = towlower((wint_t) *wptr);
wptr++; wptr++;
} }
wchar2char(str, wstr, len); wchar2char(str, wstr, len);
pfree( wstr ); pfree(wstr);
} else }
else
#endif #endif
while (*ptr) while (*ptr)
{ {
@ -126,4 +131,3 @@ lowerstr(char *str)
} }
return str; return str;
} }

View File

@ -44,9 +44,11 @@ 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_isdigit(x) ( pg_mblen(x)==1 && isdigit( TOUCHAR(x) ) )
#define t_isspace(x) ( pg_mblen(x)==1 && isspace( TOUCHAR(x) ) ) #define t_isspace(x) ( pg_mblen(x)==1 && isspace( TOUCHAR(x) ) )
extern int _t_isalpha( const char *ptr ); extern int _t_isalpha(const char *ptr);
#define t_isalpha(x) ( (pg_mblen(x)==1) ? isalpha( TOUCHAR(x) ) : _t_isalpha(x) ) #define t_isalpha(x) ( (pg_mblen(x)==1) ? isalpha( TOUCHAR(x) ) : _t_isalpha(x) )
extern int _t_isprint( const char *ptr ); extern int _t_isprint(const char *ptr);
#define t_isprint(x) ( (pg_mblen(x)==1) ? isprint( TOUCHAR(x) ) : _t_isprint(x) ) #define t_isprint(x) ( (pg_mblen(x)==1) ? isprint( TOUCHAR(x) ) : _t_isprint(x) )
/* /*
* t_iseq() should be called only for ASCII symbols * 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); \ TOUCHAR((d)+lll) = TOUCHAR((s)+lll); \
} while(0) } while(0)
#else /* not def TS_USE_WIDE */ #else /* not def TS_USE_WIDE */
#define t_isdigit(x) isdigit( TOUCHAR(x) ) #define t_isdigit(x) isdigit( TOUCHAR(x) )
@ -70,9 +71,8 @@ extern int _t_isprint( const char *ptr );
#define t_iseq(x,c) ( TOUCHAR(x) == ((unsigned char)(c)) ) #define t_iseq(x,c) ( TOUCHAR(x) == ((unsigned char)(c)) )
#define COPYCHAR(d,s) TOUCHAR(d) = TOUCHAR(s) #define COPYCHAR(d,s) TOUCHAR(d) = TOUCHAR(s)
#endif #endif
char* lowerstr(char *str); char *lowerstr(char *str);
#endif /* __TSLOCALE_H__ */ #endif /* __TSLOCALE_H__ */

View File

@ -477,7 +477,8 @@ ts_stat_sql(text *txt, text *ws)
buf = VARDATA(ws); buf = VARDATA(ws);
while (buf - VARDATA(ws) < VARSIZE(ws) - VARHDRSZ) while (buf - VARDATA(ws) < VARSIZE(ws) - VARHDRSZ)
{ {
if ( pg_mblen(buf) == 1 ) { if (pg_mblen(buf) == 1)
{
switch (*buf) switch (*buf)
{ {
case 'A': case 'A':
@ -500,7 +501,7 @@ ts_stat_sql(text *txt, text *ws)
stat->weight |= 0; stat->weight |= 0;
} }
} }
buf+=pg_mblen(buf); buf += pg_mblen(buf);
} }
} }

View File

@ -200,9 +200,9 @@ gettoken_tsvector(TI_IN_STATE * state)
{ {
if (*(state->prsbuf) == '\0') if (*(state->prsbuf) == '\0')
return 0; return 0;
else if ( t_iseq(state->prsbuf, '\'') ) else if (t_iseq(state->prsbuf, '\''))
state->state = WAITENDCMPLX; state->state = WAITENDCMPLX;
else if ( t_iseq(state->prsbuf, '\\') ) else if (t_iseq(state->prsbuf, '\\'))
{ {
state->state = WAITNEXTCHAR; state->state = WAITNEXTCHAR;
oldstate = WAITENDWORD; oldstate = WAITENDWORD;
@ -214,7 +214,7 @@ gettoken_tsvector(TI_IN_STATE * state)
else if (!t_isspace(state->prsbuf)) else if (!t_isspace(state->prsbuf))
{ {
COPYCHAR(state->curpos, state->prsbuf); COPYCHAR(state->curpos, state->prsbuf);
state->curpos+=pg_mblen(state->prsbuf); state->curpos += pg_mblen(state->prsbuf);
state->state = WAITENDWORD; state->state = WAITENDWORD;
} }
} }
@ -228,18 +228,18 @@ gettoken_tsvector(TI_IN_STATE * state)
{ {
RESIZEPRSBUF; RESIZEPRSBUF;
COPYCHAR(state->curpos, state->prsbuf); COPYCHAR(state->curpos, state->prsbuf);
state->curpos+=pg_mblen(state->prsbuf); state->curpos += pg_mblen(state->prsbuf);
state->state = oldstate; state->state = oldstate;
} }
} }
else if (state->state == WAITENDWORD) else if (state->state == WAITENDWORD)
{ {
if ( t_iseq(state->prsbuf, '\\') ) if (t_iseq(state->prsbuf, '\\'))
{ {
state->state = WAITNEXTCHAR; state->state = WAITNEXTCHAR;
oldstate = WAITENDWORD; oldstate = WAITENDWORD;
} }
else if ( t_isspace(state->prsbuf) || *(state->prsbuf) == '\0' || else if (t_isspace(state->prsbuf) || *(state->prsbuf) == '\0' ||
(state->oprisdelim && ISOPERATOR(state->prsbuf))) (state->oprisdelim && ISOPERATOR(state->prsbuf)))
{ {
RESIZEPRSBUF; RESIZEPRSBUF;
@ -250,7 +250,7 @@ gettoken_tsvector(TI_IN_STATE * state)
*(state->curpos) = '\0'; *(state->curpos) = '\0';
return 1; return 1;
} }
else if ( t_iseq(state->prsbuf,':') ) else if (t_iseq(state->prsbuf, ':'))
{ {
if (state->curpos == state->word) if (state->curpos == state->word)
ereport(ERROR, ereport(ERROR,
@ -266,15 +266,16 @@ gettoken_tsvector(TI_IN_STATE * state)
{ {
RESIZEPRSBUF; RESIZEPRSBUF;
COPYCHAR(state->curpos, state->prsbuf); COPYCHAR(state->curpos, state->prsbuf);
state->curpos+=pg_mblen(state->prsbuf); state->curpos += pg_mblen(state->prsbuf);
} }
} }
else if (state->state == WAITENDCMPLX) else if (state->state == WAITENDCMPLX)
{ {
if ( t_iseq(state->prsbuf, '\'') ) { if (t_iseq(state->prsbuf, '\''))
{
state->state = WAITCHARCMPLX; state->state = WAITCHARCMPLX;
} }
else if ( t_iseq(state->prsbuf, '\\') ) else if (t_iseq(state->prsbuf, '\\'))
{ {
state->state = WAITNEXTCHAR; state->state = WAITNEXTCHAR;
oldstate = WAITENDCMPLX; oldstate = WAITENDCMPLX;
@ -287,18 +288,20 @@ gettoken_tsvector(TI_IN_STATE * state)
{ {
RESIZEPRSBUF; RESIZEPRSBUF;
COPYCHAR(state->curpos, state->prsbuf); COPYCHAR(state->curpos, state->prsbuf);
state->curpos+=pg_mblen(state->prsbuf); state->curpos += pg_mblen(state->prsbuf);
} }
} }
else if (state->state == WAITCHARCMPLX) else if (state->state == WAITCHARCMPLX)
{ {
if ( t_iseq(state->prsbuf, '\'') ) if (t_iseq(state->prsbuf, '\''))
{ {
RESIZEPRSBUF; RESIZEPRSBUF;
COPYCHAR(state->curpos, state->prsbuf); COPYCHAR(state->curpos, state->prsbuf);
state->curpos+=pg_mblen(state->prsbuf); state->curpos += pg_mblen(state->prsbuf);
state->state = WAITENDCMPLX; state->state = WAITENDCMPLX;
} else { }
else
{
RESIZEPRSBUF; RESIZEPRSBUF;
*(state->curpos) = '\0'; *(state->curpos) = '\0';
if (state->curpos == state->word) if (state->curpos == state->word)
@ -317,7 +320,7 @@ gettoken_tsvector(TI_IN_STATE * state)
} }
else if (state->state == WAITPOSINFO) else if (state->state == WAITPOSINFO)
{ {
if ( t_iseq(state->prsbuf, ':') ) if (t_iseq(state->prsbuf, ':'))
state->state = INPOSINFO; state->state = INPOSINFO;
else else
return 1; return 1;
@ -353,9 +356,9 @@ gettoken_tsvector(TI_IN_STATE * state)
} }
else if (state->state == WAITPOSDELIM) else if (state->state == WAITPOSDELIM)
{ {
if ( t_iseq(state->prsbuf, ',') ) if (t_iseq(state->prsbuf, ','))
state->state = INPOSINFO; state->state = INPOSINFO;
else if ( t_iseq(state->prsbuf, 'a') || t_iseq(state->prsbuf, 'A') || t_iseq(state->prsbuf, '*') ) else if (t_iseq(state->prsbuf, 'a') || t_iseq(state->prsbuf, 'A') || t_iseq(state->prsbuf, '*'))
{ {
if (WEP_GETWEIGHT(state->pos[*(uint16 *) (state->pos)])) if (WEP_GETWEIGHT(state->pos[*(uint16 *) (state->pos)]))
ereport(ERROR, ereport(ERROR,
@ -363,7 +366,7 @@ gettoken_tsvector(TI_IN_STATE * state)
errmsg("syntax error"))); errmsg("syntax error")));
WEP_SETWEIGHT(state->pos[*(uint16 *) (state->pos)], 3); WEP_SETWEIGHT(state->pos[*(uint16 *) (state->pos)], 3);
} }
else if ( t_iseq(state->prsbuf, 'b') || t_iseq(state->prsbuf, 'B') ) else if (t_iseq(state->prsbuf, 'b') || t_iseq(state->prsbuf, 'B'))
{ {
if (WEP_GETWEIGHT(state->pos[*(uint16 *) (state->pos)])) if (WEP_GETWEIGHT(state->pos[*(uint16 *) (state->pos)]))
ereport(ERROR, ereport(ERROR,
@ -371,7 +374,7 @@ gettoken_tsvector(TI_IN_STATE * state)
errmsg("syntax error"))); errmsg("syntax error")));
WEP_SETWEIGHT(state->pos[*(uint16 *) (state->pos)], 2); WEP_SETWEIGHT(state->pos[*(uint16 *) (state->pos)], 2);
} }
else if ( t_iseq(state->prsbuf, 'c') || t_iseq(state->prsbuf, 'C') ) else if (t_iseq(state->prsbuf, 'c') || t_iseq(state->prsbuf, 'C'))
{ {
if (WEP_GETWEIGHT(state->pos[*(uint16 *) (state->pos)])) if (WEP_GETWEIGHT(state->pos[*(uint16 *) (state->pos)]))
ereport(ERROR, ereport(ERROR,
@ -379,7 +382,7 @@ gettoken_tsvector(TI_IN_STATE * state)
errmsg("syntax error"))); errmsg("syntax error")));
WEP_SETWEIGHT(state->pos[*(uint16 *) (state->pos)], 1); WEP_SETWEIGHT(state->pos[*(uint16 *) (state->pos)], 1);
} }
else if ( t_iseq(state->prsbuf, 'd') || t_iseq(state->prsbuf, 'D') ) else if (t_iseq(state->prsbuf, 'd') || t_iseq(state->prsbuf, 'D'))
{ {
if (WEP_GETWEIGHT(state->pos[*(uint16 *) (state->pos)])) if (WEP_GETWEIGHT(state->pos[*(uint16 *) (state->pos)]))
ereport(ERROR, ereport(ERROR,
@ -400,7 +403,7 @@ gettoken_tsvector(TI_IN_STATE * state)
elog(ERROR, "internal error"); elog(ERROR, "internal error");
/* get next char */ /* get next char */
state->prsbuf+=pg_mblen(state->prsbuf); state->prsbuf += pg_mblen(state->prsbuf);
} }
return 0; return 0;
@ -423,7 +426,7 @@ tsvector_in(PG_FUNCTION_ARGS)
SET_FUNCOID(); SET_FUNCOID();
pg_verifymbstr( buf, strlen(buf), false ); pg_verifymbstr(buf, strlen(buf), false);
state.prsbuf = buf; state.prsbuf = buf;
state.len = 32; state.len = 32;
state.word = (char *) palloc(state.len); state.word = (char *) palloc(state.len);
@ -517,13 +520,14 @@ tsvector_out(PG_FUNCTION_ARGS)
lenbuf = 0, lenbuf = 0,
pp; pp;
WordEntry *ptr = ARRPTR(out); WordEntry *ptr = ARRPTR(out);
char *curbegin, *curin, char *curbegin,
*curin,
*curout; *curout;
lenbuf = out->size * 2 /* '' */ + out->size - 1 /* space */ + 2 /* \0 */ ; lenbuf = out->size * 2 /* '' */ + out->size - 1 /* space */ + 2 /* \0 */ ;
for (i = 0; i < out->size; i++) for (i = 0; i < out->size; i++)
{ {
lenbuf += ptr[i].len * 2 * pg_database_encoding_max_length()/* for escape */ ; lenbuf += ptr[i].len * 2 * pg_database_encoding_max_length() /* for escape */ ;
if (ptr[i].haspos) if (ptr[i].haspos)
lenbuf += 7 * POSDATALEN(out, &(ptr[i])); lenbuf += 7 * POSDATALEN(out, &(ptr[i]));
} }
@ -535,10 +539,11 @@ tsvector_out(PG_FUNCTION_ARGS)
if (i != 0) if (i != 0)
*curout++ = ' '; *curout++ = ' ';
*curout++ = '\''; *curout++ = '\'';
while ( curin-curbegin < ptr->len ) while (curin - curbegin < ptr->len)
{ {
int len = pg_mblen(curin); int len = pg_mblen(curin);
if ( t_iseq(curin, '\'') )
if (t_iseq(curin, '\''))
{ {
int4 pos = curout - outbuf; int4 pos = curout - outbuf;
@ -546,7 +551,7 @@ tsvector_out(PG_FUNCTION_ARGS)
curout = outbuf + pos; curout = outbuf + pos;
*curout++ = '\''; *curout++ = '\'';
} }
while(len--) while (len--)
*curout++ = *curin++; *curout++ = *curin++;
} }
*curout++ = '\''; *curout++ = '\'';
@ -987,32 +992,45 @@ silly_cmp_tsvector(const tsvector * a, const tsvector * b)
int res; int res;
for(i=0;i<a->size;i++) { for (i = 0; i < a->size; i++)
if ( aptr->haspos != bptr->haspos ) { {
return ( aptr->haspos > bptr->haspos ) ? -1 : 1; if (aptr->haspos != bptr->haspos)
} else if ( aptr->len != bptr->len ) { {
return ( aptr->len > bptr->len ) ? -1 : 1; return (aptr->haspos > bptr->haspos) ? -1 : 1;
} else if ( (res=strncmp(STRPTR(a) + aptr->pos, STRPTR(b) + bptr->pos, bptr->len))!= 0 ) { }
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)
{
return res; return res;
} else if ( aptr->haspos ) { }
else if (aptr->haspos)
{
WordEntryPos *ap = POSDATAPTR(a, aptr); WordEntryPos *ap = POSDATAPTR(a, aptr);
WordEntryPos *bp = POSDATAPTR(b, bptr); WordEntryPos *bp = POSDATAPTR(b, bptr);
int j; int j;
if ( POSDATALEN(a, aptr) != POSDATALEN(b, bptr) ) if (POSDATALEN(a, aptr) != POSDATALEN(b, bptr))
return ( POSDATALEN(a, aptr) > POSDATALEN(b, bptr) ) ? -1 : 1; return (POSDATALEN(a, aptr) > POSDATALEN(b, bptr)) ? -1 : 1;
for(j=0;j<POSDATALEN(a, aptr);j++) { for (j = 0; j < POSDATALEN(a, aptr); j++)
if ( WEP_GETPOS(*ap) != WEP_GETPOS(*bp) ) { {
return ( WEP_GETPOS(*ap) > WEP_GETPOS(*bp) ) ? -1 : 1; if (WEP_GETPOS(*ap) != WEP_GETPOS(*bp))
} else if ( WEP_GETWEIGHT(*ap) != WEP_GETWEIGHT(*bp) ) { {
return ( WEP_GETWEIGHT(*ap) > WEP_GETWEIGHT(*bp) ) ? -1 : 1; return (WEP_GETPOS(*ap) > WEP_GETPOS(*bp)) ? -1 : 1;
}
else if (WEP_GETWEIGHT(*ap) != WEP_GETWEIGHT(*bp))
{
return (WEP_GETWEIGHT(*ap) > WEP_GETWEIGHT(*bp)) ? -1 : 1;
} }
ap++, bp++; ap++, bp++;
} }
} }
aptr++; bptr++; aptr++;
bptr++;
} }
} }

View File

@ -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" #include "postgres.h"
@ -458,7 +458,7 @@ static TParserStateActionItem actionTPS_InVerVersion[] = {
static TParserStateActionItem actionTPS_InSVerVersion[] = { static TParserStateActionItem actionTPS_InSVerVersion[] = {
{p_isEOF, 0, A_POP, TPS_Null, 0, NULL}, {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
{p_isdigit, 0, A_BINGO|A_CLRALL, TPS_InUnsignedInt, SPACE, NULL}, {p_isdigit, 0, A_BINGO | A_CLRALL, TPS_InUnsignedInt, SPACE, NULL},
{NULL, 0, A_NEXT, TPS_Null, 0, NULL} {NULL, 0, A_NEXT, TPS_Null, 0, NULL}
}; };
@ -613,7 +613,7 @@ static TParserStateActionItem actionTPS_InTagEnd[] = {
static TParserStateActionItem actionTPS_InCommentFirst[] = { static TParserStateActionItem actionTPS_InCommentFirst[] = {
{p_isEOF, 0, A_POP, TPS_Null, 0, NULL}, {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
{p_iseqC, '-', A_NEXT, TPS_InCommentLast, 0, NULL}, {p_iseqC, '-', A_NEXT, TPS_InCommentLast, 0, NULL},
/* <!DOCTYPE ...>*/ /* <!DOCTYPE ...> */
{p_iseqC, 'D', A_NEXT, TPS_InTag, 0, NULL}, {p_iseqC, 'D', A_NEXT, TPS_InTag, 0, NULL},
{p_iseqC, 'd', A_NEXT, TPS_InTag, 0, NULL}, {p_iseqC, 'd', A_NEXT, TPS_InTag, 0, NULL},
{NULL, 0, A_POP, TPS_Null, 0, NULL} {NULL, 0, A_POP, TPS_Null, 0, NULL}
@ -753,10 +753,10 @@ static TParserStateActionItem actionTPS_InPathFirstFirst[] = {
}; };
static TParserStateActionItem actionTPS_InPathSecond[] = { static TParserStateActionItem actionTPS_InPathSecond[] = {
{p_isEOF, 0, A_BINGO|A_CLEAR, TPS_Base, FILEPATH, NULL}, {p_isEOF, 0, A_BINGO | A_CLEAR, TPS_Base, FILEPATH, NULL},
{p_iseqC, '/', A_NEXT|A_PUSH, TPS_InFileFirst, 0, NULL}, {p_iseqC, '/', A_NEXT | A_PUSH, TPS_InFileFirst, 0, NULL},
{p_iseqC, '/', A_BINGO|A_CLEAR, TPS_Base, FILEPATH, NULL}, {p_iseqC, '/', A_BINGO | A_CLEAR, TPS_Base, FILEPATH, NULL},
{p_isspace, 0, A_BINGO|A_CLEAR, TPS_Base, FILEPATH, NULL}, {p_isspace, 0, A_BINGO | A_CLEAR, TPS_Base, FILEPATH, NULL},
{NULL, 0, A_POP, TPS_Null, 0, NULL} {NULL, 0, A_POP, TPS_Null, 0, NULL}
}; };

View File

@ -16,7 +16,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */

View File

@ -9,7 +9,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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, * If we are supposed to emit row descriptions, then send the tuple
* then send the tuple descriptor of the tuples. * descriptor of the tuples.
*/ */
if (myState->sendDescrip) if (myState->sendDescrip)
SendRowDescriptionMessage(typeinfo, SendRowDescriptionMessage(typeinfo,

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * If CREATE/SET, add new options to array; if RESET, just check that the
* the user didn't say RESET (option=val). (Must do this because the * user didn't say RESET (option=val). (Must do this because the grammar
* grammar doesn't enforce it.) * doesn't enforce it.)
*/ */
foreach(cell, defList) foreach(cell, defList)
{ {
@ -121,8 +121,8 @@ transformRelOptions(Datum oldOptions, List *defList,
continue; continue;
/* /*
* Flatten the DefElem into a text string like "name=arg". * Flatten the DefElem into a text string like "name=arg". If we
* If we have just "name", assume "name=true" is meant. * have just "name", assume "name=true" is meant.
*/ */
if (def->arg != NULL) if (def->arg != NULL)
value = defGetString(def); value = defGetString(def);
@ -163,7 +163,7 @@ transformRelOptions(Datum oldOptions, List *defList,
* containing the corresponding value, or NULL if the keyword does not appear. * containing the corresponding value, or NULL if the keyword does not appear.
*/ */
void void
parseRelOptions(Datum options, int numkeywords, const char * const *keywords, parseRelOptions(Datum options, int numkeywords, const char *const * keywords,
char **values, bool validate) char **values, bool validate)
{ {
ArrayType *array; ArrayType *array;
@ -240,7 +240,7 @@ bytea *
default_reloptions(Datum reloptions, bool validate, default_reloptions(Datum reloptions, bool validate,
int minFillfactor, int defaultFillfactor) int minFillfactor, int defaultFillfactor)
{ {
static const char * const default_keywords[1] = { "fillfactor" }; static const char *const default_keywords[1] = {"fillfactor"};
char *values[1]; char *values[1];
int32 fillfactor; int32 fillfactor;
StdRdOptions *result; StdRdOptions *result;
@ -249,8 +249,8 @@ default_reloptions(Datum reloptions, bool validate,
/* /*
* If no options, we can just return NULL rather than doing anything. * If no options, we can just return NULL rather than doing anything.
* (defaultFillfactor is thus not used, but we require callers to pass * (defaultFillfactor is thus not used, but we require callers to pass it
* it anyway since we would need it if more options were added.) * anyway since we would need it if more options were added.)
*/ */
if (values[0] == NULL) if (values[0] == NULL)
return NULL; return NULL;

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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" #include "postgres.h"
@ -35,15 +35,19 @@
* Function used as extractValue and extractQuery both * Function used as extractValue and extractQuery both
*/ */
Datum Datum
ginarrayextract(PG_FUNCTION_ARGS) { ginarrayextract(PG_FUNCTION_ARGS)
{
ArrayType *array; ArrayType *array;
uint32 *nentries = (uint32*)PG_GETARG_POINTER(1); uint32 *nentries = (uint32 *) PG_GETARG_POINTER(1);
Datum *entries = NULL; Datum *entries = NULL;
int16 elmlen; int16 elmlen;
bool elmbyval; bool elmbyval;
char elmalign; 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); array = PG_GETARG_ARRAYTYPE_P_COPY(0);
ARRAYCHECK(array); ARRAYCHECK(array);
@ -54,22 +58,26 @@ ginarrayextract(PG_FUNCTION_ARGS) {
deconstruct_array(array, deconstruct_array(array,
ARR_ELEMTYPE(array), ARR_ELEMTYPE(array),
elmlen, elmbyval, elmalign, elmlen, elmbyval, elmalign,
&entries, NULL, (int*)nentries); &entries, NULL, (int *) nentries);
/* we should not free array, entries[i] points into it */ /* we should not free array, entries[i] points into it */
PG_RETURN_POINTER(entries); PG_RETURN_POINTER(entries);
} }
Datum Datum
ginarrayconsistent(PG_FUNCTION_ARGS) { ginarrayconsistent(PG_FUNCTION_ARGS)
bool *check = (bool*)PG_GETARG_POINTER(0); {
bool *check = (bool *) PG_GETARG_POINTER(0);
StrategyNumber strategy = PG_GETARG_UINT16(1); StrategyNumber strategy = PG_GETARG_UINT16(1);
ArrayType *query = PG_GETARG_ARRAYTYPE_P(2); ArrayType *query = PG_GETARG_ARRAYTYPE_P(2);
int res, i, nentries; int res,
i,
nentries;
/* ARRAYCHECK was already done by previous ginarrayextract call */ /* ARRAYCHECK was already done by previous ginarrayextract call */
switch( strategy ) { switch (strategy)
{
case GinOverlapStrategy: case GinOverlapStrategy:
case GinContainedStrategy: case GinContainedStrategy:
/* at least one element in check[] is true, so result = true */ /* at least one element in check[] is true, so result = true */
@ -77,10 +85,11 @@ ginarrayconsistent(PG_FUNCTION_ARGS) {
break; break;
case GinContainsStrategy: case GinContainsStrategy:
case GinEqualStrategy: case GinEqualStrategy:
nentries=ArrayGetNItems(ARR_NDIM(query), ARR_DIMS(query)); nentries = ArrayGetNItems(ARR_NDIM(query), ARR_DIMS(query));
res = TRUE; res = TRUE;
for(i=0;i<nentries;i++) for (i = 0; i < nentries; i++)
if ( !check[i] ) { if (!check[i])
{
res = FALSE; res = FALSE;
break; break;
} }

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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. * Locks buffer by needed method for search.
*/ */
static int static int
ginTraverseLock(Buffer buffer, bool searchMode) { ginTraverseLock(Buffer buffer, bool searchMode)
{
Page page; Page page;
int access=GIN_SHARE; int access = GIN_SHARE;
LockBuffer(buffer, GIN_SHARE); LockBuffer(buffer, GIN_SHARE);
page = BufferGetPage( buffer ); page = BufferGetPage(buffer);
if ( GinPageIsLeaf(page) ) { if (GinPageIsLeaf(page))
if ( searchMode == FALSE ) { {
if (searchMode == FALSE)
{
/* we should relock our page */ /* we should relock our page */
LockBuffer(buffer, GIN_UNLOCK); LockBuffer(buffer, GIN_UNLOCK);
LockBuffer(buffer, GIN_EXCLUSIVE); LockBuffer(buffer, GIN_EXCLUSIVE);
/* But root can become non-leaf during relock */ /* But root can become non-leaf during relock */
if ( !GinPageIsLeaf(page) ) { if (!GinPageIsLeaf(page))
{
/* resore old lock type (very rare) */ /* resore old lock type (very rare) */
LockBuffer(buffer, GIN_UNLOCK); LockBuffer(buffer, GIN_UNLOCK);
LockBuffer(buffer, GIN_SHARE); LockBuffer(buffer, GIN_SHARE);
} else }
else
access = GIN_EXCLUSIVE; access = GIN_EXCLUSIVE;
} }
} }
@ -45,9 +50,10 @@ ginTraverseLock(Buffer buffer, bool searchMode) {
return access; return access;
} }
GinBtreeStack* GinBtreeStack *
ginPrepareFindLeafPage(GinBtree btree, BlockNumber blkno) { ginPrepareFindLeafPage(GinBtree btree, BlockNumber blkno)
GinBtreeStack *stack = (GinBtreeStack*)palloc(sizeof(GinBtreeStack)); {
GinBtreeStack *stack = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
stack->blkno = blkno; stack->blkno = blkno;
stack->buffer = ReadBuffer(btree->index, stack->blkno); stack->buffer = ReadBuffer(btree->index, stack->blkno);
@ -62,37 +68,44 @@ ginPrepareFindLeafPage(GinBtree btree, BlockNumber blkno) {
/* /*
* Locates leaf page contained tuple * Locates leaf page contained tuple
*/ */
GinBtreeStack* GinBtreeStack *
ginFindLeafPage(GinBtree btree, GinBtreeStack *stack) { ginFindLeafPage(GinBtree btree, GinBtreeStack *stack)
bool isfirst=TRUE; {
bool isfirst = TRUE;
BlockNumber rootBlkno; BlockNumber rootBlkno;
if ( !stack ) if (!stack)
stack = ginPrepareFindLeafPage(btree, GIN_ROOT_BLKNO); stack = ginPrepareFindLeafPage(btree, GIN_ROOT_BLKNO);
rootBlkno = stack->blkno; rootBlkno = stack->blkno;
for(;;) { for (;;)
{
Page page; Page page;
BlockNumber child; BlockNumber child;
int access=GIN_SHARE; int access = GIN_SHARE;
stack->off = InvalidOffsetNumber; stack->off = InvalidOffsetNumber;
page = BufferGetPage( stack->buffer ); page = BufferGetPage(stack->buffer);
if ( isfirst ) { if (isfirst)
if ( GinPageIsLeaf(page) && !btree->searchMode ) {
if (GinPageIsLeaf(page) && !btree->searchMode)
access = GIN_EXCLUSIVE; access = GIN_EXCLUSIVE;
isfirst = FALSE; isfirst = FALSE;
} else }
else
access = ginTraverseLock(stack->buffer, btree->searchMode); 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 */ * ok, page is correctly locked, we should check to move right ..,
while( btree->fullScan==FALSE && stack->blkno != rootBlkno && btree->isMoveRight(btree, page) ) { * 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; BlockNumber rightlink = GinPageGetOpaque(page)->rightlink;
if ( rightlink==InvalidBlockNumber ) if (rightlink == InvalidBlockNumber)
/* rightmost page */ /* rightmost page */
break; break;
@ -100,25 +113,28 @@ ginFindLeafPage(GinBtree btree, GinBtreeStack *stack) {
LockBuffer(stack->buffer, GIN_UNLOCK); LockBuffer(stack->buffer, GIN_UNLOCK);
stack->buffer = ReleaseAndReadBuffer(stack->buffer, btree->index, stack->blkno); stack->buffer = ReleaseAndReadBuffer(stack->buffer, btree->index, stack->blkno);
LockBuffer(stack->buffer, access); LockBuffer(stack->buffer, access);
page = BufferGetPage( stack->buffer ); page = BufferGetPage(stack->buffer);
} }
if ( GinPageIsLeaf(page) ) /* we found, return locked page */ if (GinPageIsLeaf(page)) /* we found, return locked page */
return stack; return stack;
/* now we have correct buffer, try to find child */ /* now we have correct buffer, try to find child */
child = btree->findChildPage(btree, stack); child = btree->findChildPage(btree, stack);
LockBuffer(stack->buffer, GIN_UNLOCK); LockBuffer(stack->buffer, GIN_UNLOCK);
Assert( child != InvalidBlockNumber ); Assert(child != InvalidBlockNumber);
Assert( stack->blkno != child ); Assert(stack->blkno != child);
if ( btree->searchMode ) { if (btree->searchMode)
{
/* in search mode we may forget path to leaf */ /* in search mode we may forget path to leaf */
stack->blkno = child; stack->blkno = child;
stack->buffer = ReleaseAndReadBuffer( stack->buffer, btree->index, stack->blkno ); stack->buffer = ReleaseAndReadBuffer(stack->buffer, btree->index, stack->blkno);
} else { }
GinBtreeStack *ptr = (GinBtreeStack*)palloc(sizeof(GinBtreeStack)); else
{
GinBtreeStack *ptr = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
ptr->parent = stack; ptr->parent = stack;
stack = ptr; stack = ptr;
@ -133,13 +149,16 @@ ginFindLeafPage(GinBtree btree, GinBtreeStack *stack) {
} }
void void
freeGinBtreeStack( GinBtreeStack *stack ) { freeGinBtreeStack(GinBtreeStack *stack)
while(stack) { {
while (stack)
{
GinBtreeStack *tmp = stack->parent; GinBtreeStack *tmp = stack->parent;
if ( stack->buffer != InvalidBuffer )
if (stack->buffer != InvalidBuffer)
ReleaseBuffer(stack->buffer); ReleaseBuffer(stack->buffer);
pfree( stack ); pfree(stack);
stack = tmp; stack = tmp;
} }
} }
@ -151,75 +170,89 @@ freeGinBtreeStack( GinBtreeStack *stack ) {
* with vacuum process * with vacuum process
*/ */
void void
findParents( GinBtree btree, GinBtreeStack *stack, findParents(GinBtree btree, GinBtreeStack *stack,
BlockNumber rootBlkno) { BlockNumber rootBlkno)
{
Page page; Page page;
Buffer buffer; Buffer buffer;
BlockNumber blkno, leftmostBlkno; BlockNumber blkno,
leftmostBlkno;
OffsetNumber offset; OffsetNumber offset;
GinBtreeStack *root = stack->parent; GinBtreeStack *root = stack->parent;
GinBtreeStack *ptr; GinBtreeStack *ptr;
if ( !root ) { if (!root)
{
/* XLog mode... */ /* XLog mode... */
root = (GinBtreeStack*)palloc(sizeof(GinBtreeStack)); root = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
root->blkno = rootBlkno; root->blkno = rootBlkno;
root->buffer = ReadBuffer(btree->index, rootBlkno); root->buffer = ReadBuffer(btree->index, rootBlkno);
LockBuffer(root->buffer, GIN_EXCLUSIVE); LockBuffer(root->buffer, GIN_EXCLUSIVE);
root->parent = NULL; root->parent = NULL;
} else { }
/* find root, we should not release root page until update is finished!! */ else
while( root->parent ) { {
ReleaseBuffer( root->buffer ); /*
* find root, we should not release root page until update is
* finished!!
*/
while (root->parent)
{
ReleaseBuffer(root->buffer);
root = root->parent; root = root->parent;
} }
Assert( root->blkno == rootBlkno ); Assert(root->blkno == rootBlkno);
Assert( BufferGetBlockNumber(root->buffer) == rootBlkno ); Assert(BufferGetBlockNumber(root->buffer) == rootBlkno);
LockBuffer(root->buffer, GIN_EXCLUSIVE); LockBuffer(root->buffer, GIN_EXCLUSIVE);
} }
root->off = InvalidOffsetNumber; root->off = InvalidOffsetNumber;
page = BufferGetPage(root->buffer); page = BufferGetPage(root->buffer);
Assert( !GinPageIsLeaf(page) ); Assert(!GinPageIsLeaf(page));
/* check trivial case */ /* 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; stack->parent = root;
return; return;
} }
leftmostBlkno = blkno = btree->getLeftMostPage(btree, page); leftmostBlkno = blkno = btree->getLeftMostPage(btree, page);
LockBuffer(root->buffer, GIN_UNLOCK ); LockBuffer(root->buffer, GIN_UNLOCK);
Assert( blkno!=InvalidBlockNumber ); Assert(blkno != InvalidBlockNumber);
for(;;) { for (;;)
{
buffer = ReadBuffer(btree->index, blkno); buffer = ReadBuffer(btree->index, blkno);
LockBuffer(buffer, GIN_EXCLUSIVE); LockBuffer(buffer, GIN_EXCLUSIVE);
page = BufferGetPage(buffer); page = BufferGetPage(buffer);
if ( GinPageIsLeaf(page) ) if (GinPageIsLeaf(page))
elog(ERROR, "Lost path"); elog(ERROR, "Lost path");
leftmostBlkno = btree->getLeftMostPage(btree, page); 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; blkno = GinPageGetOpaque(page)->rightlink;
LockBuffer(buffer,GIN_UNLOCK); LockBuffer(buffer, GIN_UNLOCK);
ReleaseBuffer(buffer); ReleaseBuffer(buffer);
if ( blkno == InvalidBlockNumber ) if (blkno == InvalidBlockNumber)
break; break;
buffer = ReadBuffer(btree->index, blkno); buffer = ReadBuffer(btree->index, blkno);
LockBuffer(buffer, GIN_EXCLUSIVE); LockBuffer(buffer, GIN_EXCLUSIVE);
page = BufferGetPage(buffer); page = BufferGetPage(buffer);
} }
if ( blkno != InvalidBlockNumber ) { if (blkno != InvalidBlockNumber)
ptr = (GinBtreeStack*)palloc(sizeof(GinBtreeStack)); {
ptr = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
ptr->blkno = blkno; ptr->blkno = blkno;
ptr->buffer = buffer; 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; ptr->off = offset;
stack->parent = ptr; stack->parent = ptr;
return; return;
@ -233,29 +266,36 @@ findParents( GinBtree btree, GinBtreeStack *stack,
* Insert value (stored in GinBtree) to tree descibed by stack * Insert value (stored in GinBtree) to tree descibed by stack
*/ */
void void
ginInsertValue(GinBtree btree, GinBtreeStack *stack) { ginInsertValue(GinBtree btree, GinBtreeStack *stack)
{
GinBtreeStack *parent = stack; GinBtreeStack *parent = stack;
BlockNumber rootBlkno = InvalidBuffer; BlockNumber rootBlkno = InvalidBuffer;
Page page, rpage, lpage; Page page,
rpage,
lpage;
/* remember root BlockNumber */ /* remember root BlockNumber */
while( parent ) { while (parent)
{
rootBlkno = parent->blkno; rootBlkno = parent->blkno;
parent = parent->parent; parent = parent->parent;
} }
while( stack ) { while (stack)
{
XLogRecData *rdata; XLogRecData *rdata;
BlockNumber savedRightLink; BlockNumber savedRightLink;
page = BufferGetPage( stack->buffer ); page = BufferGetPage(stack->buffer);
savedRightLink = GinPageGetOpaque(page)->rightlink; savedRightLink = GinPageGetOpaque(page)->rightlink;
if ( btree->isEnoughSpace( btree, stack->buffer, stack->off ) ) { if (btree->isEnoughSpace(btree, stack->buffer, stack->off))
{
START_CRIT_SECTION(); START_CRIT_SECTION();
btree->placeToPage( btree, stack->buffer, stack->off, &rdata ); btree->placeToPage(btree, stack->buffer, stack->off, &rdata);
if (!btree->index->rd_istemp) { if (!btree->index->rd_istemp)
{
XLogRecPtr recptr; XLogRecPtr recptr;
recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_INSERT, rdata); recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_INSERT, rdata);
@ -263,48 +303,56 @@ ginInsertValue(GinBtree btree, GinBtreeStack *stack) {
PageSetTLI(page, ThisTimeLineID); PageSetTLI(page, ThisTimeLineID);
} }
MarkBufferDirty( stack->buffer ); MarkBufferDirty(stack->buffer);
UnlockReleaseBuffer(stack->buffer); UnlockReleaseBuffer(stack->buffer);
END_CRIT_SECTION(); END_CRIT_SECTION();
freeGinBtreeStack(stack->parent); freeGinBtreeStack(stack->parent);
return; return;
} else { }
else
{
Buffer rbuffer = GinNewBuffer(btree->index); Buffer rbuffer = GinNewBuffer(btree->index);
Page newlpage; 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
newlpage = btree->splitPage( btree, stack->buffer, rbuffer, stack->off, &rdata ); * with buffer, stack->buffer shoud be untouched
*/
newlpage = btree->splitPage(btree, stack->buffer, rbuffer, stack->off, &rdata);
((ginxlogSplit*)(rdata->data))->rootBlkno = rootBlkno; ((ginxlogSplit *) (rdata->data))->rootBlkno = rootBlkno;
parent = stack->parent; parent = stack->parent;
if ( parent == NULL ) { if (parent == NULL)
/* split root, so we need to allocate new left page and {
place pointer on root to left and right page */ /*
* 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); Buffer lbuffer = GinNewBuffer(btree->index);
((ginxlogSplit*)(rdata->data))->isRootSplit = TRUE; ((ginxlogSplit *) (rdata->data))->isRootSplit = TRUE;
((ginxlogSplit*)(rdata->data))->rrlink = InvalidBlockNumber; ((ginxlogSplit *) (rdata->data))->rrlink = InvalidBlockNumber;
page = BufferGetPage( stack->buffer ); page = BufferGetPage(stack->buffer);
lpage = BufferGetPage( lbuffer ); lpage = BufferGetPage(lbuffer);
rpage = BufferGetPage( rbuffer ); rpage = BufferGetPage(rbuffer);
GinPageGetOpaque(rpage)->rightlink = InvalidBlockNumber; GinPageGetOpaque(rpage)->rightlink = InvalidBlockNumber;
GinPageGetOpaque(newlpage)->rightlink = BufferGetBlockNumber(rbuffer); GinPageGetOpaque(newlpage)->rightlink = BufferGetBlockNumber(rbuffer);
((ginxlogSplit*)(rdata->data))->lblkno = BufferGetBlockNumber(lbuffer); ((ginxlogSplit *) (rdata->data))->lblkno = BufferGetBlockNumber(lbuffer);
START_CRIT_SECTION(); START_CRIT_SECTION();
GinInitBuffer( stack->buffer, GinPageGetOpaque(newlpage)->flags & ~GIN_LEAF ); GinInitBuffer(stack->buffer, GinPageGetOpaque(newlpage)->flags & ~GIN_LEAF);
PageRestoreTempPage( newlpage, lpage ); PageRestoreTempPage(newlpage, lpage);
btree->fillRoot( btree, stack->buffer, lbuffer, rbuffer ); btree->fillRoot(btree, stack->buffer, lbuffer, rbuffer);
if (!btree->index->rd_istemp) { if (!btree->index->rd_istemp)
{
XLogRecPtr recptr; XLogRecPtr recptr;
recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_SPLIT, rdata); recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_SPLIT, rdata);
@ -326,20 +374,23 @@ ginInsertValue(GinBtree btree, GinBtreeStack *stack) {
END_CRIT_SECTION(); END_CRIT_SECTION();
return; return;
} else { }
else
{
/* split non-root page */ /* split non-root page */
((ginxlogSplit*)(rdata->data))->isRootSplit = FALSE; ((ginxlogSplit *) (rdata->data))->isRootSplit = FALSE;
((ginxlogSplit*)(rdata->data))->rrlink = savedRightLink; ((ginxlogSplit *) (rdata->data))->rrlink = savedRightLink;
lpage = BufferGetPage( stack->buffer ); lpage = BufferGetPage(stack->buffer);
rpage = BufferGetPage( rbuffer ); rpage = BufferGetPage(rbuffer);
GinPageGetOpaque(rpage)->rightlink = savedRightLink; GinPageGetOpaque(rpage)->rightlink = savedRightLink;
GinPageGetOpaque(newlpage)->rightlink = BufferGetBlockNumber(rbuffer); GinPageGetOpaque(newlpage)->rightlink = BufferGetBlockNumber(rbuffer);
START_CRIT_SECTION(); START_CRIT_SECTION();
PageRestoreTempPage( newlpage, lpage ); PageRestoreTempPage(newlpage, lpage);
if (!btree->index->rd_istemp) { if (!btree->index->rd_istemp)
{
XLogRecPtr recptr; XLogRecPtr recptr;
recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_SPLIT, rdata); recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_SPLIT, rdata);
@ -350,7 +401,7 @@ ginInsertValue(GinBtree btree, GinBtreeStack *stack) {
} }
MarkBufferDirty(rbuffer); MarkBufferDirty(rbuffer);
UnlockReleaseBuffer(rbuffer); UnlockReleaseBuffer(rbuffer);
MarkBufferDirty( stack->buffer ); MarkBufferDirty(stack->buffer);
END_CRIT_SECTION(); END_CRIT_SECTION();
} }
} }
@ -361,31 +412,33 @@ ginInsertValue(GinBtree btree, GinBtreeStack *stack) {
LockBuffer(parent->buffer, GIN_EXCLUSIVE); LockBuffer(parent->buffer, GIN_EXCLUSIVE);
/* move right if it's needed */ /* move right if it's needed */
page = BufferGetPage( parent->buffer ); 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; BlockNumber rightlink = GinPageGetOpaque(page)->rightlink;
LockBuffer(parent->buffer, GIN_UNLOCK); LockBuffer(parent->buffer, GIN_UNLOCK);
if ( rightlink==InvalidBlockNumber ) { if (rightlink == InvalidBlockNumber)
/* rightmost page, but we don't find parent, we should {
use plain search... */ /*
* rightmost page, but we don't find parent, we should use
* plain search...
*/
findParents(btree, stack, rootBlkno); findParents(btree, stack, rootBlkno);
parent=stack->parent; parent = stack->parent;
page = BufferGetPage( parent->buffer ); page = BufferGetPage(parent->buffer);
break; break;
} }
parent->blkno = rightlink; parent->blkno = rightlink;
parent->buffer = ReleaseAndReadBuffer(parent->buffer, btree->index, parent->blkno); parent->buffer = ReleaseAndReadBuffer(parent->buffer, btree->index, parent->blkno);
LockBuffer(parent->buffer, GIN_EXCLUSIVE); LockBuffer(parent->buffer, GIN_EXCLUSIVE);
page = BufferGetPage( parent->buffer ); page = BufferGetPage(parent->buffer);
} }
UnlockReleaseBuffer(stack->buffer); UnlockReleaseBuffer(stack->buffer);
pfree( stack ); pfree(stack);
stack = parent; stack = parent;
} }
} }

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 #define DEF_NPTR 4
void void
ginInitBA(BuildAccumulator *accum) { ginInitBA(BuildAccumulator *accum)
{
accum->maxdepth = 1; accum->maxdepth = 1;
accum->stackpos = 0; accum->stackpos = 0;
accum->entries = NULL; accum->entries = NULL;
@ -31,11 +32,13 @@ ginInitBA(BuildAccumulator *accum) {
accum->entryallocator = NULL; accum->entryallocator = NULL;
} }
static EntryAccumulator* static EntryAccumulator *
EAAllocate( BuildAccumulator *accum ) { EAAllocate(BuildAccumulator *accum)
if ( accum->entryallocator == NULL || accum->length>=DEF_NENTRY ) { {
accum->entryallocator = palloc(sizeof(EntryAccumulator)*DEF_NENTRY); if (accum->entryallocator == NULL || accum->length >= DEF_NENTRY)
accum->allocatedMemory += sizeof(EntryAccumulator)*DEF_NENTRY; {
accum->entryallocator = palloc(sizeof(EntryAccumulator) * DEF_NENTRY);
accum->allocatedMemory += sizeof(EntryAccumulator) * DEF_NENTRY;
accum->length = 0; accum->length = 0;
} }
@ -48,24 +51,27 @@ EAAllocate( BuildAccumulator *accum ) {
* item pointer are ordered * item pointer are ordered
*/ */
static void static void
ginInsertData(BuildAccumulator *accum, EntryAccumulator *entry, ItemPointer heapptr) { ginInsertData(BuildAccumulator *accum, EntryAccumulator *entry, ItemPointer heapptr)
if ( entry->number >= entry->length ) { {
if (entry->number >= entry->length)
{
accum->allocatedMemory += sizeof(ItemPointerData) * entry->length; accum->allocatedMemory += sizeof(ItemPointerData) * entry->length;
entry->length *= 2; entry->length *= 2;
entry->list = (ItemPointerData*)repalloc(entry->list, entry->list = (ItemPointerData *) repalloc(entry->list,
sizeof(ItemPointerData)*entry->length); sizeof(ItemPointerData) * entry->length);
} }
if ( entry->shouldSort==FALSE ) { if (entry->shouldSort == FALSE)
int res = compareItemPointers( entry->list + entry->number - 1, heapptr ); {
int res = compareItemPointers(entry->list + entry->number - 1, heapptr);
Assert( res != 0 ); Assert(res != 0);
if ( res > 0 ) if (res > 0)
entry->shouldSort=TRUE; entry->shouldSort = TRUE;
} }
entry->list[ entry->number ] = *heapptr; entry->list[entry->number] = *heapptr;
entry->number++; entry->number++;
} }
@ -74,7 +80,8 @@ ginInsertData(BuildAccumulator *accum, EntryAccumulator *entry, ItemPointer heap
* to avoid computing the datum size twice. * to avoid computing the datum size twice.
*/ */
static Datum static Datum
getDatumCopy(BuildAccumulator *accum, Datum value) { getDatumCopy(BuildAccumulator *accum, Datum value)
{
Form_pg_attribute *att = accum->ginstate->tupdesc->attrs; Form_pg_attribute *att = accum->ginstate->tupdesc->attrs;
Datum res; Datum res;
@ -100,18 +107,22 @@ getDatumCopy(BuildAccumulator *accum, Datum value) {
* Find/store one entry from indexed value. * Find/store one entry from indexed value.
*/ */
static void static void
ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr, Datum entry) { ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr, Datum entry)
EntryAccumulator *ea = accum->entries, *pea = NULL; {
EntryAccumulator *ea = accum->entries,
*pea = NULL;
int res = 0; int res = 0;
uint32 depth = 1; uint32 depth = 1;
while( ea ) { while (ea)
{
res = compareEntries(accum->ginstate, entry, ea->value); res = compareEntries(accum->ginstate, entry, ea->value);
if ( res == 0 ) if (res == 0)
break; /* found */ break; /* found */
else { else
{
pea = ea; pea = ea;
if ( res < 0 ) if (res < 0)
ea = ea->left; ea = ea->left;
else else
ea = ea->right; ea = ea->right;
@ -119,10 +130,11 @@ ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr, Datum entry) {
depth++; depth++;
} }
if ( depth > accum->maxdepth ) if (depth > accum->maxdepth)
accum->maxdepth = depth; accum->maxdepth = depth;
if ( ea == NULL ) { if (ea == NULL)
{
ea = EAAllocate(accum); ea = EAAllocate(accum);
ea->left = ea->right = NULL; ea->left = ea->right = NULL;
@ -130,21 +142,23 @@ ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr, Datum entry) {
ea->length = DEF_NPTR; ea->length = DEF_NPTR;
ea->number = 1; ea->number = 1;
ea->shouldSort = FALSE; ea->shouldSort = FALSE;
ea->list = (ItemPointerData*)palloc(sizeof(ItemPointerData)*DEF_NPTR); ea->list = (ItemPointerData *) palloc(sizeof(ItemPointerData) * DEF_NPTR);
ea->list[0] = *heapptr; ea->list[0] = *heapptr;
accum->allocatedMemory += sizeof(ItemPointerData)*DEF_NPTR; accum->allocatedMemory += sizeof(ItemPointerData) * DEF_NPTR;
if ( pea == NULL ) if (pea == NULL)
accum->entries = ea; accum->entries = ea;
else { else
Assert( res != 0 ); {
if ( res < 0 ) Assert(res != 0);
if (res < 0)
pea->left = ea; pea->left = ea;
else else
pea->right = ea; pea->right = ea;
} }
} else }
ginInsertData( accum, ea, heapptr ); else
ginInsertData(accum, ea, heapptr);
} }
/* /*
@ -153,21 +167,22 @@ ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr, Datum entry) {
*/ */
static void static void
ginChooseElem(BuildAccumulator *accum, ItemPointer heapptr, Datum *entries, uint32 nentry, ginChooseElem(BuildAccumulator *accum, ItemPointer heapptr, Datum *entries, uint32 nentry,
uint32 low, uint32 high, uint32 offset) { uint32 low, uint32 high, uint32 offset)
{
uint32 pos; uint32 pos;
uint32 middle = (low+high)>>1; uint32 middle = (low + high) >> 1;
pos = (low+middle)>>1; pos = (low + middle) >> 1;
if ( low!=middle && pos>=offset && pos-offset < nentry ) if (low != middle && pos >= offset && pos - offset < nentry)
ginInsertEntry( accum, heapptr, entries[ pos-offset ]); ginInsertEntry(accum, heapptr, entries[pos - offset]);
pos = (high+middle+1)>>1; pos = (high + middle + 1) >> 1;
if ( middle+1 != high && pos>=offset && pos-offset < nentry ) if (middle + 1 != high && pos >= offset && pos - offset < nentry)
ginInsertEntry( accum, heapptr, entries[ pos-offset ]); ginInsertEntry(accum, heapptr, entries[pos - offset]);
if ( low!=middle ) if (low != middle)
ginChooseElem(accum, heapptr, entries, nentry, low, middle, offset ); ginChooseElem(accum, heapptr, entries, nentry, low, middle, offset);
if ( high!=middle+1 ) if (high != middle + 1)
ginChooseElem(accum, heapptr, entries, nentry, middle+1, high, offset ); ginChooseElem(accum, heapptr, entries, nentry, middle + 1, high, offset);
} }
/* /*
@ -176,56 +191,71 @@ ginChooseElem(BuildAccumulator *accum, ItemPointer heapptr, Datum *entries, uint
* next middle on left part and middle of right part. * next middle on left part and middle of right part.
*/ */
void void
ginInsertRecordBA( BuildAccumulator *accum, ItemPointer heapptr, Datum *entries, uint32 nentry ) { ginInsertRecordBA(BuildAccumulator *accum, ItemPointer heapptr, Datum *entries, uint32 nentry)
uint32 i, nbit=0, offset; {
uint32 i,
nbit = 0,
offset;
if (nentry==0) if (nentry == 0)
return; return;
i=nentry-1; i = nentry - 1;
for(;i>0;i>>=1) nbit++; for (; i > 0; i >>= 1)
nbit++;
nbit = 1<<nbit; nbit = 1 << nbit;
offset = (nbit-nentry)/2; offset = (nbit - nentry) / 2;
ginInsertEntry( accum, heapptr, entries[ (nbit>>1)-offset ]); ginInsertEntry(accum, heapptr, entries[(nbit >> 1) - offset]);
ginChooseElem(accum, heapptr, entries, nentry, 0, nbit, offset); ginChooseElem(accum, heapptr, entries, nentry, 0, nbit, offset);
} }
static int 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 ); int res = compareItemPointers((ItemPointer) a, (ItemPointer) b);
Assert(res != 0);
return res; return res;
} }
/* /*
* walk on binary tree and returns ordered nodes * walk on binary tree and returns ordered nodes
*/ */
static EntryAccumulator* static EntryAccumulator *
walkTree( BuildAccumulator *accum ) { walkTree(BuildAccumulator *accum)
EntryAccumulator *entry = accum->stack[ accum->stackpos ]; {
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 itself: we already was at left sublink */
return entry; 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 */ /* go on right sublink */
accum->stackpos++; accum->stackpos++;
entry = entry->right; entry = entry->right;
/* find most-left value */ /* find most-left value */
for(;;) { for (;;)
accum->stack[ accum->stackpos ] = entry; {
if ( entry->left ) { accum->stack[accum->stackpos] = entry;
if (entry->left)
{
accum->stackpos++; accum->stackpos++;
entry = entry->left; entry = entry->left;
} else }
else
break; break;
} }
} else { }
else
{
/* we already return all left subtree, itself and right subtree */ /* we already return all left subtree, itself and right subtree */
if ( accum->stackpos == 0 ) if (accum->stackpos == 0)
return 0; return 0;
accum->stackpos--; accum->stackpos--;
return walkTree(accum); return walkTree(accum);
@ -234,36 +264,43 @@ walkTree( BuildAccumulator *accum ) {
return entry; return entry;
} }
ItemPointerData* ItemPointerData *
ginGetEntry(BuildAccumulator *accum, Datum *value, uint32 *n) { ginGetEntry(BuildAccumulator *accum, Datum *value, uint32 *n)
{
EntryAccumulator *entry; EntryAccumulator *entry;
ItemPointerData *list; ItemPointerData *list;
if ( accum->stack == NULL ) { if (accum->stack == NULL)
{
/* first call */ /* first call */
accum->stack = palloc0(sizeof(EntryAccumulator*)*(accum->maxdepth+1)); accum->stack = palloc0(sizeof(EntryAccumulator *) * (accum->maxdepth + 1));
entry = accum->entries; entry = accum->entries;
if ( entry == NULL ) if (entry == NULL)
return NULL; return NULL;
/* find most-left value */ /* find most-left value */
for(;;) { for (;;)
accum->stack[ accum->stackpos ] = entry; {
if ( entry->left ) { accum->stack[accum->stackpos] = entry;
if (entry->left)
{
accum->stackpos++; accum->stackpos++;
entry = entry->left; entry = entry->left;
} else }
else
break; break;
} }
} else { }
pfree( accum->stack[ accum->stackpos ]->list ); else
accum->stack[ accum->stackpos ]->list = NULL; {
entry = walkTree( accum ); pfree(accum->stack[accum->stackpos]->list);
accum->stack[accum->stackpos]->list = NULL;
entry = walkTree(accum);
} }
if ( entry == NULL ) if (entry == NULL)
return NULL; return NULL;
*n = entry->number; *n = entry->number;
@ -272,9 +309,8 @@ ginGetEntry(BuildAccumulator *accum, Datum *value, uint32 *n) {
Assert(list != NULL); Assert(list != NULL);
if ( entry->shouldSort && entry->number > 1 ) if (entry->shouldSort && entry->number > 1)
qsort(list, *n, sizeof(ItemPointerData), qsortCompareItemPointers); qsort(list, *n, sizeof(ItemPointerData), qsortCompareItemPointers);
return list; return list;
} }

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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,35 +16,40 @@
#include "access/gin.h" #include "access/gin.h"
int int
compareItemPointers( ItemPointer a, ItemPointer b ) { compareItemPointers(ItemPointer a, ItemPointer b)
if ( GinItemPointerGetBlockNumber(a) == GinItemPointerGetBlockNumber(b) ) { {
if ( GinItemPointerGetOffsetNumber(a) == GinItemPointerGetOffsetNumber(b) ) if (GinItemPointerGetBlockNumber(a) == GinItemPointerGetBlockNumber(b))
{
if (GinItemPointerGetOffsetNumber(a) == GinItemPointerGetOffsetNumber(b))
return 0; return 0;
return ( GinItemPointerGetOffsetNumber(a) > GinItemPointerGetOffsetNumber(b) ) ? 1 : -1; return (GinItemPointerGetOffsetNumber(a) > GinItemPointerGetOffsetNumber(b)) ? 1 : -1;
} }
return ( GinItemPointerGetBlockNumber(a) > GinItemPointerGetBlockNumber(b) ) ? 1 : -1; return (GinItemPointerGetBlockNumber(a) > GinItemPointerGetBlockNumber(b)) ? 1 : -1;
} }
/* /*
* Merge two ordered array of itempointer * Merge two ordered array of itempointer
*/ */
void 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 *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 ) {
if (compareItemPointers(aptr, bptr) > 0)
*dptr++ = *bptr++; *dptr++ = *bptr++;
else else
*dptr++ = *aptr++; *dptr++ = *aptr++;
} }
while( aptr - a < na ) while (aptr - a < na)
*dptr++ = *aptr++; *dptr++ = *aptr++;
while( bptr - b < nb ) while (bptr - b < nb)
*dptr++ = *bptr++; *dptr++ = *bptr++;
} }
@ -53,13 +58,14 @@ MergeItemPointers(ItemPointerData *dst, ItemPointerData *a, uint32 na, ItemPoint
* Compares inserting itemp pointer with right bound of current page * Compares inserting itemp pointer with right bound of current page
*/ */
static bool static bool
dataIsMoveRight(GinBtree btree, Page page) { dataIsMoveRight(GinBtree btree, Page page)
{
ItemPointer iptr = GinDataPageGetRightBound(page); ItemPointer iptr = GinDataPageGetRightBound(page);
if ( GinPageRightMost(page) ) if (GinPageRightMost(page))
return FALSE; return FALSE;
return ( compareItemPointers( btree->items + btree->curitem, iptr ) > 0 ) ? TRUE : FALSE; return (compareItemPointers(btree->items + btree->curitem, iptr) > 0) ? TRUE : FALSE;
} }
/* /*
@ -67,16 +73,20 @@ dataIsMoveRight(GinBtree btree, Page page) {
* page correctly choosen and searching value SHOULD be on page * page correctly choosen and searching value SHOULD be on page
*/ */
static BlockNumber static BlockNumber
dataLocateItem(GinBtree btree, GinBtreeStack *stack) { dataLocateItem(GinBtree btree, GinBtreeStack *stack)
OffsetNumber low, high, maxoff; {
PostingItem *pitem=NULL; OffsetNumber low,
high,
maxoff;
PostingItem *pitem = NULL;
int result; int result;
Page page = BufferGetPage( stack->buffer ); Page page = BufferGetPage(stack->buffer);
Assert( !GinPageIsLeaf(page) ); Assert(!GinPageIsLeaf(page));
Assert( GinPageIsData(page) ); Assert(GinPageIsData(page));
if ( btree->fullScan ) { if (btree->fullScan)
{
stack->off = FirstOffsetNumber; stack->off = FirstOffsetNumber;
stack->predictNumber *= GinPageGetOpaque(page)->maxoff; stack->predictNumber *= GinPageGetOpaque(page)->maxoff;
return btree->getLeftMostPage(btree, page); return btree->getLeftMostPage(btree, page);
@ -84,36 +94,44 @@ dataLocateItem(GinBtree btree, GinBtreeStack *stack) {
low = FirstOffsetNumber; low = FirstOffsetNumber;
maxoff = high = GinPageGetOpaque(page)->maxoff; maxoff = high = GinPageGetOpaque(page)->maxoff;
Assert( high >= low ); Assert(high >= low);
high++; high++;
while (high > low) { while (high > low)
{
OffsetNumber mid = low + ((high - low) / 2); OffsetNumber mid = low + ((high - low) / 2);
pitem = (PostingItem*)GinDataPageGetItem(page,mid);
if ( mid == maxoff ) pitem = (PostingItem *) GinDataPageGetItem(page, mid);
/* Right infinity, page already correctly choosen
with a help of dataIsMoveRight */ if (mid == maxoff)
/*
* Right infinity, page already correctly choosen with a help of
* dataIsMoveRight
*/
result = -1; result = -1;
else { else
pitem = (PostingItem*)GinDataPageGetItem(page,mid); {
result = compareItemPointers( btree->items + btree->curitem, &( pitem->key ) ); pitem = (PostingItem *) GinDataPageGetItem(page, mid);
result = compareItemPointers(btree->items + btree->curitem, &(pitem->key));
} }
if ( result == 0 ) { if (result == 0)
{
stack->off = mid; stack->off = mid;
return PostingItemGetBlockNumber(pitem); return PostingItemGetBlockNumber(pitem);
} else if ( result > 0 ) }
else if (result > 0)
low = mid + 1; low = mid + 1;
else else
high = mid; high = mid;
} }
Assert( high>=FirstOffsetNumber && high <= maxoff ); Assert(high >= FirstOffsetNumber && high <= maxoff);
stack->off = high; stack->off = high;
pitem = (PostingItem*)GinDataPageGetItem(page,high); pitem = (PostingItem *) GinDataPageGetItem(page, high);
return PostingItemGetBlockNumber(pitem); return PostingItemGetBlockNumber(pitem);
} }
@ -123,38 +141,45 @@ dataLocateItem(GinBtree btree, GinBtreeStack *stack) {
* Returns true if value found on page. * Returns true if value found on page.
*/ */
static bool static bool
dataLocateLeafItem(GinBtree btree, GinBtreeStack *stack) { dataLocateLeafItem(GinBtree btree, GinBtreeStack *stack)
Page page = BufferGetPage( stack->buffer ); {
OffsetNumber low, high; Page page = BufferGetPage(stack->buffer);
OffsetNumber low,
high;
int result; int result;
Assert( GinPageIsLeaf(page) ); Assert(GinPageIsLeaf(page));
Assert( GinPageIsData(page) ); Assert(GinPageIsData(page));
if ( btree->fullScan ) { if (btree->fullScan)
{
stack->off = FirstOffsetNumber; stack->off = FirstOffsetNumber;
return TRUE; return TRUE;
} }
low=FirstOffsetNumber; low = FirstOffsetNumber;
high = GinPageGetOpaque(page)->maxoff; high = GinPageGetOpaque(page)->maxoff;
if ( high < low ) { if (high < low)
{
stack->off = FirstOffsetNumber; stack->off = FirstOffsetNumber;
return false; return false;
} }
high++; high++;
while (high > low) { while (high > low)
{
OffsetNumber mid = low + ((high - low) / 2); OffsetNumber mid = low + ((high - low) / 2);
result = compareItemPointers( btree->items + btree->curitem, (ItemPointer)GinDataPageGetItem(page,mid) ); result = compareItemPointers(btree->items + btree->curitem, (ItemPointer) GinDataPageGetItem(page, mid));
if ( result == 0 ) { if (result == 0)
{
stack->off = mid; stack->off = mid;
return true; return true;
} else if ( result > 0 ) }
else if (result > 0)
low = mid + 1; low = mid + 1;
else else
high = mid; high = mid;
@ -169,34 +194,41 @@ dataLocateLeafItem(GinBtree btree, GinBtreeStack *stack) {
* offset of PostingItem * offset of PostingItem
*/ */
static OffsetNumber static OffsetNumber
dataFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber storedOff) { dataFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber storedOff)
OffsetNumber i, maxoff = GinPageGetOpaque(page)->maxoff; {
OffsetNumber i,
maxoff = GinPageGetOpaque(page)->maxoff;
PostingItem *pitem; PostingItem *pitem;
Assert( !GinPageIsLeaf(page) ); Assert(!GinPageIsLeaf(page));
Assert( GinPageIsData(page) ); Assert(GinPageIsData(page));
/* if page isn't changed, we returns storedOff */ /* 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 ) pitem = (PostingItem *) GinDataPageGetItem(page, storedOff);
if (PostingItemGetBlockNumber(pitem) == blkno)
return storedOff; return storedOff;
/* we hope, that needed pointer goes to right. It's true /*
if there wasn't a deletion */ * we hope, that needed pointer goes to right. It's true if there
for( i=storedOff+1 ; i <= maxoff ; i++ ) { * wasn't a deletion
pitem = (PostingItem*)GinDataPageGetItem(page, i); */
if ( PostingItemGetBlockNumber(pitem) == blkno ) for (i = storedOff + 1; i <= maxoff; i++)
{
pitem = (PostingItem *) GinDataPageGetItem(page, i);
if (PostingItemGetBlockNumber(pitem) == blkno)
return i; return i;
} }
maxoff = storedOff-1; maxoff = storedOff - 1;
} }
/* last chance */ /* last chance */
for( i=FirstOffsetNumber; i <= maxoff ; i++ ) { for (i = FirstOffsetNumber; i <= maxoff; i++)
pitem = (PostingItem*)GinDataPageGetItem(page, i); {
if ( PostingItemGetBlockNumber(pitem) == blkno ) pitem = (PostingItem *) GinDataPageGetItem(page, i);
if (PostingItemGetBlockNumber(pitem) == blkno)
return i; return i;
} }
@ -207,14 +239,15 @@ dataFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber stor
* retunrs blkno of lefmost child * retunrs blkno of lefmost child
*/ */
static BlockNumber static BlockNumber
dataGetLeftMostPage(GinBtree btree, Page page) { dataGetLeftMostPage(GinBtree btree, Page page)
{
PostingItem *pitem; PostingItem *pitem;
Assert( !GinPageIsLeaf(page) ); Assert(!GinPageIsLeaf(page));
Assert( GinPageIsData(page) ); Assert(GinPageIsData(page));
Assert( GinPageGetOpaque(page)->maxoff >= FirstOffsetNumber ); Assert(GinPageGetOpaque(page)->maxoff >= FirstOffsetNumber);
pitem = (PostingItem*)GinDataPageGetItem(page, FirstOffsetNumber); pitem = (PostingItem *) GinDataPageGetItem(page, FirstOffsetNumber);
return PostingItemGetBlockNumber(pitem); return PostingItemGetBlockNumber(pitem);
} }
@ -223,18 +256,22 @@ dataGetLeftMostPage(GinBtree btree, Page page) {
* correct value! depending on leaf or non-leaf page * correct value! depending on leaf or non-leaf page
*/ */
void void
GinDataPageAddItem( Page page, void *data, OffsetNumber offset ) { GinDataPageAddItem(Page page, void *data, OffsetNumber offset)
{
OffsetNumber maxoff = GinPageGetOpaque(page)->maxoff; OffsetNumber maxoff = GinPageGetOpaque(page)->maxoff;
char *ptr; char *ptr;
if ( offset == InvalidOffsetNumber ) { if (offset == InvalidOffsetNumber)
ptr = GinDataPageGetItem(page,maxoff+1); {
} else { ptr = GinDataPageGetItem(page, maxoff + 1);
ptr = GinDataPageGetItem(page,offset);
if ( maxoff+1-offset != 0 )
memmove( ptr+GinSizeOfItem(page), ptr, (maxoff-offset+1) * GinSizeOfItem(page) );
} }
memcpy( ptr, data, GinSizeOfItem(page) ); else
{
ptr = GinDataPageGetItem(page, offset);
if (maxoff + 1 - offset != 0)
memmove(ptr + GinSizeOfItem(page), ptr, (maxoff - offset + 1) * GinSizeOfItem(page));
}
memcpy(ptr, data, GinSizeOfItem(page));
GinPageGetOpaque(page)->maxoff++; GinPageGetOpaque(page)->maxoff++;
} }
@ -243,15 +280,16 @@ GinDataPageAddItem( Page page, void *data, OffsetNumber offset ) {
* Deletes posting item from non-leaf page * Deletes posting item from non-leaf page
*/ */
void void
PageDeletePostingItem(Page page, OffsetNumber offset) { PageDeletePostingItem(Page page, OffsetNumber offset)
{
OffsetNumber maxoff = GinPageGetOpaque(page)->maxoff; OffsetNumber maxoff = GinPageGetOpaque(page)->maxoff;
Assert( !GinPageIsLeaf(page) ); Assert(!GinPageIsLeaf(page));
Assert( offset>=FirstOffsetNumber && offset <= maxoff ); Assert(offset >= FirstOffsetNumber && offset <= maxoff);
if ( offset != maxoff ) if (offset != maxoff)
memmove( GinDataPageGetItem(page,offset), GinDataPageGetItem(page,offset+1), memmove(GinDataPageGetItem(page, offset), GinDataPageGetItem(page, offset + 1),
sizeof(PostingItem) * (maxoff-offset) ); sizeof(PostingItem) * (maxoff - offset));
GinPageGetOpaque(page)->maxoff--; GinPageGetOpaque(page)->maxoff--;
} }
@ -261,19 +299,24 @@ PageDeletePostingItem(Page page, OffsetNumber offset) {
* item pointer never deletes! * item pointer never deletes!
*/ */
static bool static bool
dataIsEnoughSpace( GinBtree btree, Buffer buf, OffsetNumber off ) { dataIsEnoughSpace(GinBtree btree, Buffer buf, OffsetNumber off)
{
Page page = BufferGetPage(buf); Page page = BufferGetPage(buf);
Assert( GinPageIsData(page) ); Assert(GinPageIsData(page));
Assert( !btree->isDelete ); Assert(!btree->isDelete);
if ( GinPageIsLeaf(page) ) { if (GinPageIsLeaf(page))
if ( GinPageRightMost(page) && off > GinPageGetOpaque(page)->maxoff ) { {
if ( (btree->nitem - btree->curitem) * sizeof(ItemPointerData) <= GinDataPageGetFreeSpace(page) ) if (GinPageRightMost(page) && off > GinPageGetOpaque(page)->maxoff)
{
if ((btree->nitem - btree->curitem) * sizeof(ItemPointerData) <= GinDataPageGetFreeSpace(page))
return true; return true;
} else if ( sizeof(ItemPointerData) <= GinDataPageGetFreeSpace(page) ) }
else if (sizeof(ItemPointerData) <= GinDataPageGetFreeSpace(page))
return true; return true;
} else if ( sizeof(PostingItem) <= GinDataPageGetFreeSpace(page) ) }
else if (sizeof(PostingItem) <= GinDataPageGetFreeSpace(page))
return true; return true;
return false; return false;
@ -285,14 +328,17 @@ dataIsEnoughSpace( GinBtree btree, Buffer buf, OffsetNumber off ) {
* item pointer never deletes! * item pointer never deletes!
*/ */
static BlockNumber static BlockNumber
dataPrepareData( GinBtree btree, Page page, OffsetNumber off) { dataPrepareData(GinBtree btree, Page page, OffsetNumber off)
{
BlockNumber ret = InvalidBlockNumber; BlockNumber ret = InvalidBlockNumber;
Assert( GinPageIsData(page) ); 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 ); PostingItem *pitem = (PostingItem *) GinDataPageGetItem(page, off);
PostingItemSetBlockNumber(pitem, btree->rightblkno);
ret = btree->rightblkno; ret = btree->rightblkno;
} }
@ -306,19 +352,20 @@ dataPrepareData( GinBtree btree, Page page, OffsetNumber off) {
* build mode puts all ItemPointers to page. * build mode puts all ItemPointers to page.
*/ */
static void static void
dataPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prdata) { dataPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prdata)
{
Page page = BufferGetPage(buf); Page page = BufferGetPage(buf);
static XLogRecData rdata[3]; static XLogRecData rdata[3];
int sizeofitem = GinSizeOfItem(page); int sizeofitem = GinSizeOfItem(page);
static ginxlogInsert data; static ginxlogInsert data;
*prdata = rdata; *prdata = rdata;
Assert( GinPageIsData(page) ); Assert(GinPageIsData(page));
data.updateBlkno = dataPrepareData( btree, page, off ); data.updateBlkno = dataPrepareData(btree, page, off);
data.node = btree->index->rd_node; data.node = btree->index->rd_node;
data.blkno = BufferGetBlockNumber( buf ); data.blkno = BufferGetBlockNumber(buf);
data.offset = off; data.offset = off;
data.nitem = 1; data.nitem = 1;
data.isDelete = FALSE; data.isDelete = FALSE;
@ -337,27 +384,33 @@ dataPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prda
rdata[1].next = &rdata[2]; rdata[1].next = &rdata[2];
rdata[2].buffer = InvalidBuffer; rdata[2].buffer = InvalidBuffer;
rdata[2].data = (GinPageIsLeaf(page)) ? ((char*)(btree->items+btree->curitem)) : ((char*)&(btree->pitem)); rdata[2].data = (GinPageIsLeaf(page)) ? ((char *) (btree->items + btree->curitem)) : ((char *) &(btree->pitem));
rdata[2].len = sizeofitem; rdata[2].len = sizeofitem;
rdata[2].next = NULL; rdata[2].next = NULL;
if ( GinPageIsLeaf(page) ) { if (GinPageIsLeaf(page))
if ( GinPageRightMost(page) && off > GinPageGetOpaque(page)->maxoff ) { {
if (GinPageRightMost(page) && off > GinPageGetOpaque(page)->maxoff)
{
/* usually, create index... */ /* usually, create index... */
uint32 savedPos = btree->curitem; uint32 savedPos = btree->curitem;
while( btree->curitem < btree->nitem ) { while (btree->curitem < btree->nitem)
GinDataPageAddItem(page, btree->items+btree->curitem, off); {
GinDataPageAddItem(page, btree->items + btree->curitem, off);
off++; off++;
btree->curitem++; btree->curitem++;
} }
data.nitem = btree->curitem-savedPos; data.nitem = btree->curitem - savedPos;
rdata[2].len = sizeofitem * data.nitem; rdata[2].len = sizeofitem * data.nitem;
} else { }
GinDataPageAddItem(page, btree->items+btree->curitem, off); else
{
GinDataPageAddItem(page, btree->items + btree->curitem, off);
btree->curitem++; btree->curitem++;
} }
} else }
else
GinDataPageAddItem(page, &(btree->pitem), off); GinDataPageAddItem(page, &(btree->pitem), off);
} }
@ -368,77 +421,86 @@ dataPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prda
* left page * left page
*/ */
static 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 ginxlogSplit data;
static XLogRecData rdata[4]; static XLogRecData rdata[4];
static char vector[2*BLCKSZ]; static char vector[2 * BLCKSZ];
char *ptr; char *ptr;
OffsetNumber separator; OffsetNumber separator;
ItemPointer bound; ItemPointer bound;
Page lpage = GinPageGetCopyPage( BufferGetPage( lbuf ) ); Page lpage = GinPageGetCopyPage(BufferGetPage(lbuf));
ItemPointerData oldbound = *GinDataPageGetRightBound(lpage); ItemPointerData oldbound = *GinDataPageGetRightBound(lpage);
int sizeofitem = GinSizeOfItem(lpage); int sizeofitem = GinSizeOfItem(lpage);
OffsetNumber maxoff = GinPageGetOpaque(lpage)->maxoff; OffsetNumber maxoff = GinPageGetOpaque(lpage)->maxoff;
Page rpage = BufferGetPage( rbuf ); Page rpage = BufferGetPage(rbuf);
Size pageSize = PageGetPageSize( lpage ); Size pageSize = PageGetPageSize(lpage);
Size freeSpace; Size freeSpace;
uint32 nCopied = 1; uint32 nCopied = 1;
GinInitPage( rpage, GinPageGetOpaque(lpage)->flags, pageSize ); GinInitPage(rpage, GinPageGetOpaque(lpage)->flags, pageSize);
freeSpace = GinDataPageGetFreeSpace(rpage); freeSpace = GinDataPageGetFreeSpace(rpage);
*prdata = rdata; *prdata = rdata;
data.leftChildBlkno = ( GinPageIsLeaf(lpage) ) ? data.leftChildBlkno = (GinPageIsLeaf(lpage)) ?
InvalidOffsetNumber : PostingItemGetBlockNumber( &(btree->pitem) ); InvalidOffsetNumber : PostingItemGetBlockNumber(&(btree->pitem));
data.updateBlkno = dataPrepareData( btree, lpage, off ); data.updateBlkno = dataPrepareData(btree, lpage, off);
memcpy(vector, GinDataPageGetItem(lpage, FirstOffsetNumber), memcpy(vector, GinDataPageGetItem(lpage, FirstOffsetNumber),
maxoff*sizeofitem); maxoff * sizeofitem);
if ( GinPageIsLeaf(lpage) && GinPageRightMost(lpage) && off > GinPageGetOpaque(lpage)->maxoff ) { if (GinPageIsLeaf(lpage) && GinPageRightMost(lpage) && off > GinPageGetOpaque(lpage)->maxoff)
{
nCopied = 0; 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) ); memcpy(vector + maxoff * sizeof(ItemPointerData), btree->items + btree->curitem,
sizeof(ItemPointerData));
maxoff++; maxoff++;
nCopied++; nCopied++;
btree->curitem++; btree->curitem++;
} }
} else { }
ptr = vector + (off-1)*sizeofitem; else
if ( maxoff+1-off != 0 ) {
memmove( ptr+sizeofitem, ptr, (maxoff-off+1) * sizeofitem ); ptr = vector + (off - 1) * sizeofitem;
if ( GinPageIsLeaf(lpage) ) { if (maxoff + 1 - off != 0)
memcpy(ptr, btree->items+btree->curitem, sizeofitem ); memmove(ptr + sizeofitem, ptr, (maxoff - off + 1) * sizeofitem);
if (GinPageIsLeaf(lpage))
{
memcpy(ptr, btree->items + btree->curitem, sizeofitem);
btree->curitem++; btree->curitem++;
} else }
memcpy(ptr, &(btree->pitem), sizeofitem ); else
memcpy(ptr, &(btree->pitem), sizeofitem);
maxoff++; 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,
if ( btree->isBuild && GinPageRightMost(lpage) ) * so ItemPointers are monotonically increased..
separator=freeSpace/sizeofitem; */
if (btree->isBuild && GinPageRightMost(lpage))
separator = freeSpace / sizeofitem;
else else
separator=maxoff/2; separator = maxoff / 2;
GinInitPage( rpage, GinPageGetOpaque(lpage)->flags, pageSize ); GinInitPage(rpage, GinPageGetOpaque(lpage)->flags, pageSize);
GinInitPage( lpage, GinPageGetOpaque(rpage)->flags, pageSize ); GinInitPage(lpage, GinPageGetOpaque(rpage)->flags, pageSize);
memcpy( GinDataPageGetItem(lpage, FirstOffsetNumber), vector, separator * sizeofitem ); memcpy(GinDataPageGetItem(lpage, FirstOffsetNumber), vector, separator * sizeofitem);
GinPageGetOpaque(lpage)->maxoff = separator; GinPageGetOpaque(lpage)->maxoff = separator;
memcpy( GinDataPageGetItem(rpage, FirstOffsetNumber), memcpy(GinDataPageGetItem(rpage, FirstOffsetNumber),
vector + separator * sizeofitem, (maxoff-separator) * sizeofitem ); vector + separator * sizeofitem, (maxoff - separator) * sizeofitem);
GinPageGetOpaque(rpage)->maxoff = maxoff-separator; GinPageGetOpaque(rpage)->maxoff = maxoff - separator;
PostingItemSetBlockNumber( &(btree->pitem), BufferGetBlockNumber(lbuf) ); PostingItemSetBlockNumber(&(btree->pitem), BufferGetBlockNumber(lbuf));
if ( GinPageIsLeaf(lpage) ) if (GinPageIsLeaf(lpage))
btree->pitem.key = *(ItemPointerData*)GinDataPageGetItem(lpage, btree->pitem.key = *(ItemPointerData *) GinDataPageGetItem(lpage,
GinPageGetOpaque(lpage)->maxoff); GinPageGetOpaque(lpage)->maxoff);
else else
btree->pitem.key = ((PostingItem*)GinDataPageGetItem(lpage, btree->pitem.key = ((PostingItem *) GinDataPageGetItem(lpage,
GinPageGetOpaque(lpage)->maxoff))->key; GinPageGetOpaque(lpage)->maxoff))->key;
btree->rightblkno = BufferGetBlockNumber(rbuf); btree->rightblkno = BufferGetBlockNumber(rbuf);
@ -452,8 +514,8 @@ dataSplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogRe
data.node = btree->index->rd_node; data.node = btree->index->rd_node;
data.rootBlkno = InvalidBlockNumber; data.rootBlkno = InvalidBlockNumber;
data.lblkno = BufferGetBlockNumber( lbuf ); data.lblkno = BufferGetBlockNumber(lbuf);
data.rblkno = BufferGetBlockNumber( rbuf ); data.rblkno = BufferGetBlockNumber(rbuf);
data.separator = separator; data.separator = separator;
data.nitem = maxoff; data.nitem = maxoff;
data.isData = TRUE; data.isData = TRUE;
@ -468,7 +530,7 @@ dataSplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogRe
rdata[1].buffer = InvalidBuffer; rdata[1].buffer = InvalidBuffer;
rdata[1].data = vector; rdata[1].data = vector;
rdata[1].len = MAXALIGN( maxoff * sizeofitem ); rdata[1].len = MAXALIGN(maxoff * sizeofitem);
rdata[1].next = NULL; rdata[1].next = NULL;
return lpage; return lpage;
@ -479,23 +541,26 @@ dataSplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogRe
* Also called from ginxlog, should not use btree * Also called from ginxlog, should not use btree
*/ */
void void
dataFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf) { dataFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf)
{
Page page = BufferGetPage(root), Page page = BufferGetPage(root),
lpage = BufferGetPage(lbuf), lpage = BufferGetPage(lbuf),
rpage = BufferGetPage(rbuf); rpage = BufferGetPage(rbuf);
PostingItem li, ri; PostingItem li,
ri;
li.key = *GinDataPageGetRightBound(lpage); li.key = *GinDataPageGetRightBound(lpage);
PostingItemSetBlockNumber( &li, BufferGetBlockNumber(lbuf) ); PostingItemSetBlockNumber(&li, BufferGetBlockNumber(lbuf));
GinDataPageAddItem(page, &li, InvalidOffsetNumber ); GinDataPageAddItem(page, &li, InvalidOffsetNumber);
ri.key = *GinDataPageGetRightBound(rpage); ri.key = *GinDataPageGetRightBound(rpage);
PostingItemSetBlockNumber( &ri, BufferGetBlockNumber(rbuf) ); PostingItemSetBlockNumber(&ri, BufferGetBlockNumber(rbuf));
GinDataPageAddItem(page, &ri, InvalidOffsetNumber ); GinDataPageAddItem(page, &ri, InvalidOffsetNumber);
} }
void void
prepareDataScan( GinBtree btree, Relation index) { prepareDataScan(GinBtree btree, Relation index)
{
memset(btree, 0, sizeof(GinBtreeData)); memset(btree, 0, sizeof(GinBtreeData));
btree->index = index; btree->index = index;
btree->isMoveRight = dataIsMoveRight; btree->isMoveRight = dataIsMoveRight;
@ -511,19 +576,20 @@ prepareDataScan( GinBtree btree, Relation index) {
btree->searchMode = FALSE; btree->searchMode = FALSE;
btree->isDelete = FALSE; btree->isDelete = FALSE;
btree->fullScan = FALSE; btree->fullScan = FALSE;
btree->isBuild= FALSE; btree->isBuild = FALSE;
} }
GinPostingTreeScan* GinPostingTreeScan *
prepareScanPostingTree( Relation index, BlockNumber rootBlkno, bool searchMode) { prepareScanPostingTree(Relation index, BlockNumber rootBlkno, bool searchMode)
GinPostingTreeScan *gdi = (GinPostingTreeScan*)palloc0( sizeof(GinPostingTreeScan) ); {
GinPostingTreeScan *gdi = (GinPostingTreeScan *) palloc0(sizeof(GinPostingTreeScan));
prepareDataScan( &gdi->btree, index ); prepareDataScan(&gdi->btree, index);
gdi->btree.searchMode = searchMode; gdi->btree.searchMode = searchMode;
gdi->btree.fullScan = searchMode; gdi->btree.fullScan = searchMode;
gdi->stack = ginPrepareFindLeafPage( &gdi->btree, rootBlkno ); gdi->stack = ginPrepareFindLeafPage(&gdi->btree, rootBlkno);
return gdi; return gdi;
} }
@ -532,33 +598,35 @@ prepareScanPostingTree( Relation index, BlockNumber rootBlkno, bool searchMode)
* Inserts array of item pointers, may execute several tree scan (very rare) * Inserts array of item pointers, may execute several tree scan (very rare)
*/ */
void void
insertItemPointer(GinPostingTreeScan *gdi, ItemPointerData *items, uint32 nitem) { insertItemPointer(GinPostingTreeScan *gdi, ItemPointerData *items, uint32 nitem)
{
BlockNumber rootBlkno = gdi->stack->blkno; BlockNumber rootBlkno = gdi->stack->blkno;
gdi->btree.items = items; gdi->btree.items = items;
gdi->btree.nitem = nitem; gdi->btree.nitem = nitem;
gdi->btree.curitem = 0; gdi->btree.curitem = 0;
while( gdi->btree.curitem < gdi->btree.nitem ) { while (gdi->btree.curitem < gdi->btree.nitem)
{
if (!gdi->stack) if (!gdi->stack)
gdi->stack = ginPrepareFindLeafPage( &gdi->btree, rootBlkno ); gdi->stack = ginPrepareFindLeafPage(&gdi->btree, rootBlkno);
gdi->stack = ginFindLeafPage( &gdi->btree, gdi->stack ); gdi->stack = ginFindLeafPage(&gdi->btree, gdi->stack);
if ( gdi->btree.findItem( &(gdi->btree), gdi->stack ) ) if (gdi->btree.findItem(&(gdi->btree), gdi->stack))
elog(ERROR,"item pointer (%u,%d) already exists", elog(ERROR, "item pointer (%u,%d) already exists",
ItemPointerGetBlockNumber(gdi->btree.items + gdi->btree.curitem), ItemPointerGetBlockNumber(gdi->btree.items + gdi->btree.curitem),
ItemPointerGetOffsetNumber(gdi->btree.items + gdi->btree.curitem)); ItemPointerGetOffsetNumber(gdi->btree.items + gdi->btree.curitem));
ginInsertValue(&(gdi->btree), gdi->stack); ginInsertValue(&(gdi->btree), gdi->stack);
gdi->stack=NULL; gdi->stack = NULL;
} }
} }
Buffer Buffer
scanBeginPostingTree( GinPostingTreeScan *gdi ) { scanBeginPostingTree(GinPostingTreeScan *gdi)
gdi->stack = ginFindLeafPage( &gdi->btree, gdi->stack ); {
gdi->stack = ginFindLeafPage(&gdi->btree, gdi->stack);
return gdi->stack->buffer; return gdi->stack->buffer;
} }

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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,33 +37,37 @@
* - ItemPointerGetOffsetNumber(&itup->t_tid) contains magick number GIN_TREE_POSTING * - ItemPointerGetOffsetNumber(&itup->t_tid) contains magick number GIN_TREE_POSTING
*/ */
IndexTuple IndexTuple
GinFormTuple(GinState *ginstate, Datum key, ItemPointerData *ipd, uint32 nipd) { GinFormTuple(GinState *ginstate, Datum key, ItemPointerData *ipd, uint32 nipd)
bool isnull=FALSE; {
bool isnull = FALSE;
IndexTuple itup; IndexTuple itup;
itup = index_form_tuple(ginstate->tupdesc, &key, &isnull); itup = index_form_tuple(ginstate->tupdesc, &key, &isnull);
GinSetOrigSizePosting( itup, IndexTupleSize(itup) ); GinSetOrigSizePosting(itup, IndexTupleSize(itup));
if ( nipd > 0 ) { if (nipd > 0)
uint32 newsize = MAXALIGN(SHORTALIGN(IndexTupleSize(itup)) + sizeof(ItemPointerData)*nipd); {
uint32 newsize = MAXALIGN(SHORTALIGN(IndexTupleSize(itup)) + sizeof(ItemPointerData) * nipd);
if ( newsize >= INDEX_SIZE_MASK ) if (newsize >= INDEX_SIZE_MASK)
return NULL; return NULL;
if ( newsize > TOAST_INDEX_TARGET && nipd > 1 ) if (newsize > TOAST_INDEX_TARGET && nipd > 1)
return NULL; return NULL;
itup = repalloc( itup, newsize ); itup = repalloc(itup, newsize);
/* set new size */ /* set new size */
itup->t_info &= ~INDEX_SIZE_MASK; itup->t_info &= ~INDEX_SIZE_MASK;
itup->t_info |= newsize; itup->t_info |= newsize;
if ( ipd ) if (ipd)
memcpy( GinGetPosting(itup), ipd, sizeof(ItemPointerData)*nipd ); memcpy(GinGetPosting(itup), ipd, sizeof(ItemPointerData) * nipd);
GinSetNPosting(itup, nipd); GinSetNPosting(itup, nipd);
} else { }
else
{
GinSetNPosting(itup, 0); GinSetNPosting(itup, 0);
} }
return itup; 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. * so we don't use right bound, we use rightest key instead.
*/ */
static IndexTuple static IndexTuple
getRightMostTuple(Page page) { getRightMostTuple(Page page)
{
OffsetNumber maxoff = PageGetMaxOffsetNumber(page); OffsetNumber maxoff = PageGetMaxOffsetNumber(page);
return (IndexTuple) PageGetItem(page, PageGetItemId(page, maxoff)); return (IndexTuple) PageGetItem(page, PageGetItemId(page, maxoff));
} }
Datum Datum
ginGetHighKey(GinState *ginstate, Page page) { ginGetHighKey(GinState *ginstate, Page page)
{
IndexTuple itup; IndexTuple itup;
bool isnull; bool isnull;
@ -90,15 +97,16 @@ ginGetHighKey(GinState *ginstate, Page page) {
} }
static bool static bool
entryIsMoveRight(GinBtree btree, Page page) { entryIsMoveRight(GinBtree btree, Page page)
{
Datum highkey; Datum highkey;
if ( GinPageRightMost(page) ) if (GinPageRightMost(page))
return FALSE; return FALSE;
highkey = ginGetHighKey(btree->ginstate, page); highkey = ginGetHighKey(btree->ginstate, page);
if ( compareEntries(btree->ginstate, btree->entryValue, highkey) > 0 ) if (compareEntries(btree->ginstate, btree->entryValue, highkey) > 0)
return TRUE; return TRUE;
return FALSE; return FALSE;
@ -109,16 +117,20 @@ entryIsMoveRight(GinBtree btree, Page page) {
* page correctly choosen and searching value SHOULD be on page * page correctly choosen and searching value SHOULD be on page
*/ */
static BlockNumber static BlockNumber
entryLocateEntry(GinBtree btree, GinBtreeStack *stack) { entryLocateEntry(GinBtree btree, GinBtreeStack *stack)
OffsetNumber low, high, maxoff; {
OffsetNumber low,
high,
maxoff;
IndexTuple itup = NULL; IndexTuple itup = NULL;
int result; int result;
Page page = BufferGetPage( stack->buffer ); Page page = BufferGetPage(stack->buffer);
Assert( !GinPageIsLeaf(page) ); Assert(!GinPageIsLeaf(page));
Assert( !GinPageIsData(page) ); Assert(!GinPageIsData(page));
if ( btree->fullScan ) { if (btree->fullScan)
{
stack->off = FirstOffsetNumber; stack->off = FirstOffsetNumber;
stack->predictNumber *= PageGetMaxOffsetNumber(page); stack->predictNumber *= PageGetMaxOffsetNumber(page);
return btree->getLeftMostPage(btree, page); return btree->getLeftMostPage(btree, page);
@ -126,39 +138,43 @@ entryLocateEntry(GinBtree btree, GinBtreeStack *stack) {
low = FirstOffsetNumber; low = FirstOffsetNumber;
maxoff = high = PageGetMaxOffsetNumber(page); maxoff = high = PageGetMaxOffsetNumber(page);
Assert( high >= low ); Assert(high >= low);
high++; high++;
while (high > low) { while (high > low)
{
OffsetNumber mid = low + ((high - low) / 2); OffsetNumber mid = low + ((high - low) / 2);
if ( mid == maxoff && GinPageRightMost(page) ) if (mid == maxoff && GinPageRightMost(page))
/* Right infinity */ /* Right infinity */
result = -1; result = -1;
else { else
{
bool isnull; bool isnull;
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, mid)); itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, mid));
result = compareEntries(btree->ginstate, btree->entryValue, result = compareEntries(btree->ginstate, btree->entryValue,
index_getattr(itup, FirstOffsetNumber, btree->ginstate->tupdesc, &isnull) ); index_getattr(itup, FirstOffsetNumber, btree->ginstate->tupdesc, &isnull));
} }
if ( result == 0 ) { if (result == 0)
{
stack->off = mid; stack->off = mid;
Assert( GinItemPointerGetBlockNumber(&(itup)->t_tid) != GIN_ROOT_BLKNO ); Assert(GinItemPointerGetBlockNumber(&(itup)->t_tid) != GIN_ROOT_BLKNO);
return GinItemPointerGetBlockNumber(&(itup)->t_tid); return GinItemPointerGetBlockNumber(&(itup)->t_tid);
} else if ( result > 0 ) }
else if (result > 0)
low = mid + 1; low = mid + 1;
else else
high = mid; high = mid;
} }
Assert( high>=FirstOffsetNumber && high <= maxoff ); Assert(high >= FirstOffsetNumber && high <= maxoff);
stack->off = high; stack->off = high;
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, high)); itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, high));
Assert( GinItemPointerGetBlockNumber(&(itup)->t_tid) != GIN_ROOT_BLKNO ); Assert(GinItemPointerGetBlockNumber(&(itup)->t_tid) != GIN_ROOT_BLKNO);
return GinItemPointerGetBlockNumber(&(itup)->t_tid); return GinItemPointerGetBlockNumber(&(itup)->t_tid);
} }
@ -168,15 +184,18 @@ entryLocateEntry(GinBtree btree, GinBtreeStack *stack) {
* Returns true if value found on page. * Returns true if value found on page.
*/ */
static bool static bool
entryLocateLeafEntry(GinBtree btree, GinBtreeStack *stack) { entryLocateLeafEntry(GinBtree btree, GinBtreeStack *stack)
Page page = BufferGetPage( stack->buffer ); {
OffsetNumber low, high; Page page = BufferGetPage(stack->buffer);
OffsetNumber low,
high;
IndexTuple itup; IndexTuple itup;
Assert( GinPageIsLeaf(page) ); Assert(GinPageIsLeaf(page));
Assert( !GinPageIsData(page) ); Assert(!GinPageIsData(page));
if ( btree->fullScan ) { if (btree->fullScan)
{
stack->off = FirstOffsetNumber; stack->off = FirstOffsetNumber;
return TRUE; return TRUE;
} }
@ -184,26 +203,30 @@ entryLocateLeafEntry(GinBtree btree, GinBtreeStack *stack) {
low = FirstOffsetNumber; low = FirstOffsetNumber;
high = PageGetMaxOffsetNumber(page); high = PageGetMaxOffsetNumber(page);
if ( high < low ) { if (high < low)
{
stack->off = FirstOffsetNumber; stack->off = FirstOffsetNumber;
return false; return false;
} }
high++; high++;
while (high > low) { while (high > low)
{
OffsetNumber mid = low + ((high - low) / 2); OffsetNumber mid = low + ((high - low) / 2);
bool isnull; bool isnull;
int result; int result;
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, mid)); itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, mid));
result = compareEntries(btree->ginstate, btree->entryValue, result = compareEntries(btree->ginstate, btree->entryValue,
index_getattr(itup, FirstOffsetNumber, btree->ginstate->tupdesc, &isnull) ); index_getattr(itup, FirstOffsetNumber, btree->ginstate->tupdesc, &isnull));
if ( result == 0 ) { if (result == 0)
{
stack->off = mid; stack->off = mid;
return true; return true;
} else if ( result > 0 ) }
else if (result > 0)
low = mid + 1; low = mid + 1;
else else
high = mid; high = mid;
@ -214,33 +237,40 @@ entryLocateLeafEntry(GinBtree btree, GinBtreeStack *stack) {
} }
static OffsetNumber static OffsetNumber
entryFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber storedOff) { entryFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber storedOff)
OffsetNumber i, maxoff = PageGetMaxOffsetNumber(page); {
OffsetNumber i,
maxoff = PageGetMaxOffsetNumber(page);
IndexTuple itup; IndexTuple itup;
Assert( !GinPageIsLeaf(page) ); Assert(!GinPageIsLeaf(page));
Assert( !GinPageIsData(page) ); Assert(!GinPageIsData(page));
/* if page isn't changed, we returns storedOff */ /* 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)); itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, storedOff));
if ( GinItemPointerGetBlockNumber(&(itup)->t_tid) == blkno ) if (GinItemPointerGetBlockNumber(&(itup)->t_tid) == blkno)
return storedOff; return storedOff;
/* we hope, that needed pointer goes to right. It's true /*
if there wasn't a deletion */ * we hope, that needed pointer goes to right. It's true if there
for( i=storedOff+1 ; i <= maxoff ; i++ ) { * wasn't a deletion
*/
for (i = storedOff + 1; i <= maxoff; i++)
{
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, i)); itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
if ( GinItemPointerGetBlockNumber(&(itup)->t_tid) == blkno ) if (GinItemPointerGetBlockNumber(&(itup)->t_tid) == blkno)
return i; return i;
} }
maxoff = storedOff-1; maxoff = storedOff - 1;
} }
/* last chance */ /* last chance */
for( i=FirstOffsetNumber; i <= maxoff ; i++ ) { for (i = FirstOffsetNumber; i <= maxoff; i++)
{
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, i)); itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
if ( GinItemPointerGetBlockNumber(&(itup)->t_tid) == blkno ) if (GinItemPointerGetBlockNumber(&(itup)->t_tid) == blkno)
return i; return i;
} }
@ -248,31 +278,35 @@ entryFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber sto
} }
static BlockNumber static BlockNumber
entryGetLeftMostPage(GinBtree btree, Page page) { entryGetLeftMostPage(GinBtree btree, Page page)
{
IndexTuple itup; IndexTuple itup;
Assert( !GinPageIsLeaf(page) ); Assert(!GinPageIsLeaf(page));
Assert( !GinPageIsData(page) ); Assert(!GinPageIsData(page));
Assert( PageGetMaxOffsetNumber(page) >= FirstOffsetNumber ); Assert(PageGetMaxOffsetNumber(page) >= FirstOffsetNumber);
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, FirstOffsetNumber)); itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, FirstOffsetNumber));
return GinItemPointerGetBlockNumber(&(itup)->t_tid); return GinItemPointerGetBlockNumber(&(itup)->t_tid);
} }
static bool static bool
entryIsEnoughSpace( GinBtree btree, Buffer buf, OffsetNumber off ) { entryIsEnoughSpace(GinBtree btree, Buffer buf, OffsetNumber off)
{
Size itupsz = 0; Size itupsz = 0;
Page page = BufferGetPage(buf); Page page = BufferGetPage(buf);
Assert( btree->entry ); Assert(btree->entry);
Assert( !GinPageIsData(page) ); Assert(!GinPageIsData(page));
if ( btree->isDelete ) { if (btree->isDelete)
IndexTuple itup = (IndexTuple)PageGetItem(page, PageGetItemId(page, off)); {
itupsz = MAXALIGN( IndexTupleSize( itup ) ) + sizeof(ItemIdData); IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, off));
itupsz = MAXALIGN(IndexTupleSize(itup)) + sizeof(ItemIdData);
} }
if ( PageGetFreeSpace(page) + itupsz >= MAXALIGN(IndexTupleSize(btree->entry)) + sizeof(ItemIdData) ) if (PageGetFreeSpace(page) + itupsz >= MAXALIGN(IndexTupleSize(btree->entry)) + sizeof(ItemIdData))
return true; return true;
return false; return false;
@ -284,19 +318,23 @@ entryIsEnoughSpace( GinBtree btree, Buffer buf, OffsetNumber off ) {
* if child split is occured * if child split is occured
*/ */
static BlockNumber static BlockNumber
entryPreparePage( GinBtree btree, Page page, OffsetNumber off) { entryPreparePage(GinBtree btree, Page page, OffsetNumber off)
{
BlockNumber ret = InvalidBlockNumber; BlockNumber ret = InvalidBlockNumber;
Assert( btree->entry ); Assert(btree->entry);
Assert( !GinPageIsData(page) ); Assert(!GinPageIsData(page));
if ( btree->isDelete ) { if (btree->isDelete)
Assert( GinPageIsLeaf(page) ); {
Assert(GinPageIsLeaf(page));
PageIndexTupleDelete(page, off); PageIndexTupleDelete(page, off);
} }
if ( !GinPageIsLeaf(page) && btree->rightblkno != InvalidBlockNumber ) { if (!GinPageIsLeaf(page) && btree->rightblkno != InvalidBlockNumber)
IndexTuple itup = (IndexTuple)PageGetItem(page, PageGetItemId(page, off)); {
IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, off));
ItemPointerSet(&itup->t_tid, btree->rightblkno, InvalidOffsetNumber); ItemPointerSet(&itup->t_tid, btree->rightblkno, InvalidOffsetNumber);
ret = btree->rightblkno; ret = btree->rightblkno;
} }
@ -310,22 +348,23 @@ entryPreparePage( GinBtree btree, Page page, OffsetNumber off) {
* Place tuple on page and fills WAL record * Place tuple on page and fills WAL record
*/ */
static void static void
entryPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prdata) { entryPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prdata)
{
Page page = BufferGetPage(buf); Page page = BufferGetPage(buf);
static XLogRecData rdata[3]; static XLogRecData rdata[3];
OffsetNumber placed; OffsetNumber placed;
static ginxlogInsert data; static ginxlogInsert data;
*prdata = rdata; *prdata = rdata;
data.updateBlkno = entryPreparePage( btree, page, off ); data.updateBlkno = entryPreparePage(btree, page, off);
placed = PageAddItem( page, (Item)btree->entry, IndexTupleSize(btree->entry), off, LP_USED); placed = PageAddItem(page, (Item) btree->entry, IndexTupleSize(btree->entry), off, LP_USED);
if ( placed != off ) if (placed != off)
elog(ERROR, "failed to add item to index page in \"%s\"", elog(ERROR, "failed to add item to index page in \"%s\"",
RelationGetRelationName(btree->index)); RelationGetRelationName(btree->index));
data.node = btree->index->rd_node; data.node = btree->index->rd_node;
data.blkno = BufferGetBlockNumber( buf ); data.blkno = BufferGetBlockNumber(buf);
data.offset = off; data.offset = off;
data.nitem = 1; data.nitem = 1;
data.isDelete = btree->isDelete; data.isDelete = btree->isDelete;
@ -358,87 +397,99 @@ entryPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prd
* an equal number! * an equal number!
*/ */
static Page 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]; static XLogRecData rdata[2];
OffsetNumber i, maxoff, separator=InvalidOffsetNumber; OffsetNumber i,
Size totalsize=0; maxoff,
Size lsize = 0, size; separator = InvalidOffsetNumber;
static char tupstore[ 2*BLCKSZ ]; Size totalsize = 0;
Size lsize = 0,
size;
static char tupstore[2 * BLCKSZ];
char *ptr; char *ptr;
IndexTuple itup, leftrightmost=NULL; IndexTuple itup,
leftrightmost = NULL;
static ginxlogSplit data; static ginxlogSplit data;
Datum value; Datum value;
bool isnull; bool isnull;
Page page; Page page;
Page lpage = GinPageGetCopyPage( BufferGetPage( lbuf ) ); Page lpage = GinPageGetCopyPage(BufferGetPage(lbuf));
Page rpage = BufferGetPage( rbuf ); Page rpage = BufferGetPage(rbuf);
Size pageSize = PageGetPageSize( lpage ); Size pageSize = PageGetPageSize(lpage);
*prdata = rdata; *prdata = rdata;
data.leftChildBlkno = ( GinPageIsLeaf(lpage) ) ? data.leftChildBlkno = (GinPageIsLeaf(lpage)) ?
InvalidOffsetNumber : GinItemPointerGetBlockNumber( &(btree->entry->t_tid) ); InvalidOffsetNumber : GinItemPointerGetBlockNumber(&(btree->entry->t_tid));
data.updateBlkno = entryPreparePage( btree, lpage, off ); data.updateBlkno = entryPreparePage(btree, lpage, off);
maxoff = PageGetMaxOffsetNumber(lpage); maxoff = PageGetMaxOffsetNumber(lpage);
ptr = tupstore; ptr = tupstore;
for(i=FirstOffsetNumber; i<=maxoff; i++) { for (i = FirstOffsetNumber; i <= maxoff; i++)
if ( i==off ) { {
size = MAXALIGN( IndexTupleSize(btree->entry) ); if (i == off)
{
size = MAXALIGN(IndexTupleSize(btree->entry));
memcpy(ptr, btree->entry, size); memcpy(ptr, btree->entry, size);
ptr+=size; ptr += size;
totalsize += size + sizeof(ItemIdData); totalsize += size + sizeof(ItemIdData);
} }
itup = (IndexTuple)PageGetItem(lpage, PageGetItemId(lpage, i)); itup = (IndexTuple) PageGetItem(lpage, PageGetItemId(lpage, i));
size = MAXALIGN( IndexTupleSize(itup) ); size = MAXALIGN(IndexTupleSize(itup));
memcpy(ptr, itup, size); memcpy(ptr, itup, size);
ptr+=size; ptr += size;
totalsize += size + sizeof(ItemIdData); totalsize += size + sizeof(ItemIdData);
} }
if ( off==maxoff+1 ) { if (off == maxoff + 1)
size = MAXALIGN( IndexTupleSize(btree->entry) ); {
size = MAXALIGN(IndexTupleSize(btree->entry));
memcpy(ptr, btree->entry, size); memcpy(ptr, btree->entry, size);
ptr+=size; ptr += size;
totalsize += size + sizeof(ItemIdData); totalsize += size + sizeof(ItemIdData);
} }
GinInitPage( rpage, GinPageGetOpaque(lpage)->flags, pageSize ); GinInitPage(rpage, GinPageGetOpaque(lpage)->flags, pageSize);
GinInitPage( lpage, GinPageGetOpaque(rpage)->flags, pageSize ); GinInitPage(lpage, GinPageGetOpaque(rpage)->flags, pageSize);
ptr = tupstore; ptr = tupstore;
maxoff++; maxoff++;
lsize = 0; lsize = 0;
page = lpage; page = lpage;
for(i=FirstOffsetNumber; i<=maxoff; i++) { for (i = FirstOffsetNumber; i <= maxoff; i++)
itup = (IndexTuple)ptr; {
itup = (IndexTuple) ptr;
if ( lsize > totalsize/2 ) { if (lsize > totalsize / 2)
if ( separator==InvalidOffsetNumber ) {
separator = i-1; if (separator == InvalidOffsetNumber)
separator = i - 1;
page = rpage; page = rpage;
} else { }
else
{
leftrightmost = itup; leftrightmost = itup;
lsize += MAXALIGN( IndexTupleSize(itup) ) + sizeof(ItemIdData); lsize += MAXALIGN(IndexTupleSize(itup)) + sizeof(ItemIdData);
} }
if ( PageAddItem( page, (Item)itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber ) if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber)
elog(ERROR, "failed to add item to index page in \"%s\"", elog(ERROR, "failed to add item to index page in \"%s\"",
RelationGetRelationName(btree->index)); RelationGetRelationName(btree->index));
ptr += MAXALIGN( IndexTupleSize(itup) ); ptr += MAXALIGN(IndexTupleSize(itup));
} }
value = index_getattr(leftrightmost, FirstOffsetNumber, btree->ginstate->tupdesc, &isnull); value = index_getattr(leftrightmost, FirstOffsetNumber, btree->ginstate->tupdesc, &isnull);
btree->entry = GinFormTuple( btree->ginstate, value, NULL, 0); btree->entry = GinFormTuple(btree->ginstate, value, NULL, 0);
ItemPointerSet(&(btree->entry)->t_tid, BufferGetBlockNumber( lbuf ), InvalidOffsetNumber); ItemPointerSet(&(btree->entry)->t_tid, BufferGetBlockNumber(lbuf), InvalidOffsetNumber);
btree->rightblkno = BufferGetBlockNumber( rbuf ); btree->rightblkno = BufferGetBlockNumber(rbuf);
data.node = btree->index->rd_node; data.node = btree->index->rd_node;
data.rootBlkno = InvalidBlockNumber; data.rootBlkno = InvalidBlockNumber;
data.lblkno = BufferGetBlockNumber( lbuf ); data.lblkno = BufferGetBlockNumber(lbuf);
data.rblkno = BufferGetBlockNumber( rbuf ); data.rblkno = BufferGetBlockNumber(rbuf);
data.separator = separator; data.separator = separator;
data.nitem = maxoff; data.nitem = maxoff;
data.isData = FALSE; data.isData = FALSE;
@ -462,19 +513,24 @@ entrySplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogR
* return newly allocate rightmost tuple * return newly allocate rightmost tuple
*/ */
IndexTuple IndexTuple
ginPageGetLinkItup(Buffer buf) { ginPageGetLinkItup(Buffer buf)
IndexTuple itup, nitup; {
IndexTuple itup,
nitup;
Page page = BufferGetPage(buf); Page page = BufferGetPage(buf);
itup = getRightMostTuple( page ); 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 = (IndexTuple) palloc(MAXALIGN(GinGetOrigSizePosting(itup)));
memcpy(nitup, itup, GinGetOrigSizePosting(itup));
nitup->t_info &= ~INDEX_SIZE_MASK; nitup->t_info &= ~INDEX_SIZE_MASK;
nitup->t_info |= GinGetOrigSizePosting(itup); nitup->t_info |= GinGetOrigSizePosting(itup);
} else { }
nitup = (IndexTuple)palloc( MAXALIGN(IndexTupleSize(itup)) ); else
memcpy( nitup, itup, IndexTupleSize(itup) ); {
nitup = (IndexTuple) palloc(MAXALIGN(IndexTupleSize(itup)));
memcpy(nitup, itup, IndexTupleSize(itup));
} }
ItemPointerSet(&nitup->t_tid, BufferGetBlockNumber(buf), InvalidOffsetNumber); ItemPointerSet(&nitup->t_tid, BufferGetBlockNumber(buf), InvalidOffsetNumber);
@ -486,23 +542,25 @@ ginPageGetLinkItup(Buffer buf) {
* Also called from ginxlog, should not use btree * Also called from ginxlog, should not use btree
*/ */
void void
entryFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf) { entryFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf)
{
Page page; Page page;
IndexTuple itup; IndexTuple itup;
page = BufferGetPage(root); page = BufferGetPage(root);
itup = ginPageGetLinkItup( lbuf ); itup = ginPageGetLinkItup(lbuf);
if ( PageAddItem( page, (Item)itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber ) if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber)
elog(ERROR, "failed to add item to index root page"); elog(ERROR, "failed to add item to index root page");
itup = ginPageGetLinkItup( rbuf ); itup = ginPageGetLinkItup(rbuf);
if ( PageAddItem( page, (Item)itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber ) if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber)
elog(ERROR, "failed to add item to index root page"); elog(ERROR, "failed to add item to index root page");
} }
void void
prepareEntryScan( GinBtree btree, Relation index, Datum value, GinState *ginstate) { prepareEntryScan(GinBtree btree, Relation index, Datum value, GinState *ginstate)
{
memset(btree, 0, sizeof(GinBtreeData)); memset(btree, 0, sizeof(GinBtreeData));
btree->isMoveRight = entryIsMoveRight; btree->isMoveRight = entryIsMoveRight;
@ -524,4 +582,3 @@ prepareEntryScan( GinBtree btree, Relation index, Datum value, GinState *ginstat
btree->fullScan = FALSE; btree->fullScan = FALSE;
btree->isBuild = FALSE; btree->isBuild = FALSE;
} }

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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,15 +18,17 @@
#include "utils/memutils.h" #include "utils/memutils.h"
static OffsetNumber static OffsetNumber
findItemInPage( Page page, ItemPointer item, OffsetNumber off ) { findItemInPage(Page page, ItemPointer item, OffsetNumber off)
{
OffsetNumber maxoff = GinPageGetOpaque(page)->maxoff; OffsetNumber maxoff = GinPageGetOpaque(page)->maxoff;
int res; int res;
for(; off<=maxoff; off++) { for (; off <= maxoff; off++)
res = compareItemPointers( item, (ItemPointer)GinDataPageGetItem(page, off) ); {
Assert( res>= 0 ); res = compareItemPointers(item, (ItemPointer) GinDataPageGetItem(page, off));
Assert(res >= 0);
if ( res == 0 ) if (res == 0)
return off; return off;
} }
@ -38,24 +40,29 @@ findItemInPage( Page page, ItemPointer item, OffsetNumber off ) {
* Stop* functions unlock buffer (but don't release!) * Stop* functions unlock buffer (but don't release!)
*/ */
static void static void
startScanEntry( Relation index, GinState *ginstate, GinScanEntry entry, bool firstCall ) { startScanEntry(Relation index, GinState *ginstate, GinScanEntry entry, bool firstCall)
if ( entry->master != NULL ) { {
if (entry->master != NULL)
{
entry->isFinished = entry->master->isFinished; entry->isFinished = entry->master->isFinished;
return; return;
} }
if ( firstCall ) { if (firstCall)
/* at first call we should find entry, and {
begin scan of posting tree or just store posting list in memory */ /*
* at first call we should find entry, and begin scan of posting tree
* or just store posting list in memory
*/
GinBtreeData btreeEntry; GinBtreeData btreeEntry;
GinBtreeStack *stackEntry; GinBtreeStack *stackEntry;
Page page; Page page;
bool needUnlock = TRUE; bool needUnlock = TRUE;
prepareEntryScan( &btreeEntry, index, entry->entry, ginstate ); prepareEntryScan(&btreeEntry, index, entry->entry, ginstate);
btreeEntry.searchMode = TRUE; btreeEntry.searchMode = TRUE;
stackEntry = ginFindLeafPage(&btreeEntry, NULL); stackEntry = ginFindLeafPage(&btreeEntry, NULL);
page = BufferGetPage( stackEntry->buffer ); page = BufferGetPage(stackEntry->buffer);
entry->isFinished = TRUE; entry->isFinished = TRUE;
entry->buffer = InvalidBuffer; entry->buffer = InvalidBuffer;
@ -65,103 +72,115 @@ startScanEntry( Relation index, GinState *ginstate, GinScanEntry entry, bool fir
entry->reduceResult = FALSE; entry->reduceResult = FALSE;
entry->predictNumberResult = 0; entry->predictNumberResult = 0;
if ( btreeEntry.findItem( &btreeEntry, stackEntry ) ) { if (btreeEntry.findItem(&btreeEntry, stackEntry))
{
IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, stackEntry->off)); IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, stackEntry->off));
if ( GinIsPostingTree(itup) ) { if (GinIsPostingTree(itup))
{
BlockNumber rootPostingTree = GinGetPostingTree(itup); BlockNumber rootPostingTree = GinGetPostingTree(itup);
GinPostingTreeScan *gdi; GinPostingTreeScan *gdi;
Page page; Page page;
LockBuffer(stackEntry->buffer, GIN_UNLOCK); LockBuffer(stackEntry->buffer, GIN_UNLOCK);
needUnlock = FALSE; needUnlock = FALSE;
gdi = prepareScanPostingTree( index, rootPostingTree, TRUE ); gdi = prepareScanPostingTree(index, rootPostingTree, TRUE);
entry->buffer = scanBeginPostingTree( gdi ); entry->buffer = scanBeginPostingTree(gdi);
IncrBufferRefCount( entry->buffer ); IncrBufferRefCount(entry->buffer);
page = BufferGetPage( entry->buffer ); page = BufferGetPage(entry->buffer);
entry->predictNumberResult = gdi->stack->predictNumber * GinPageGetOpaque(page)->maxoff; entry->predictNumberResult = gdi->stack->predictNumber * GinPageGetOpaque(page)->maxoff;
freeGinBtreeStack( gdi->stack ); freeGinBtreeStack(gdi->stack);
pfree( gdi ); pfree(gdi);
entry->isFinished = FALSE; entry->isFinished = FALSE;
} else if ( GinGetNPosting(itup) > 0 ) { }
else if (GinGetNPosting(itup) > 0)
{
entry->nlist = GinGetNPosting(itup); entry->nlist = GinGetNPosting(itup);
entry->list = (ItemPointerData*)palloc( sizeof(ItemPointerData) * entry->nlist ); entry->list = (ItemPointerData *) palloc(sizeof(ItemPointerData) * entry->nlist);
memcpy( entry->list, GinGetPosting(itup), sizeof(ItemPointerData) * entry->nlist ); memcpy(entry->list, GinGetPosting(itup), sizeof(ItemPointerData) * entry->nlist);
entry->isFinished = FALSE; entry->isFinished = FALSE;
} }
} }
if ( needUnlock ) if (needUnlock)
LockBuffer(stackEntry->buffer, GIN_UNLOCK); LockBuffer(stackEntry->buffer, GIN_UNLOCK);
freeGinBtreeStack( stackEntry ); freeGinBtreeStack(stackEntry);
} else if ( entry->buffer != InvalidBuffer ) { }
else if (entry->buffer != InvalidBuffer)
{
/* we should find place were we was stopped */ /* we should find place were we was stopped */
BlockNumber blkno; BlockNumber blkno;
Page page; Page page;
LockBuffer( entry->buffer, GIN_SHARE ); LockBuffer(entry->buffer, GIN_SHARE);
if ( !ItemPointerIsValid( &entry->curItem ) ) if (!ItemPointerIsValid(&entry->curItem))
/* start position */ /* start position */
return; return;
Assert( entry->offset!=InvalidOffsetNumber ); Assert(entry->offset != InvalidOffsetNumber);
page = BufferGetPage( entry->buffer ); page = BufferGetPage(entry->buffer);
/* try to find curItem in current buffer */ /* try to find curItem in current buffer */
if ( (entry->offset=findItemInPage(page , &entry->curItem, entry->offset))!=InvalidOffsetNumber ) if ((entry->offset = findItemInPage(page, &entry->curItem, entry->offset)) != InvalidOffsetNumber)
return; return;
/* walk to right */ /* 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_UNLOCK);
LockBuffer( entry->buffer, GIN_SHARE ); entry->buffer = ReleaseAndReadBuffer(entry->buffer, index, blkno);
page = BufferGetPage( entry->buffer ); LockBuffer(entry->buffer, GIN_SHARE);
page = BufferGetPage(entry->buffer);
if ( (entry->offset=findItemInPage(page , &entry->curItem, FirstOffsetNumber))!=InvalidOffsetNumber ) if ((entry->offset = findItemInPage(page, &entry->curItem, FirstOffsetNumber)) != InvalidOffsetNumber)
return; return;
} }
elog(ERROR,"Logic error: lost previously founded ItemId"); elog(ERROR, "Logic error: lost previously founded ItemId");
} }
} }
static void static void
stopScanEntry( GinScanEntry entry ) { stopScanEntry(GinScanEntry entry)
if ( entry->buffer != InvalidBuffer ) {
LockBuffer( entry->buffer, GIN_UNLOCK ); if (entry->buffer != InvalidBuffer)
LockBuffer(entry->buffer, GIN_UNLOCK);
} }
static void static void
startScanKey( Relation index, GinState *ginstate, GinScanKey key ) { startScanKey(Relation index, GinState *ginstate, GinScanKey key)
{
uint32 i; uint32 i;
for(i=0;i<key->nentries;i++) for (i = 0; i < key->nentries; i++)
startScanEntry( index, ginstate, key->scanEntry+i, key->firstCall ); startScanEntry(index, ginstate, key->scanEntry + i, key->firstCall);
if ( key->firstCall ) { if (key->firstCall)
memset( key->entryRes, TRUE, sizeof(bool) * key->nentries ); {
memset(key->entryRes, TRUE, sizeof(bool) * key->nentries);
key->isFinished = FALSE; key->isFinished = FALSE;
key->firstCall = FALSE; key->firstCall = FALSE;
if ( GinFuzzySearchLimit > 0 ) { if (GinFuzzySearchLimit > 0)
{
/* /*
* If all of keys more than treshold we will try to reduce * If all of keys more than treshold we will try to reduce result,
* result, we hope (and only hope, for intersection operation of array * we hope (and only hope, for intersection operation of array our
* our supposition isn't true), that total result will not more * supposition isn't true), that total result will not more than
* than minimal predictNumberResult. * minimal predictNumberResult.
*/ */
for(i=0;i<key->nentries;i++) for (i = 0; i < key->nentries; i++)
if ( key->scanEntry[i].predictNumberResult <= key->nentries * GinFuzzySearchLimit ) if (key->scanEntry[i].predictNumberResult <= key->nentries * GinFuzzySearchLimit)
return; return;
for(i=0;i<key->nentries;i++) 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].predictNumberResult /= key->nentries;
key->scanEntry[i].reduceResult = TRUE; key->scanEntry[i].reduceResult = TRUE;
} }
@ -170,50 +189,60 @@ startScanKey( Relation index, GinState *ginstate, GinScanKey key ) {
} }
static void static void
stopScanKey( GinScanKey key ) { stopScanKey(GinScanKey key)
{
uint32 i; uint32 i;
for(i=0;i<key->nentries;i++) for (i = 0; i < key->nentries; i++)
stopScanEntry( key->scanEntry+i ); stopScanEntry(key->scanEntry + i);
} }
static void static void
startScan( IndexScanDesc scan ) { startScan(IndexScanDesc scan)
{
uint32 i; uint32 i;
GinScanOpaque so = (GinScanOpaque) scan->opaque; GinScanOpaque so = (GinScanOpaque) scan->opaque;
for(i=0; i<so->nkeys; i++) for (i = 0; i < so->nkeys; i++)
startScanKey( scan->indexRelation, &so->ginstate, so->keys + i ); startScanKey(scan->indexRelation, &so->ginstate, so->keys + i);
} }
static void static void
stopScan( IndexScanDesc scan ) { stopScan(IndexScanDesc scan)
{
uint32 i; uint32 i;
GinScanOpaque so = (GinScanOpaque) scan->opaque; GinScanOpaque so = (GinScanOpaque) scan->opaque;
for(i=0; i<so->nkeys; i++) for (i = 0; i < so->nkeys; i++)
stopScanKey( so->keys + i ); stopScanKey(so->keys + i);
} }
static void static void
entryGetNextItem( Relation index, GinScanEntry entry ) { entryGetNextItem(Relation index, GinScanEntry entry)
Page page = BufferGetPage( entry->buffer ); {
Page page = BufferGetPage(entry->buffer);
entry->offset++; 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 { entry->curItem = *(ItemPointerData *) GinDataPageGetItem(page, entry->offset);
BlockNumber blkno = GinPageGetOpaque( page )->rightlink; }
else
{
BlockNumber blkno = GinPageGetOpaque(page)->rightlink;
LockBuffer( entry->buffer, GIN_UNLOCK ); LockBuffer(entry->buffer, GIN_UNLOCK);
if ( blkno == InvalidBlockNumber ) { if (blkno == InvalidBlockNumber)
ReleaseBuffer( entry->buffer ); {
ReleaseBuffer(entry->buffer);
entry->buffer = InvalidBuffer; entry->buffer = InvalidBuffer;
entry->isFinished = TRUE; entry->isFinished = TRUE;
} else { }
entry->buffer = ReleaseAndReadBuffer( entry->buffer, index, blkno ); else
LockBuffer( entry->buffer, GIN_SHARE ); {
entry->buffer = ReleaseAndReadBuffer(entry->buffer, index, blkno);
LockBuffer(entry->buffer, GIN_SHARE);
entry->offset = InvalidOffsetNumber; entry->offset = InvalidOffsetNumber;
entryGetNextItem(index, entry); entryGetNextItem(index, entry);
} }
@ -228,22 +257,30 @@ entryGetNextItem( Relation index, GinScanEntry entry ) {
* entry of one scan key * entry of one scan key
*/ */
static bool static bool
entryGetItem( Relation index, GinScanEntry entry ) { entryGetItem(Relation index, GinScanEntry entry)
if ( entry->master ) { {
if (entry->master)
{
entry->isFinished = entry->master->isFinished; entry->isFinished = entry->master->isFinished;
entry->curItem = entry->master->curItem; entry->curItem = entry->master->curItem;
} else if ( entry->list ) { }
else if (entry->list)
{
entry->offset++; entry->offset++;
if ( entry->offset <= entry->nlist ) if (entry->offset <= entry->nlist)
entry->curItem = entry->list[ entry->offset - 1 ]; entry->curItem = entry->list[entry->offset - 1];
else { else
ItemPointerSet( &entry->curItem, InvalidBlockNumber, InvalidOffsetNumber ); {
ItemPointerSet(&entry->curItem, InvalidBlockNumber, InvalidOffsetNumber);
entry->isFinished = TRUE; entry->isFinished = TRUE;
} }
} else { }
do { else
{
do
{
entryGetNextItem(index, entry); entryGetNextItem(index, entry);
} while ( entry->isFinished == FALSE && entry->reduceResult == TRUE && dropItem(entry) ); } while (entry->isFinished == FALSE && entry->reduceResult == TRUE && dropItem(entry));
} }
return entry->isFinished; return entry->isFinished;
@ -254,66 +291,79 @@ entryGetItem( Relation index, GinScanEntry entry ) {
* returns isFinished! * returns isFinished!
*/ */
static bool static bool
keyGetItem( Relation index, GinState *ginstate, MemoryContext tempCtx, GinScanKey key ) { keyGetItem(Relation index, GinState *ginstate, MemoryContext tempCtx, GinScanKey key)
{
uint32 i; uint32 i;
GinScanEntry entry; GinScanEntry entry;
bool res; bool res;
MemoryContext oldCtx; MemoryContext oldCtx;
if ( key->isFinished ) if (key->isFinished)
return TRUE; return TRUE;
do { do
/* move forward from previously value and set new curItem, {
which is minimal from entries->curItems */ /*
ItemPointerSetMax( &key->curItem ); * move forward from previously value and set new curItem, which is
for(i=0;i<key->nentries;i++) { * minimal from entries->curItems
entry = key->scanEntry+i; */
ItemPointerSetMax(&key->curItem);
for (i = 0; i < key->nentries; i++)
{
entry = key->scanEntry + i;
if ( key->entryRes[i] ) { if (key->entryRes[i])
if ( entry->isFinished == FALSE && entryGetItem(index, entry) == FALSE ) { {
if (compareItemPointers( &entry->curItem, &key->curItem ) < 0) if (entry->isFinished == FALSE && entryGetItem(index, entry) == FALSE)
{
if (compareItemPointers(&entry->curItem, &key->curItem) < 0)
key->curItem = entry->curItem; key->curItem = entry->curItem;
} else }
else
key->entryRes[i] = FALSE; key->entryRes[i] = FALSE;
} else if ( entry->isFinished == FALSE ) { }
if (compareItemPointers( &entry->curItem, &key->curItem ) < 0) else if (entry->isFinished == FALSE)
{
if (compareItemPointers(&entry->curItem, &key->curItem) < 0)
key->curItem = entry->curItem; key->curItem = entry->curItem;
} }
} }
if ( ItemPointerIsMax( &key->curItem ) ) { if (ItemPointerIsMax(&key->curItem))
{
/* all entries are finished */ /* all entries are finished */
key->isFinished = TRUE; key->isFinished = TRUE;
return TRUE; return TRUE;
} }
if ( key->nentries == 1 ) { if (key->nentries == 1)
{
/* we can do not call consistentFn !! */ /* we can do not call consistentFn !! */
key->entryRes[0] = TRUE; key->entryRes[0] = TRUE;
return FALSE; return FALSE;
} }
/* setting up array for consistentFn */ /* setting up array for consistentFn */
for(i=0;i<key->nentries;i++) { for (i = 0; i < key->nentries; i++)
entry = key->scanEntry+i; {
entry = key->scanEntry + i;
if ( entry->isFinished == FALSE && compareItemPointers( &entry->curItem, &key->curItem )==0 ) if (entry->isFinished == FALSE && compareItemPointers(&entry->curItem, &key->curItem) == 0)
key->entryRes[i] = TRUE; key->entryRes[i] = TRUE;
else else
key->entryRes[i] = FALSE; key->entryRes[i] = FALSE;
} }
oldCtx = MemoryContextSwitchTo(tempCtx); oldCtx = MemoryContextSwitchTo(tempCtx);
res = DatumGetBool( FunctionCall3( res = DatumGetBool(FunctionCall3(
&ginstate->consistentFn, &ginstate->consistentFn,
PointerGetDatum( key->entryRes ), PointerGetDatum(key->entryRes),
UInt16GetDatum( key->strategy ), UInt16GetDatum(key->strategy),
key->query key->query
)); ));
MemoryContextSwitchTo(oldCtx); MemoryContextSwitchTo(oldCtx);
MemoryContextReset(tempCtx); MemoryContextReset(tempCtx);
} while( !res ); } while (!res);
return FALSE; return FALSE;
} }
@ -323,35 +373,44 @@ keyGetItem( Relation index, GinState *ginstate, MemoryContext tempCtx, GinScanKe
* returns true if found * returns true if found
*/ */
static bool static bool
scanGetItem( IndexScanDesc scan, ItemPointerData *item ) { scanGetItem(IndexScanDesc scan, ItemPointerData *item)
{
uint32 i; uint32 i;
GinScanOpaque so = (GinScanOpaque) scan->opaque; GinScanOpaque so = (GinScanOpaque) scan->opaque;
ItemPointerSetMin( item ); ItemPointerSetMin(item);
for(i=0;i<so->nkeys;i++) { for (i = 0; i < so->nkeys; i++)
GinScanKey key = so->keys+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 ) {
if (compareItemPointers(item, &key->curItem) < 0)
*item = key->curItem; *item = key->curItem;
} else }
else
return FALSE; /* finshed one of keys */ 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; {
GinScanKey key = so->keys + i - 1;
for(;;) { for (;;)
int cmp = compareItemPointers( item, &key->curItem ); {
int cmp = compareItemPointers(item, &key->curItem);
if ( cmp == 0 ) if (cmp == 0)
break; break;
else if ( cmp > 0 ) { else if (cmp > 0)
if ( keyGetItem( scan->indexRelation, &so->ginstate, so->tempCtx, key )==TRUE ) {
if (keyGetItem(scan->indexRelation, &so->ginstate, so->tempCtx, key) == TRUE)
return FALSE; /* finshed one of keys */ return FALSE; /* finshed one of keys */
} else { /* returns to begin */ }
else
{ /* returns to begin */
*item = key->curItem; *item = key->curItem;
i=0; i = 0;
break; break;
} }
} }
@ -363,46 +422,49 @@ scanGetItem( IndexScanDesc scan, ItemPointerData *item ) {
#define GinIsNewKey(s) ( ((GinScanOpaque) scan->opaque)->keys == NULL ) #define GinIsNewKey(s) ( ((GinScanOpaque) scan->opaque)->keys == NULL )
Datum Datum
gingetmulti(PG_FUNCTION_ARGS) { gingetmulti(PG_FUNCTION_ARGS)
{
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
ItemPointer tids = (ItemPointer) PG_GETARG_POINTER(1); ItemPointer tids = (ItemPointer) PG_GETARG_POINTER(1);
int32 max_tids = PG_GETARG_INT32(2); int32 max_tids = PG_GETARG_INT32(2);
int32 *returned_tids = (int32 *) PG_GETARG_POINTER(3); int32 *returned_tids = (int32 *) PG_GETARG_POINTER(3);
if ( GinIsNewKey(scan) ) if (GinIsNewKey(scan))
newScanKey( scan ); newScanKey(scan);
startScan( scan ); startScan(scan);
*returned_tids = 0; *returned_tids = 0;
do { do
if ( scanGetItem( scan, tids + *returned_tids ) ) {
if (scanGetItem(scan, tids + *returned_tids))
(*returned_tids)++; (*returned_tids)++;
else else
break; break;
} while ( *returned_tids < max_tids ); } while (*returned_tids < max_tids);
stopScan( scan ); stopScan(scan);
PG_RETURN_BOOL(*returned_tids == max_tids); PG_RETURN_BOOL(*returned_tids == max_tids);
} }
Datum Datum
gingettuple(PG_FUNCTION_ARGS) { gingettuple(PG_FUNCTION_ARGS)
{
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1); ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1);
bool res; bool res;
if ( dir != ForwardScanDirection ) if (dir != ForwardScanDirection)
elog(ERROR, "Gin doesn't support other scan directions than forward"); elog(ERROR, "Gin doesn't support other scan directions than forward");
if ( GinIsNewKey(scan) ) if (GinIsNewKey(scan))
newScanKey( scan ); newScanKey(scan);
startScan( scan ); startScan(scan);
res = scanGetItem(scan, &scan->xs_ctup.t_self); res = scanGetItem(scan, &scan->xs_ctup.t_self);
stopScan( scan ); stopScan(scan);
PG_RETURN_BOOL(res); PG_RETURN_BOOL(res);
} }

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 "miscadmin.h"
#include "utils/memutils.h" #include "utils/memutils.h"
typedef struct { typedef struct
{
GinState ginstate; GinState ginstate;
double indtuples; double indtuples;
MemoryContext tmpCtx; MemoryContext tmpCtx;
@ -32,21 +33,23 @@ typedef struct {
* suppose that items[] fits to page * suppose that items[] fits to page
*/ */
static BlockNumber static BlockNumber
createPostingTree( Relation index, ItemPointerData *items, uint32 nitems ) { createPostingTree(Relation index, ItemPointerData *items, uint32 nitems)
{
BlockNumber blkno; BlockNumber blkno;
Buffer buffer = GinNewBuffer(index); Buffer buffer = GinNewBuffer(index);
Page page; Page page;
START_CRIT_SECTION(); START_CRIT_SECTION();
GinInitBuffer( buffer, GIN_DATA|GIN_LEAF ); GinInitBuffer(buffer, GIN_DATA | GIN_LEAF);
page = BufferGetPage(buffer); page = BufferGetPage(buffer);
blkno = BufferGetBlockNumber(buffer); blkno = BufferGetBlockNumber(buffer);
memcpy( GinDataPageGetData(page), items, sizeof(ItemPointerData) * nitems ); memcpy(GinDataPageGetData(page), items, sizeof(ItemPointerData) * nitems);
GinPageGetOpaque(page)->maxoff = nitems; GinPageGetOpaque(page)->maxoff = nitems;
if (!index->rd_istemp) { if (!index->rd_istemp)
{
XLogRecPtr recptr; XLogRecPtr recptr;
XLogRecData rdata[2]; XLogRecData rdata[2];
ginxlogCreatePostingTree data; ginxlogCreatePostingTree data;
@ -90,20 +93,24 @@ createPostingTree( Relation index, ItemPointerData *items, uint32 nitems ) {
*/ */
static IndexTuple static IndexTuple
addItemPointersToTuple(Relation index, GinState *ginstate, GinBtreeStack *stack, 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; bool isnull;
Datum key = index_getattr(old, FirstOffsetNumber, ginstate->tupdesc, &isnull); Datum key = index_getattr(old, FirstOffsetNumber, ginstate->tupdesc, &isnull);
IndexTuple res = GinFormTuple(ginstate, key, NULL, nitem + GinGetNPosting(old)); IndexTuple res = GinFormTuple(ginstate, key, NULL, nitem + GinGetNPosting(old));
if ( res ) { if (res)
{
/* good, small enough */ /* good, small enough */
MergeItemPointers( GinGetPosting(res), MergeItemPointers(GinGetPosting(res),
GinGetPosting(old), GinGetNPosting(old), GinGetPosting(old), GinGetNPosting(old),
items, nitem items, nitem
); );
GinSetNPosting(res, nitem + GinGetNPosting(old)); GinSetNPosting(res, nitem + GinGetNPosting(old));
} else { }
else
{
BlockNumber postingRoot; BlockNumber postingRoot;
GinPostingTreeScan *gdi; GinPostingTreeScan *gdi;
@ -128,32 +135,35 @@ addItemPointersToTuple(Relation index, GinState *ginstate, GinBtreeStack *stack,
* ItemPointer. * ItemPointer.
*/ */
static void 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; GinBtreeData btree;
GinBtreeStack *stack; GinBtreeStack *stack;
IndexTuple itup; IndexTuple itup;
Page page; Page page;
prepareEntryScan( &btree, index, value, ginstate ); prepareEntryScan(&btree, index, value, ginstate);
stack = ginFindLeafPage(&btree, NULL); stack = ginFindLeafPage(&btree, NULL);
page = BufferGetPage( stack->buffer ); page = BufferGetPage(stack->buffer);
if ( btree.findItem( &btree, stack ) ) { if (btree.findItem(&btree, stack))
{
/* found entry */ /* found entry */
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, stack->off)); itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, stack->off));
if ( GinIsPostingTree(itup) ) { if (GinIsPostingTree(itup))
{
/* lock root of posting tree */ /* lock root of posting tree */
GinPostingTreeScan *gdi; GinPostingTreeScan *gdi;
BlockNumber rootPostingTree = GinGetPostingTree(itup); BlockNumber rootPostingTree = GinGetPostingTree(itup);
/* release all stack */ /* release all stack */
LockBuffer(stack->buffer, GIN_UNLOCK); LockBuffer(stack->buffer, GIN_UNLOCK);
freeGinBtreeStack( stack ); freeGinBtreeStack(stack);
/* insert into posting tree */ /* insert into posting tree */
gdi = prepareScanPostingTree( index, rootPostingTree, FALSE ); gdi = prepareScanPostingTree(index, rootPostingTree, FALSE);
gdi->btree.isBuild = isBuild; gdi->btree.isBuild = isBuild;
insertItemPointer(gdi, items, nitem); insertItemPointer(gdi, items, nitem);
@ -163,23 +173,26 @@ ginEntryInsert( Relation index, GinState *ginstate, Datum value, ItemPointerData
itup = addItemPointersToTuple(index, ginstate, stack, itup, items, nitem, isBuild); itup = addItemPointersToTuple(index, ginstate, stack, itup, items, nitem, isBuild);
btree.isDelete = TRUE; btree.isDelete = TRUE;
} else { }
else
{
/* We suppose, that tuple can store at list one itempointer */ /* We suppose, that tuple can store at list one itempointer */
itup = GinFormTuple( ginstate, value, items, 1); itup = GinFormTuple(ginstate, value, items, 1);
if ( itup==NULL || IndexTupleSize(itup) >= GinMaxItemSize ) if (itup == NULL || IndexTupleSize(itup) >= GinMaxItemSize)
elog(ERROR, "huge tuple"); elog(ERROR, "huge tuple");
if ( nitem>1 ) { if (nitem > 1)
{
IndexTuple previtup = itup; IndexTuple previtup = itup;
itup = addItemPointersToTuple(index, ginstate, stack, previtup, items+1, nitem-1, isBuild); itup = addItemPointersToTuple(index, ginstate, stack, previtup, items + 1, nitem - 1, isBuild);
pfree(previtup); pfree(previtup);
} }
} }
btree.entry = itup; btree.entry = itup;
ginInsertValue(&btree, stack); ginInsertValue(&btree, stack);
pfree( itup ); pfree(itup);
} }
/* /*
@ -187,20 +200,21 @@ ginEntryInsert( Relation index, GinState *ginstate, Datum value, ItemPointerData
* Function isnt use during normal insert * Function isnt use during normal insert
*/ */
static uint32 static uint32
ginHeapTupleBulkInsert(GinBuildState *buildstate, Datum value, ItemPointer heapptr) { ginHeapTupleBulkInsert(GinBuildState *buildstate, Datum value, ItemPointer heapptr)
{
Datum *entries; Datum *entries;
uint32 nentries; uint32 nentries;
MemoryContext oldCtx; MemoryContext oldCtx;
oldCtx = MemoryContextSwitchTo(buildstate->funcCtx); oldCtx = MemoryContextSwitchTo(buildstate->funcCtx);
entries = extractEntriesSU( buildstate->accum.ginstate, value, &nentries); entries = extractEntriesSU(buildstate->accum.ginstate, value, &nentries);
MemoryContextSwitchTo(oldCtx); MemoryContextSwitchTo(oldCtx);
if ( nentries==0 ) if (nentries == 0)
/* nothing to insert */ /* nothing to insert */
return 0; return 0;
ginInsertRecordBA( &buildstate->accum, heapptr, entries, nentries); ginInsertRecordBA(&buildstate->accum, heapptr, entries, nentries);
MemoryContextReset(buildstate->funcCtx); MemoryContextReset(buildstate->funcCtx);
@ -209,26 +223,30 @@ ginHeapTupleBulkInsert(GinBuildState *buildstate, Datum value, ItemPointer heapp
static void static void
ginBuildCallback(Relation index, HeapTuple htup, Datum *values, ginBuildCallback(Relation index, HeapTuple htup, Datum *values,
bool *isnull, bool tupleIsAlive, void *state) { bool *isnull, bool tupleIsAlive, void *state)
{
GinBuildState *buildstate = (GinBuildState*)state; GinBuildState *buildstate = (GinBuildState *) state;
MemoryContext oldCtx; MemoryContext oldCtx;
if ( *isnull ) if (*isnull)
return; return;
oldCtx = MemoryContextSwitchTo(buildstate->tmpCtx); oldCtx = MemoryContextSwitchTo(buildstate->tmpCtx);
buildstate->indtuples += ginHeapTupleBulkInsert(buildstate, *values, &htup->t_self); 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 */ * we use only half maintenance_work_mem, because there is some leaks
if ( buildstate->accum.allocatedMemory >= maintenance_work_mem*1024L/2L ) { * during insertion and extract values
*/
if (buildstate->accum.allocatedMemory >= maintenance_work_mem * 1024L / 2L)
{
ItemPointerData *list; ItemPointerData *list;
Datum entry; Datum entry;
uint32 nlist; uint32 nlist;
while( (list=ginGetEntry(&buildstate->accum, &entry, &nlist)) != NULL ) while ((list = ginGetEntry(&buildstate->accum, &entry, &nlist)) != NULL)
ginEntryInsert(index, &buildstate->ginstate, entry, list, nlist, TRUE); ginEntryInsert(index, &buildstate->ginstate, entry, list, nlist, TRUE);
MemoryContextReset(buildstate->tmpCtx); MemoryContextReset(buildstate->tmpCtx);
@ -239,7 +257,8 @@ ginBuildCallback(Relation index, HeapTuple htup, Datum *values,
} }
Datum Datum
ginbuild(PG_FUNCTION_ARGS) { ginbuild(PG_FUNCTION_ARGS)
{
Relation heap = (Relation) PG_GETARG_POINTER(0); Relation heap = (Relation) PG_GETARG_POINTER(0);
Relation index = (Relation) PG_GETARG_POINTER(1); Relation index = (Relation) PG_GETARG_POINTER(1);
IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2); IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
@ -262,7 +281,8 @@ ginbuild(PG_FUNCTION_ARGS) {
buffer = GinNewBuffer(index); buffer = GinNewBuffer(index);
START_CRIT_SECTION(); START_CRIT_SECTION();
GinInitBuffer(buffer, GIN_LEAF); GinInitBuffer(buffer, GIN_LEAF);
if (!index->rd_istemp) { if (!index->rd_istemp)
{
XLogRecPtr recptr; XLogRecPtr recptr;
XLogRecData rdata; XLogRecData rdata;
Page page; Page page;
@ -305,14 +325,14 @@ ginbuild(PG_FUNCTION_ARGS) {
ALLOCSET_DEFAULT_MAXSIZE); ALLOCSET_DEFAULT_MAXSIZE);
buildstate.accum.ginstate = &buildstate.ginstate; buildstate.accum.ginstate = &buildstate.ginstate;
ginInitBA( &buildstate.accum ); ginInitBA(&buildstate.accum);
/* do the heap scan */ /* do the heap scan */
reltuples = IndexBuildHeapScan(heap, index, indexInfo, reltuples = IndexBuildHeapScan(heap, index, indexInfo,
ginBuildCallback, (void *) &buildstate); ginBuildCallback, (void *) &buildstate);
oldCtx = MemoryContextSwitchTo(buildstate.tmpCtx); oldCtx = MemoryContextSwitchTo(buildstate.tmpCtx);
while( (list=ginGetEntry(&buildstate.accum, &entry, &nlist)) != NULL ) while ((list = ginGetEntry(&buildstate.accum, &entry, &nlist)) != NULL)
ginEntryInsert(index, &buildstate.ginstate, entry, list, nlist, TRUE); ginEntryInsert(index, &buildstate.ginstate, entry, list, nlist, TRUE);
MemoryContextSwitchTo(oldCtx); MemoryContextSwitchTo(oldCtx);
@ -333,28 +353,32 @@ ginbuild(PG_FUNCTION_ARGS) {
* Inserts value during normal insertion * Inserts value during normal insertion
*/ */
static uint32 static uint32
ginHeapTupleInsert( Relation index, GinState *ginstate, Datum value, ItemPointer item) { ginHeapTupleInsert(Relation index, GinState *ginstate, Datum value, ItemPointer item)
{
Datum *entries; Datum *entries;
uint32 i,nentries; uint32 i,
nentries;
entries = extractEntriesSU( ginstate, value, &nentries); entries = extractEntriesSU(ginstate, value, &nentries);
if ( nentries==0 ) if (nentries == 0)
/* nothing to insert */ /* nothing to insert */
return 0; return 0;
for(i=0;i<nentries;i++) for (i = 0; i < nentries; i++)
ginEntryInsert(index, ginstate, entries[i], item, 1, FALSE); ginEntryInsert(index, ginstate, entries[i], item, 1, FALSE);
return nentries; return nentries;
} }
Datum Datum
gininsert(PG_FUNCTION_ARGS) { gininsert(PG_FUNCTION_ARGS)
{
Relation index = (Relation) PG_GETARG_POINTER(0); Relation index = (Relation) PG_GETARG_POINTER(0);
Datum *values = (Datum *) PG_GETARG_POINTER(1); Datum *values = (Datum *) PG_GETARG_POINTER(1);
bool *isnull = (bool *) PG_GETARG_POINTER(2); bool *isnull = (bool *) PG_GETARG_POINTER(2);
ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3); ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
#ifdef NOT_USED #ifdef NOT_USED
Relation heapRel = (Relation) PG_GETARG_POINTER(4); Relation heapRel = (Relation) PG_GETARG_POINTER(4);
bool checkUnique = PG_GETARG_BOOL(5); bool checkUnique = PG_GETARG_BOOL(5);
@ -364,7 +388,7 @@ gininsert(PG_FUNCTION_ARGS) {
MemoryContext insertCtx; MemoryContext insertCtx;
uint32 res; uint32 res;
if ( *isnull ) if (*isnull)
PG_RETURN_BOOL(false); PG_RETURN_BOOL(false);
insertCtx = AllocSetContextCreate(CurrentMemoryContext, insertCtx = AllocSetContextCreate(CurrentMemoryContext,
@ -382,6 +406,5 @@ gininsert(PG_FUNCTION_ARGS) {
MemoryContextSwitchTo(oldCtx); MemoryContextSwitchTo(oldCtx);
MemoryContextDelete(insertCtx); MemoryContextDelete(insertCtx);
PG_RETURN_BOOL(res>0); PG_RETURN_BOOL(res > 0);
} }

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 Datum
ginbeginscan(PG_FUNCTION_ARGS) { ginbeginscan(PG_FUNCTION_ARGS)
{
Relation rel = (Relation) PG_GETARG_POINTER(0); Relation rel = (Relation) PG_GETARG_POINTER(0);
int keysz = PG_GETARG_INT32(1); int keysz = PG_GETARG_INT32(1);
ScanKey scankey = (ScanKey) PG_GETARG_POINTER(2); ScanKey scankey = (ScanKey) PG_GETARG_POINTER(2);
@ -32,22 +33,25 @@ ginbeginscan(PG_FUNCTION_ARGS) {
} }
static void static void
fillScanKey( GinState *ginstate, GinScanKey key, Datum query, fillScanKey(GinState *ginstate, GinScanKey key, Datum query,
Datum *entryValues, uint32 nEntryValues, StrategyNumber strategy ) { Datum *entryValues, uint32 nEntryValues, StrategyNumber strategy)
uint32 i,j; {
uint32 i,
j;
key->nentries = nEntryValues; key->nentries = nEntryValues;
key->entryRes = (bool*)palloc0( sizeof(bool) * nEntryValues ); key->entryRes = (bool *) palloc0(sizeof(bool) * nEntryValues);
key->scanEntry = (GinScanEntry) palloc( sizeof(GinScanEntryData) * nEntryValues ); key->scanEntry = (GinScanEntry) palloc(sizeof(GinScanEntryData) * nEntryValues);
key->strategy = strategy; key->strategy = strategy;
key->query = query; key->query = query;
key->firstCall= TRUE; key->firstCall = TRUE;
ItemPointerSet( &(key->curItem), InvalidBlockNumber, InvalidOffsetNumber ); 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].pval = key->entryRes + i;
key->scanEntry[i].entry = entryValues[i]; key->scanEntry[i].entry = entryValues[i];
ItemPointerSet( &(key->scanEntry[i].curItem), InvalidBlockNumber, InvalidOffsetNumber ); ItemPointerSet(&(key->scanEntry[i].curItem), InvalidBlockNumber, InvalidOffsetNumber);
key->scanEntry[i].offset = InvalidOffsetNumber; key->scanEntry[i].offset = InvalidOffsetNumber;
key->scanEntry[i].buffer = InvalidBuffer; key->scanEntry[i].buffer = InvalidBuffer;
key->scanEntry[i].list = NULL; key->scanEntry[i].list = NULL;
@ -55,8 +59,9 @@ fillScanKey( GinState *ginstate, GinScanKey key, Datum query,
/* link to the equals entry in current scan key */ /* link to the equals entry in current scan key */
key->scanEntry[i].master = NULL; key->scanEntry[i].master = NULL;
for( j=0; j<i; j++) 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; key->scanEntry[i].master = key->scanEntry + j;
break; break;
} }
@ -66,23 +71,27 @@ fillScanKey( GinState *ginstate, GinScanKey key, Datum query,
#ifdef NOT_USED #ifdef NOT_USED
static void static void
resetScanKeys(GinScanKey keys, uint32 nkeys) { resetScanKeys(GinScanKey keys, uint32 nkeys)
uint32 i, j; {
uint32 i,
j;
if ( keys == NULL ) if (keys == NULL)
return; return;
for(i=0;i<nkeys;i++) { for (i = 0; i < nkeys; i++)
{
GinScanKey key = keys + i; GinScanKey key = keys + i;
key->firstCall = TRUE; key->firstCall = TRUE;
ItemPointerSet( &(key->curItem), InvalidBlockNumber, InvalidOffsetNumber ); 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 ); if (key->scanEntry[j].buffer != InvalidBuffer)
ReleaseBuffer(key->scanEntry[i].buffer);
ItemPointerSet( &(key->scanEntry[j].curItem), InvalidBlockNumber, InvalidOffsetNumber ); ItemPointerSet(&(key->scanEntry[j].curItem), InvalidBlockNumber, InvalidOffsetNumber);
key->scanEntry[j].offset = InvalidOffsetNumber; key->scanEntry[j].offset = InvalidOffsetNumber;
key->scanEntry[j].buffer = InvalidBuffer; key->scanEntry[j].buffer = InvalidBuffer;
key->scanEntry[j].list = NULL; key->scanEntry[j].list = NULL;
@ -90,27 +99,30 @@ resetScanKeys(GinScanKey keys, uint32 nkeys) {
} }
} }
} }
#endif #endif
static void static void
freeScanKeys(GinScanKey keys, uint32 nkeys, bool removeRes) { freeScanKeys(GinScanKey keys, uint32 nkeys, bool removeRes)
uint32 i, j; {
uint32 i,
j;
if ( keys == NULL ) if (keys == NULL)
return; return;
for(i=0;i<nkeys;i++) { for (i = 0; i < nkeys; i++)
{
GinScanKey key = keys + 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 (key->scanEntry[j].buffer != InvalidBuffer)
if ( removeRes && key->scanEntry[j].list ) ReleaseBuffer(key->scanEntry[j].buffer);
if (removeRes && key->scanEntry[j].list)
pfree(key->scanEntry[j].list); pfree(key->scanEntry[j].list);
} }
if ( removeRes ) if (removeRes)
pfree(key->entryRes); pfree(key->entryRes);
pfree(key->scanEntry); pfree(key->scanEntry);
} }
@ -119,47 +131,49 @@ freeScanKeys(GinScanKey keys, uint32 nkeys, bool removeRes) {
} }
void void
newScanKey( IndexScanDesc scan ) { newScanKey(IndexScanDesc scan)
{
ScanKey scankey = scan->keyData; ScanKey scankey = scan->keyData;
GinScanOpaque so = (GinScanOpaque) scan->opaque; GinScanOpaque so = (GinScanOpaque) scan->opaque;
int i; int i;
uint32 nkeys = 0; uint32 nkeys = 0;
so->keys = (GinScanKey) palloc( scan->numberOfKeys * sizeof(GinScanKeyData) ); so->keys = (GinScanKey) palloc(scan->numberOfKeys * sizeof(GinScanKeyData));
if (scan->numberOfKeys < 1) if (scan->numberOfKeys < 1)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("GIN indexes do not support whole-index scans"))); 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; {
Datum *entryValues;
uint32 nEntryValues; uint32 nEntryValues;
if ( scankey[i].sk_flags & SK_ISNULL ) if (scankey[i].sk_flags & SK_ISNULL)
elog(ERROR, "Gin doesn't support NULL as scan key"); elog(ERROR, "Gin doesn't support NULL as scan key");
Assert( scankey[i].sk_attno == 1 ); Assert(scankey[i].sk_attno == 1);
entryValues = (Datum*)DatumGetPointer( entryValues = (Datum *) DatumGetPointer(
FunctionCall3( FunctionCall3(
&so->ginstate.extractQueryFn, &so->ginstate.extractQueryFn,
scankey[i].sk_argument, scankey[i].sk_argument,
PointerGetDatum( &nEntryValues ), PointerGetDatum(&nEntryValues),
UInt16GetDatum(scankey[i].sk_strategy) UInt16GetDatum(scankey[i].sk_strategy)
) )
); );
if ( entryValues==NULL || nEntryValues == 0 ) if (entryValues == NULL || nEntryValues == 0)
/* full scan... */ /* full scan... */
continue; continue;
fillScanKey( &so->ginstate, &(so->keys[nkeys]), scankey[i].sk_argument, fillScanKey(&so->ginstate, &(so->keys[nkeys]), scankey[i].sk_argument,
entryValues, nEntryValues, scankey[i].sk_strategy ); entryValues, nEntryValues, scankey[i].sk_strategy);
nkeys++; nkeys++;
} }
so->nkeys = nkeys; so->nkeys = nkeys;
if ( so->nkeys == 0 ) if (so->nkeys == 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("GIN index doesn't support search with void query"))); errmsg("GIN index doesn't support search with void query")));
@ -168,16 +182,18 @@ newScanKey( IndexScanDesc scan ) {
} }
Datum Datum
ginrescan(PG_FUNCTION_ARGS) { ginrescan(PG_FUNCTION_ARGS)
{
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
ScanKey scankey = (ScanKey) PG_GETARG_POINTER(1); ScanKey scankey = (ScanKey) PG_GETARG_POINTER(1);
GinScanOpaque so; GinScanOpaque so;
so = (GinScanOpaque) scan->opaque; so = (GinScanOpaque) scan->opaque;
if ( so == NULL ) { if (so == NULL)
{
/* if called from ginbeginscan */ /* if called from ginbeginscan */
so = (GinScanOpaque)palloc( sizeof(GinScanOpaqueData) ); so = (GinScanOpaque) palloc(sizeof(GinScanOpaqueData));
so->tempCtx = AllocSetContextCreate(CurrentMemoryContext, so->tempCtx = AllocSetContextCreate(CurrentMemoryContext,
"Gin scan temporary context", "Gin scan temporary context",
ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_MINSIZE,
@ -185,14 +201,17 @@ ginrescan(PG_FUNCTION_ARGS) {
ALLOCSET_DEFAULT_MAXSIZE); ALLOCSET_DEFAULT_MAXSIZE);
initGinState(&so->ginstate, scan->indexRelation); initGinState(&so->ginstate, scan->indexRelation);
scan->opaque = so; scan->opaque = so;
} else { }
else
{
freeScanKeys(so->keys, so->nkeys, TRUE); freeScanKeys(so->keys, so->nkeys, TRUE);
freeScanKeys(so->markPos, so->nkeys, FALSE); freeScanKeys(so->markPos, so->nkeys, FALSE);
} }
so->markPos=so->keys=NULL; so->markPos = so->keys = NULL;
if ( scankey && scan->numberOfKeys > 0 ) { if (scankey && scan->numberOfKeys > 0)
{
memmove(scan->keyData, scankey, memmove(scan->keyData, scankey,
scan->numberOfKeys * sizeof(ScanKeyData)); scan->numberOfKeys * sizeof(ScanKeyData));
} }
@ -202,11 +221,13 @@ ginrescan(PG_FUNCTION_ARGS) {
Datum Datum
ginendscan(PG_FUNCTION_ARGS) { ginendscan(PG_FUNCTION_ARGS)
{
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
GinScanOpaque so = (GinScanOpaque) scan->opaque; GinScanOpaque so = (GinScanOpaque) scan->opaque;
if ( so != NULL ) { if (so != NULL)
{
freeScanKeys(so->keys, so->nkeys, TRUE); freeScanKeys(so->keys, so->nkeys, TRUE);
freeScanKeys(so->markPos, so->nkeys, FALSE); freeScanKeys(so->markPos, so->nkeys, FALSE);
@ -219,22 +240,28 @@ ginendscan(PG_FUNCTION_ARGS) {
} }
static GinScanKey static GinScanKey
copyScanKeys( GinScanKey keys, uint32 nkeys ) { copyScanKeys(GinScanKey keys, uint32 nkeys)
{
GinScanKey newkeys; GinScanKey newkeys;
uint32 i, j; uint32 i,
j;
newkeys = (GinScanKey)palloc( sizeof(GinScanKeyData) * nkeys ); newkeys = (GinScanKey) palloc(sizeof(GinScanKeyData) * nkeys);
memcpy( newkeys, keys, 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 ); 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].buffer != InvalidBuffer)
if ( keys[i].scanEntry[j].master ) { IncrBufferRefCount(keys[i].scanEntry[j].buffer);
if (keys[i].scanEntry[j].master)
{
int masterN = keys[i].scanEntry[j].master - keys[i].scanEntry; int masterN = keys[i].scanEntry[j].master - keys[i].scanEntry;
newkeys[i].scanEntry[j].master = newkeys[i].scanEntry + masterN; newkeys[i].scanEntry[j].master = newkeys[i].scanEntry + masterN;
} }
} }
@ -244,23 +271,25 @@ copyScanKeys( GinScanKey keys, uint32 nkeys ) {
} }
Datum Datum
ginmarkpos(PG_FUNCTION_ARGS) { ginmarkpos(PG_FUNCTION_ARGS)
{
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
GinScanOpaque so = (GinScanOpaque) scan->opaque; GinScanOpaque so = (GinScanOpaque) scan->opaque;
freeScanKeys(so->markPos, so->nkeys, FALSE); freeScanKeys(so->markPos, so->nkeys, FALSE);
so->markPos = copyScanKeys( so->keys, so->nkeys ); so->markPos = copyScanKeys(so->keys, so->nkeys);
PG_RETURN_VOID(); PG_RETURN_VOID();
} }
Datum Datum
ginrestrpos(PG_FUNCTION_ARGS) { ginrestrpos(PG_FUNCTION_ARGS)
{
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
GinScanOpaque so = (GinScanOpaque) scan->opaque; GinScanOpaque so = (GinScanOpaque) scan->opaque;
freeScanKeys(so->keys, so->nkeys, FALSE); freeScanKeys(so->keys, so->nkeys, FALSE);
so->keys = copyScanKeys( so->markPos, so->nkeys ); so->keys = copyScanKeys(so->markPos, so->nkeys);
PG_RETURN_VOID(); PG_RETURN_VOID();
} }

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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,8 +20,9 @@
#include "storage/freespace.h" #include "storage/freespace.h"
void void
initGinState( GinState *state, Relation index ) { initGinState(GinState *state, Relation index)
if ( index->rd_att->natts != 1 ) {
if (index->rd_att->natts != 1)
elog(ERROR, "numberOfAttributes %d != 1", elog(ERROR, "numberOfAttributes %d != 1",
index->rd_att->natts); index->rd_att->natts);
@ -48,13 +49,16 @@ initGinState( GinState *state, Relation index ) {
*/ */
Buffer Buffer
GinNewBuffer(Relation index) { GinNewBuffer(Relation index)
{
Buffer buffer; Buffer buffer;
bool needLock; bool needLock;
/* First, try to get a page from FSM */ /* First, try to get a page from FSM */
for(;;) { for (;;)
{
BlockNumber blkno = GetFreeIndexPage(&index->rd_node); BlockNumber blkno = GetFreeIndexPage(&index->rd_node);
if (blkno == InvalidBlockNumber) if (blkno == InvalidBlockNumber)
break; break;
@ -64,7 +68,8 @@ GinNewBuffer(Relation index) {
* We have to guard against the possibility that someone else already * We have to guard against the possibility that someone else already
* recycled this page; the buffer may be locked if so. * recycled this page; the buffer may be locked if so.
*/ */
if (ConditionalLockBuffer(buffer)) { if (ConditionalLockBuffer(buffer))
{
Page page = BufferGetPage(buffer); Page page = BufferGetPage(buffer);
if (PageIsNew(page)) if (PageIsNew(page))
@ -95,24 +100,27 @@ GinNewBuffer(Relation index) {
} }
void void
GinInitPage(Page page, uint32 f, Size pageSize) { GinInitPage(Page page, uint32 f, Size pageSize)
{
GinPageOpaque opaque; GinPageOpaque opaque;
PageInit(page, pageSize, sizeof(GinPageOpaqueData)); PageInit(page, pageSize, sizeof(GinPageOpaqueData));
opaque = GinPageGetOpaque(page); opaque = GinPageGetOpaque(page);
memset( opaque, 0, sizeof(GinPageOpaqueData) ); memset(opaque, 0, sizeof(GinPageOpaqueData));
opaque->flags = f; opaque->flags = f;
opaque->rightlink = InvalidBlockNumber; opaque->rightlink = InvalidBlockNumber;
} }
void void
GinInitBuffer(Buffer b, uint32 f) { GinInitBuffer(Buffer b, uint32 f)
GinInitPage( BufferGetPage(b), f, BufferGetPageSize(b) ); {
GinInitPage(BufferGetPage(b), f, BufferGetPageSize(b));
} }
int int
compareEntries(GinState *ginstate, Datum a, Datum b) { compareEntries(GinState *ginstate, Datum a, Datum b)
{
return DatumGetInt32( return DatumGetInt32(
FunctionCall2( FunctionCall2(
&ginstate->compareFn, &ginstate->compareFn,
@ -121,7 +129,7 @@ compareEntries(GinState *ginstate, Datum a, Datum b) {
); );
} }
static FmgrInfo* cmpDatumPtr=NULL; static FmgrInfo *cmpDatumPtr = NULL;
#if defined(__INTEL_COMPILER) && (defined(__ia64__) || defined(__ia64)) #if defined(__INTEL_COMPILER) && (defined(__ia64__) || defined(__ia64))
/* /*
@ -140,37 +148,40 @@ static FmgrInfo* cmpDatumPtr=NULL;
static bool VOLATILE needUnique = FALSE; static bool VOLATILE needUnique = FALSE;
static int static int
cmpEntries(const void * a, const void * b) { cmpEntries(const void *a, const void *b)
{
int res = DatumGetInt32( int res = DatumGetInt32(
FunctionCall2( FunctionCall2(
cmpDatumPtr, cmpDatumPtr,
*(Datum*)a, *(Datum *) a,
*(Datum*)b *(Datum *) b
) )
); );
if ( res == 0 ) if (res == 0)
needUnique = TRUE; needUnique = TRUE;
return res; return res;
} }
Datum* Datum *
extractEntriesS(GinState *ginstate, Datum value, uint32 *nentries) { extractEntriesS(GinState *ginstate, Datum value, uint32 *nentries)
{
Datum *entries; Datum *entries;
entries = (Datum*)DatumGetPointer( entries = (Datum *) DatumGetPointer(
FunctionCall2( FunctionCall2(
&ginstate->extractValueFn, &ginstate->extractValueFn,
value, value,
PointerGetDatum( nentries ) PointerGetDatum(nentries)
) )
); );
if ( entries == NULL ) if (entries == NULL)
*nentries = 0; *nentries = 0;
if ( *nentries > 1 ) { if (*nentries > 1)
{
cmpDatumPtr = &ginstate->compareFn; cmpDatumPtr = &ginstate->compareFn;
needUnique = FALSE; needUnique = FALSE;
qsort(entries, *nentries, sizeof(Datum), cmpEntries); qsort(entries, *nentries, sizeof(Datum), cmpEntries);
@ -180,17 +191,21 @@ extractEntriesS(GinState *ginstate, Datum value, uint32 *nentries) {
} }
Datum* Datum *
extractEntriesSU(GinState *ginstate, Datum value, uint32 *nentries) { extractEntriesSU(GinState *ginstate, Datum value, uint32 *nentries)
{
Datum *entries = extractEntriesS(ginstate, value, nentries); Datum *entries = extractEntriesS(ginstate, value, nentries);
if ( *nentries>1 && needUnique ) { if (*nentries > 1 && needUnique)
Datum *ptr, *res; {
Datum *ptr,
*res;
ptr = res = entries; ptr = res = entries;
while( ptr - entries < *nentries ) { while (ptr - entries < *nentries)
if ( compareEntries(ginstate, *ptr, *res ) != 0 ) {
if (compareEntries(ginstate, *ptr, *res) != 0)
*(++res) = *ptr++; *(++res) = *ptr++;
else else
ptr++; ptr++;
@ -206,12 +221,13 @@ extractEntriesSU(GinState *ginstate, Datum value, uint32 *nentries) {
* It's analog of PageGetTempPage(), but copies whole page * It's analog of PageGetTempPage(), but copies whole page
*/ */
Page Page
GinPageGetCopyPage( Page page ) { GinPageGetCopyPage(Page page)
Size pageSize = PageGetPageSize( page ); {
Size pageSize = PageGetPageSize(page);
Page tmppage; Page tmppage;
tmppage=(Page)palloc( pageSize ); tmppage = (Page) palloc(pageSize);
memcpy( tmppage, page, pageSize ); memcpy(tmppage, page, pageSize);
return tmppage; return tmppage;
} }

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 "storage/freespace.h"
#include "commands/vacuum.h" #include "commands/vacuum.h"
typedef struct { typedef struct
{
Relation index; Relation index;
IndexBulkDeleteResult *result; IndexBulkDeleteResult *result;
IndexBulkDeleteCallback callback; IndexBulkDeleteCallback callback;
@ -39,24 +40,31 @@ typedef struct {
*/ */
static uint32 static uint32
ginVacuumPostingList( GinVacuumState *gvs, ItemPointerData *items, uint32 nitem, ItemPointerData **cleaned ) { ginVacuumPostingList(GinVacuumState *gvs, ItemPointerData *items, uint32 nitem, ItemPointerData **cleaned)
uint32 i,j=0; {
uint32 i,
j = 0;
/* /*
* just scan over ItemPointer array * just scan over ItemPointer array
*/ */
for(i=0;i<nitem;i++) { for (i = 0; i < nitem; i++)
if ( gvs->callback(items+i, gvs->callback_state) ) { {
if (gvs->callback(items + i, gvs->callback_state))
{
gvs->result->tuples_removed += 1; gvs->result->tuples_removed += 1;
if ( !*cleaned ) { if (!*cleaned)
*cleaned = (ItemPointerData*)palloc(sizeof(ItemPointerData)*nitem); {
if ( i!=0 ) *cleaned = (ItemPointerData *) palloc(sizeof(ItemPointerData) * nitem);
memcpy( *cleaned, items, sizeof(ItemPointerData)*i); if (i != 0)
memcpy(*cleaned, items, sizeof(ItemPointerData) * i);
} }
} else { }
else
{
gvs->result->num_index_tuples += 1; gvs->result->num_index_tuples += 1;
if (i!=j) if (i != j)
(*cleaned)[j] = items[i]; (*cleaned)[j] = items[i];
j++; j++;
} }
@ -69,16 +77,17 @@ ginVacuumPostingList( GinVacuumState *gvs, ItemPointerData *items, uint32 nitem,
* fills WAL record for vacuum leaf page * fills WAL record for vacuum leaf page
*/ */
static void static void
xlogVacuumPage(Relation index, Buffer buffer) { xlogVacuumPage(Relation index, Buffer buffer)
Page page = BufferGetPage( buffer ); {
Page page = BufferGetPage(buffer);
XLogRecPtr recptr; XLogRecPtr recptr;
XLogRecData rdata[3]; XLogRecData rdata[3];
ginxlogVacuumPage data; ginxlogVacuumPage data;
char *backup; char *backup;
char itups[BLCKSZ]; char itups[BLCKSZ];
uint32 len=0; uint32 len = 0;
Assert( GinPageIsLeaf( page ) ); Assert(GinPageIsLeaf(page));
if (index->rd_istemp) if (index->rd_istemp)
return; return;
@ -86,39 +95,47 @@ xlogVacuumPage(Relation index, Buffer buffer) {
data.node = index->rd_node; data.node = index->rd_node;
data.blkno = BufferGetBlockNumber(buffer); data.blkno = BufferGetBlockNumber(buffer);
if ( GinPageIsData( page ) ) { if (GinPageIsData(page))
backup = GinDataPageGetData( page ); {
data.nitem = GinPageGetOpaque( page )->maxoff; backup = GinDataPageGetData(page);
if ( data.nitem ) data.nitem = GinPageGetOpaque(page)->maxoff;
len = MAXALIGN( sizeof(ItemPointerData)*data.nitem ); if (data.nitem)
} else { len = MAXALIGN(sizeof(ItemPointerData) * data.nitem);
}
else
{
char *ptr; char *ptr;
OffsetNumber i; OffsetNumber i;
ptr = backup = itups; 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)); IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
memcpy( ptr, itup, IndexTupleSize( itup ) );
ptr += MAXALIGN( IndexTupleSize( itup ) ); memcpy(ptr, itup, IndexTupleSize(itup));
ptr += MAXALIGN(IndexTupleSize(itup));
} }
data.nitem = PageGetMaxOffsetNumber(page); data.nitem = PageGetMaxOffsetNumber(page);
len = ptr-backup; len = ptr - backup;
} }
rdata[0].buffer = buffer; rdata[0].buffer = buffer;
rdata[0].buffer_std = ( GinPageIsData( page ) ) ? FALSE : TRUE; rdata[0].buffer_std = (GinPageIsData(page)) ? FALSE : TRUE;
rdata[0].len = 0; rdata[0].len = 0;
rdata[0].data = NULL; rdata[0].data = NULL;
rdata[0].next = rdata + 1; rdata[0].next = rdata + 1;
rdata[1].buffer = InvalidBuffer; rdata[1].buffer = InvalidBuffer;
rdata[1].len = sizeof(ginxlogVacuumPage); rdata[1].len = sizeof(ginxlogVacuumPage);
rdata[1].data = (char*)&data; rdata[1].data = (char *) &data;
if ( len == 0 ) { if (len == 0)
{
rdata[1].next = NULL; rdata[1].next = NULL;
} else { }
else
{
rdata[1].next = rdata + 2; rdata[1].next = rdata + 2;
rdata[2].buffer = InvalidBuffer; rdata[2].buffer = InvalidBuffer;
@ -133,71 +150,84 @@ xlogVacuumPage(Relation index, Buffer buffer) {
} }
static bool 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 ); Buffer buffer = ReadBuffer(gvs->index, blkno);
Page page = BufferGetPage(buffer);
bool hasVoidPage = FALSE; bool hasVoidPage = FALSE;
/* /*
* We should be sure that we don't concurrent with inserts, insert process * 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). * never release root page until end (but it can unlock it and lock
* If we lock root with with LockBufferForCleanup, new scan process can't begin, * again). If we lock root with with LockBufferForCleanup, new scan
* but previous may run. * process can't begin, but previous may run. ginmarkpos/start* keeps
* ginmarkpos/start* keeps buffer pinned, so we will wait for it. * buffer pinned, so we will wait for it. We lock only one posting tree in
* We lock only one posting tree in whole index, so, it's concurrent enough.. * whole index, so, it's concurrent enough.. Side effect: after this is
* Side effect: after this is full complete, tree is unused by any other process * full complete, tree is unused by any other process
*/ */
LockBufferForCleanup( buffer ); LockBufferForCleanup(buffer);
Assert( GinPageIsData(page) ); Assert(GinPageIsData(page));
if ( GinPageIsLeaf(page) ) { if (GinPageIsLeaf(page))
OffsetNumber newMaxOff, oldMaxOff = GinPageGetOpaque(page)->maxoff; {
OffsetNumber newMaxOff,
oldMaxOff = GinPageGetOpaque(page)->maxoff;
ItemPointerData *cleaned = NULL; ItemPointerData *cleaned = NULL;
newMaxOff = ginVacuumPostingList( gvs, newMaxOff = ginVacuumPostingList(gvs,
(ItemPointer)GinDataPageGetData(page), oldMaxOff, &cleaned ); (ItemPointer) GinDataPageGetData(page), oldMaxOff, &cleaned);
/* saves changes about deleted tuple ... */ /* saves changes about deleted tuple ... */
if ( oldMaxOff != newMaxOff ) { if (oldMaxOff != newMaxOff)
{
START_CRIT_SECTION(); START_CRIT_SECTION();
if ( newMaxOff > 0 ) if (newMaxOff > 0)
memcpy( GinDataPageGetData(page), cleaned, sizeof(ItemPointerData) * newMaxOff ); memcpy(GinDataPageGetData(page), cleaned, sizeof(ItemPointerData) * newMaxOff);
pfree( cleaned ); pfree(cleaned);
GinPageGetOpaque(page)->maxoff = newMaxOff; GinPageGetOpaque(page)->maxoff = newMaxOff;
xlogVacuumPage(gvs->index, buffer); xlogVacuumPage(gvs->index, buffer);
MarkBufferDirty( buffer ); MarkBufferDirty(buffer);
END_CRIT_SECTION(); END_CRIT_SECTION();
/* if root is a leaf page, we don't desire futher processing */ /* if root is a leaf page, we don't desire futher processing */
if ( !isRoot && GinPageGetOpaque(page)->maxoff < FirstOffsetNumber ) if (!isRoot && GinPageGetOpaque(page)->maxoff < FirstOffsetNumber)
hasVoidPage = TRUE; hasVoidPage = TRUE;
} }
} else { }
else
{
OffsetNumber i; OffsetNumber i;
bool isChildHasVoid = FALSE; 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 ) ) PostingItem *pitem = (PostingItem *) GinDataPageGetItem(page, i);
if (ginVacuumPostingTreeLeaves(gvs, PostingItemGetBlockNumber(pitem), FALSE, NULL))
isChildHasVoid = TRUE; isChildHasVoid = TRUE;
} }
if ( isChildHasVoid ) if (isChildHasVoid)
hasVoidPage = TRUE; 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 we have root and theres void pages in tree, then we don't release
if ( !(isRoot && hasVoidPage) ) { * lock to go further processing and guarantee that tree is unused
UnlockReleaseBuffer( buffer ); */
} else { if (!(isRoot && hasVoidPage))
Assert( rootBuffer ); {
UnlockReleaseBuffer(buffer);
}
else
{
Assert(rootBuffer);
*rootBuffer = buffer; *rootBuffer = buffer;
} }
@ -206,37 +236,42 @@ ginVacuumPostingTreeLeaves( GinVacuumState *gvs, BlockNumber blkno, bool isRoot,
static void static void
ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkno, 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 dBuffer = ReadBuffer(gvs->index, deleteBlkno);
Buffer pBuffer = ReadBuffer( gvs->index, parentBlkno ); Buffer lBuffer = (leftBlkno == InvalidBlockNumber) ? InvalidBuffer : ReadBuffer(gvs->index, leftBlkno);
Page page, parentPage; Buffer pBuffer = ReadBuffer(gvs->index, parentBlkno);
Page page,
parentPage;
LockBuffer( dBuffer, GIN_EXCLUSIVE ); LockBuffer(dBuffer, GIN_EXCLUSIVE);
if ( !isParentRoot ) /* parent is already locked by LockBufferForCleanup() */ if (!isParentRoot) /* parent is already locked by
LockBuffer( pBuffer, GIN_EXCLUSIVE ); * LockBufferForCleanup() */
LockBuffer(pBuffer, GIN_EXCLUSIVE);
START_CRIT_SECTION(); START_CRIT_SECTION();
if ( leftBlkno!= InvalidBlockNumber ) { if (leftBlkno != InvalidBlockNumber)
{
BlockNumber rightlink; BlockNumber rightlink;
LockBuffer( lBuffer, GIN_EXCLUSIVE ); LockBuffer(lBuffer, GIN_EXCLUSIVE);
page = BufferGetPage( dBuffer ); page = BufferGetPage(dBuffer);
rightlink = GinPageGetOpaque(page)->rightlink; rightlink = GinPageGetOpaque(page)->rightlink;
page = BufferGetPage( lBuffer ); page = BufferGetPage(lBuffer);
GinPageGetOpaque(page)->rightlink = rightlink; GinPageGetOpaque(page)->rightlink = rightlink;
} }
parentPage = BufferGetPage( pBuffer ); parentPage = BufferGetPage(pBuffer);
PageDeletePostingItem(parentPage, myoff); PageDeletePostingItem(parentPage, myoff);
page = BufferGetPage( dBuffer ); page = BufferGetPage(dBuffer);
GinPageGetOpaque(page)->flags = GIN_DELETED; GinPageGetOpaque(page)->flags = GIN_DELETED;
if (!gvs->index->rd_istemp) { if (!gvs->index->rd_istemp)
{
XLogRecPtr recptr; XLogRecPtr recptr;
XLogRecData rdata[4]; XLogRecData rdata[4];
ginxlogDeletePage data; ginxlogDeletePage data;
@ -261,20 +296,22 @@ ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkn
rdata[1].len = 0; rdata[1].len = 0;
rdata[1].next = rdata + 2; rdata[1].next = rdata + 2;
if ( leftBlkno!= InvalidBlockNumber ) { if (leftBlkno != InvalidBlockNumber)
{
rdata[2].buffer = lBuffer; rdata[2].buffer = lBuffer;
rdata[2].buffer_std = FALSE; rdata[2].buffer_std = FALSE;
rdata[2].data = NULL; rdata[2].data = NULL;
rdata[2].len = 0; rdata[2].len = 0;
rdata[2].next = rdata + 3; rdata[2].next = rdata + 3;
n = 3; n = 3;
} else }
else
n = 2; n = 2;
rdata[n].buffer = InvalidBuffer; rdata[n].buffer = InvalidBuffer;
rdata[n].buffer_std = FALSE; rdata[n].buffer_std = FALSE;
rdata[n].len = sizeof(ginxlogDeletePage); rdata[n].len = sizeof(ginxlogDeletePage);
rdata[n].data = (char*)&data; rdata[n].data = (char *) &data;
rdata[n].next = NULL; rdata[n].next = NULL;
recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_DELETE_PAGE, rdata); recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_DELETE_PAGE, rdata);
@ -282,32 +319,35 @@ ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkn
PageSetTLI(page, ThisTimeLineID); PageSetTLI(page, ThisTimeLineID);
PageSetLSN(parentPage, recptr); PageSetLSN(parentPage, recptr);
PageSetTLI(parentPage, ThisTimeLineID); PageSetTLI(parentPage, ThisTimeLineID);
if ( leftBlkno!= InvalidBlockNumber ) { if (leftBlkno != InvalidBlockNumber)
page = BufferGetPage( lBuffer ); {
page = BufferGetPage(lBuffer);
PageSetLSN(page, recptr); PageSetLSN(page, recptr);
PageSetTLI(page, ThisTimeLineID); PageSetTLI(page, ThisTimeLineID);
} }
} }
MarkBufferDirty( pBuffer ); MarkBufferDirty(pBuffer);
if ( !isParentRoot ) if (!isParentRoot)
LockBuffer( pBuffer, GIN_UNLOCK ); LockBuffer(pBuffer, GIN_UNLOCK);
ReleaseBuffer( pBuffer ); ReleaseBuffer(pBuffer);
if ( leftBlkno!= InvalidBlockNumber ) { if (leftBlkno != InvalidBlockNumber)
MarkBufferDirty( lBuffer ); {
UnlockReleaseBuffer( lBuffer ); MarkBufferDirty(lBuffer);
UnlockReleaseBuffer(lBuffer);
} }
MarkBufferDirty( dBuffer ); MarkBufferDirty(dBuffer);
UnlockReleaseBuffer( dBuffer ); UnlockReleaseBuffer(dBuffer);
END_CRIT_SECTION(); END_CRIT_SECTION();
gvs->result->pages_deleted++; gvs->result->pages_deleted++;
} }
typedef struct DataPageDeleteStack { typedef struct DataPageDeleteStack
{
struct DataPageDeleteStack *child; struct DataPageDeleteStack *child;
struct DataPageDeleteStack *parent; struct DataPageDeleteStack *parent;
@ -319,85 +359,101 @@ typedef struct DataPageDeleteStack {
* scans posting tree and deletes empty pages * scans posting tree and deletes empty pages
*/ */
static bool 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; DataPageDeleteStack *me;
Buffer buffer; Buffer buffer;
Page page; Page page;
bool meDelete = FALSE; bool meDelete = FALSE;
if ( isRoot ) { if (isRoot)
{
me = parent; me = parent;
} else { }
if ( ! parent->child ) { else
me = (DataPageDeleteStack*)palloc0(sizeof(DataPageDeleteStack)); {
me->parent=parent; if (!parent->child)
{
me = (DataPageDeleteStack *) palloc0(sizeof(DataPageDeleteStack));
me->parent = parent;
parent->child = me; parent->child = me;
me->blkno = InvalidBlockNumber; me->blkno = InvalidBlockNumber;
} else }
else
me = parent->child; me = parent->child;
} }
buffer = ReadBuffer( gvs->index, blkno ); buffer = ReadBuffer(gvs->index, blkno);
page = BufferGetPage( buffer ); page = BufferGetPage(buffer);
Assert( GinPageIsData(page) ); Assert(GinPageIsData(page));
if ( !GinPageIsLeaf(page) ) { if (!GinPageIsLeaf(page))
{
OffsetNumber i; OffsetNumber i;
for(i=FirstOffsetNumber;i<=GinPageGetOpaque(page)->maxoff;i++) { for (i = FirstOffsetNumber; i <= GinPageGetOpaque(page)->maxoff; i++)
PostingItem *pitem = (PostingItem*)GinDataPageGetItem(page, i); {
PostingItem *pitem = (PostingItem *) GinDataPageGetItem(page, i);
if ( ginScanToDelete( gvs, PostingItemGetBlockNumber(pitem), FALSE, me, i ) ) if (ginScanToDelete(gvs, PostingItemGetBlockNumber(pitem), FALSE, me, i))
i--; i--;
} }
} }
if ( GinPageGetOpaque(page)->maxoff < FirstOffsetNumber ) { if (GinPageGetOpaque(page)->maxoff < FirstOffsetNumber)
if ( !( me->blkno == InvalidBlockNumber && GinPageRightMost(page) ) ) { {
if (!(me->blkno == InvalidBlockNumber && GinPageRightMost(page)))
{
/* we never delete right most branch */ /* we never delete right most branch */
Assert( !isRoot ); Assert(!isRoot);
if ( GinPageGetOpaque(page)->maxoff < FirstOffsetNumber ) { if (GinPageGetOpaque(page)->maxoff < FirstOffsetNumber)
ginDeletePage( gvs, blkno, me->blkno, me->parent->blkno, myoff, me->parent->isRoot ); {
ginDeletePage(gvs, blkno, me->blkno, me->parent->blkno, myoff, me->parent->isRoot);
meDelete = TRUE; meDelete = TRUE;
} }
} }
} }
ReleaseBuffer( buffer ); ReleaseBuffer(buffer);
if ( !meDelete ) if (!meDelete)
me->blkno = blkno; me->blkno = blkno;
return meDelete; return meDelete;
} }
static void static void
ginVacuumPostingTree( GinVacuumState *gvs, BlockNumber rootBlkno ) { ginVacuumPostingTree(GinVacuumState *gvs, BlockNumber rootBlkno)
{
Buffer rootBuffer = InvalidBuffer; 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 ); {
Assert(rootBuffer == InvalidBuffer);
return; return;
} }
memset(&root,0,sizeof(DataPageDeleteStack)); memset(&root, 0, sizeof(DataPageDeleteStack));
root.blkno = rootBlkno; root.blkno = rootBlkno;
root.isRoot = TRUE; root.isRoot = TRUE;
vacuum_delay_point(); vacuum_delay_point();
ginScanToDelete( gvs, rootBlkno, TRUE, &root, InvalidOffsetNumber ); ginScanToDelete(gvs, rootBlkno, TRUE, &root, InvalidOffsetNumber);
ptr = root.child; ptr = root.child;
while( ptr ) { while (ptr)
{
tmp = ptr->child; tmp = ptr->child;
pfree( ptr ); pfree(ptr);
ptr = tmp; ptr = tmp;
} }
UnlockReleaseBuffer( rootBuffer ); UnlockReleaseBuffer(rootBuffer);
} }
/* /*
@ -406,48 +462,65 @@ ginVacuumPostingTree( GinVacuumState *gvs, BlockNumber rootBlkno ) {
* then page is copied into temprorary one. * then page is copied into temprorary one.
*/ */
static Page static Page
ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint32 *nroot) { ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint32 *nroot)
Page origpage = BufferGetPage( buffer ), tmppage; {
OffsetNumber i, maxoff = PageGetMaxOffsetNumber( origpage ); Page origpage = BufferGetPage(buffer),
tmppage;
OffsetNumber i,
maxoff = PageGetMaxOffsetNumber(origpage);
tmppage = origpage; tmppage = origpage;
*nroot=0; *nroot = 0;
for(i=FirstOffsetNumber; i<= maxoff; i++) { for (i = FirstOffsetNumber; i <= maxoff; i++)
{
IndexTuple itup = (IndexTuple) PageGetItem(tmppage, PageGetItemId(tmppage, i)); IndexTuple itup = (IndexTuple) PageGetItem(tmppage, PageGetItemId(tmppage, i));
if ( GinIsPostingTree(itup) ) { 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); * 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)++; (*nroot)++;
} else if ( GinGetNPosting(itup) > 0 ) { }
/* if we already create temrorary page, we will make changes in place */ else if (GinGetNPosting(itup) > 0)
ItemPointerData *cleaned = (tmppage==origpage) ? NULL : GinGetPosting(itup ); {
uint32 newN = ginVacuumPostingList( gvs, GinGetPosting(itup), GinGetNPosting(itup), &cleaned ); /*
* 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; bool isnull;
Datum value; 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 * On first difference we create temprorary page in memory
* and copies content in to it. * and copies content in to it.
*/ */
tmppage=GinPageGetCopyPage ( origpage ); tmppage = GinPageGetCopyPage(origpage);
if ( newN > 0 ) { if (newN > 0)
Size pos = ((char*)GinGetPosting(itup)) - ((char*)origpage); {
memcpy( tmppage+pos, cleaned, sizeof(ItemPointerData)*newN ); Size pos = ((char *) GinGetPosting(itup)) - ((char *) origpage);
memcpy(tmppage + pos, cleaned, sizeof(ItemPointerData) * newN);
} }
pfree( cleaned ); pfree(cleaned);
/* set itup pointer to new page */ /* set itup pointer to new page */
itup = (IndexTuple) PageGetItem(tmppage, PageGetItemId(tmppage, i)); itup = (IndexTuple) PageGetItem(tmppage, PageGetItemId(tmppage, i));
@ -457,20 +530,21 @@ ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint3
itup = GinFormTuple(&gvs->ginstate, value, GinGetPosting(itup), newN); itup = GinFormTuple(&gvs->ginstate, value, GinGetPosting(itup), newN);
PageIndexTupleDelete(tmppage, i); PageIndexTupleDelete(tmppage, i);
if ( PageAddItem( tmppage, (Item)itup, IndexTupleSize(itup), i, LP_USED ) != i ) if (PageAddItem(tmppage, (Item) itup, IndexTupleSize(itup), i, LP_USED) != i)
elog(ERROR, "failed to add item to index page in \"%s\"", elog(ERROR, "failed to add item to index page in \"%s\"",
RelationGetRelationName(gvs->index)); RelationGetRelationName(gvs->index));
pfree( itup ); pfree(itup);
} }
} }
} }
return ( tmppage==origpage ) ? NULL : tmppage; return (tmppage == origpage) ? NULL : tmppage;
} }
Datum Datum
ginbulkdelete(PG_FUNCTION_ARGS) { ginbulkdelete(PG_FUNCTION_ARGS)
{
IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0); IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1); IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(2); IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(2);
@ -479,7 +553,7 @@ ginbulkdelete(PG_FUNCTION_ARGS) {
BlockNumber blkno = GIN_ROOT_BLKNO; BlockNumber blkno = GIN_ROOT_BLKNO;
GinVacuumState gvs; GinVacuumState gvs;
Buffer buffer; Buffer buffer;
BlockNumber rootOfPostingTree[ BLCKSZ/ (sizeof(IndexTupleData)+sizeof(ItemId)) ]; BlockNumber rootOfPostingTree[BLCKSZ / (sizeof(IndexTupleData) + sizeof(ItemId))];
uint32 nRoot; uint32 nRoot;
/* first time through? */ /* first time through? */
@ -494,81 +568,90 @@ ginbulkdelete(PG_FUNCTION_ARGS) {
gvs.callback_state = callback_state; gvs.callback_state = callback_state;
initGinState(&gvs.ginstate, index); initGinState(&gvs.ginstate, index);
buffer = ReadBuffer( index, blkno ); buffer = ReadBuffer(index, blkno);
/* find leaf page */ /* find leaf page */
for(;;) { for (;;)
Page page = BufferGetPage( buffer ); {
Page page = BufferGetPage(buffer);
IndexTuple itup; IndexTuple itup;
LockBuffer(buffer,GIN_SHARE); LockBuffer(buffer, GIN_SHARE);
Assert( !GinPageIsData(page) ); Assert(!GinPageIsData(page));
if ( GinPageIsLeaf(page) ) { if (GinPageIsLeaf(page))
LockBuffer(buffer,GIN_UNLOCK); {
LockBuffer(buffer,GIN_EXCLUSIVE); 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); {
LockBuffer(buffer, GIN_UNLOCK);
continue; /* check it one more */ continue; /* check it one more */
} }
break; break;
} }
Assert( PageGetMaxOffsetNumber(page) >= FirstOffsetNumber ); Assert(PageGetMaxOffsetNumber(page) >= FirstOffsetNumber);
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, FirstOffsetNumber)); itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, FirstOffsetNumber));
blkno = GinItemPointerGetBlockNumber(&(itup)->t_tid); blkno = GinItemPointerGetBlockNumber(&(itup)->t_tid);
Assert( blkno!= InvalidBlockNumber ); Assert(blkno != InvalidBlockNumber);
LockBuffer(buffer,GIN_UNLOCK); LockBuffer(buffer, GIN_UNLOCK);
buffer = ReleaseAndReadBuffer( buffer, index, blkno ); buffer = ReleaseAndReadBuffer(buffer, index, blkno);
} }
/* right now we found leftmost page in entry's BTree */ /* right now we found leftmost page in entry's BTree */
for(;;) { for (;;)
Page page = BufferGetPage( buffer ); {
Page page = BufferGetPage(buffer);
Page resPage; Page resPage;
uint32 i; uint32 i;
Assert( !GinPageIsData(page) ); Assert(!GinPageIsData(page));
resPage = ginVacuumEntryPage(&gvs, buffer, rootOfPostingTree, &nRoot); resPage = ginVacuumEntryPage(&gvs, buffer, rootOfPostingTree, &nRoot);
blkno = GinPageGetOpaque( page )->rightlink; blkno = GinPageGetOpaque(page)->rightlink;
if ( resPage ) { if (resPage)
{
START_CRIT_SECTION(); START_CRIT_SECTION();
PageRestoreTempPage( resPage, page ); PageRestoreTempPage(resPage, page);
xlogVacuumPage(gvs.index, buffer); xlogVacuumPage(gvs.index, buffer);
MarkBufferDirty( buffer ); MarkBufferDirty(buffer);
UnlockReleaseBuffer(buffer); UnlockReleaseBuffer(buffer);
END_CRIT_SECTION(); END_CRIT_SECTION();
} else { }
else
{
UnlockReleaseBuffer(buffer); UnlockReleaseBuffer(buffer);
} }
vacuum_delay_point(); vacuum_delay_point();
for(i=0; i<nRoot; i++) { for (i = 0; i < nRoot; i++)
ginVacuumPostingTree( &gvs, rootOfPostingTree[i] ); {
ginVacuumPostingTree(&gvs, rootOfPostingTree[i]);
vacuum_delay_point(); vacuum_delay_point();
} }
if ( blkno==InvalidBlockNumber ) /*rightmost page*/ if (blkno == InvalidBlockNumber) /* rightmost page */
break; break;
buffer = ReadBuffer( index, blkno ); buffer = ReadBuffer(index, blkno);
LockBuffer(buffer,GIN_EXCLUSIVE); LockBuffer(buffer, GIN_EXCLUSIVE);
} }
PG_RETURN_POINTER(gvs.result); PG_RETURN_POINTER(gvs.result);
} }
Datum Datum
ginvacuumcleanup(PG_FUNCTION_ARGS) { ginvacuumcleanup(PG_FUNCTION_ARGS)
{
IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0); IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1); IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
Relation index = info->index; Relation index = info->index;
@ -585,16 +668,17 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) {
/* Set up all-zero stats if ginbulkdelete wasn't called */ /* Set up all-zero stats if ginbulkdelete wasn't called */
if (stats == NULL) if (stats == NULL)
stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult)); stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
/* /*
* XXX we always report the heap tuple count as the number of index * 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 * entries. This is bogus if the index is partial, but it's real hard to
* to tell how many distinct heap entries are referenced by a GIN index. * tell how many distinct heap entries are referenced by a GIN index.
*/ */
stats->num_index_tuples = info->num_heap_tuples; stats->num_index_tuples = info->num_heap_tuples;
/* /*
* If vacuum full, we already have exclusive lock on the index. * If vacuum full, we already have exclusive lock on the index. Otherwise,
* Otherwise, need lock unless it's local to this backend. * need lock unless it's local to this backend.
*/ */
if (info->vacuum_full) if (info->vacuum_full)
needLock = false; needLock = false;
@ -614,7 +698,8 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) {
totFreePages = nFreePages = 0; totFreePages = nFreePages = 0;
freePages = (BlockNumber *) palloc(sizeof(BlockNumber) * maxFreePages); 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; Buffer buffer;
Page page; Page page;
@ -624,22 +709,27 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) {
LockBuffer(buffer, GIN_SHARE); LockBuffer(buffer, GIN_SHARE);
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
if ( GinPageIsDeleted(page) ) { if (GinPageIsDeleted(page))
{
if (nFreePages < maxFreePages) if (nFreePages < maxFreePages)
freePages[nFreePages++] = blkno; freePages[nFreePages++] = blkno;
totFreePages++; totFreePages++;
} else }
else
lastFilledBlock = blkno; lastFilledBlock = blkno;
UnlockReleaseBuffer(buffer); UnlockReleaseBuffer(buffer);
} }
lastBlock = npages - 1; lastBlock = npages - 1;
if (info->vacuum_full && nFreePages > 0) { if (info->vacuum_full && nFreePages > 0)
{
/* try to truncate index */ /* try to truncate index */
int i; int i;
for (i = 0; i < nFreePages; i++) for (i = 0; i < nFreePages; i++)
if (freePages[i] >= lastFilledBlock) { if (freePages[i] >= lastFilledBlock)
{
totFreePages = nFreePages = i; totFreePages = nFreePages = i;
break; break;
} }
@ -661,4 +751,3 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) {
PG_RETURN_POINTER(stats); PG_RETURN_POINTER(stats);
} }

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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" #include "postgres.h"
@ -20,7 +20,8 @@
static MemoryContext opCtx; /* working memory for operations */ static MemoryContext opCtx; /* working memory for operations */
static MemoryContext topCtx; static MemoryContext topCtx;
typedef struct ginIncompleteSplit { typedef struct ginIncompleteSplit
{
RelFileNode node; RelFileNode node;
BlockNumber leftBlkno; BlockNumber leftBlkno;
BlockNumber rightBlkno; BlockNumber rightBlkno;
@ -30,10 +31,11 @@ typedef struct ginIncompleteSplit {
static List *incomplete_splits; static List *incomplete_splits;
static void static void
pushIncompleteSplit(RelFileNode node, BlockNumber leftBlkno, BlockNumber rightBlkno, BlockNumber rootBlkno) { pushIncompleteSplit(RelFileNode node, BlockNumber leftBlkno, BlockNumber rightBlkno, BlockNumber rootBlkno)
{
ginIncompleteSplit *split; ginIncompleteSplit *split;
MemoryContextSwitchTo( topCtx ); MemoryContextSwitchTo(topCtx);
split = palloc(sizeof(ginIncompleteSplit)); split = palloc(sizeof(ginIncompleteSplit));
@ -44,17 +46,20 @@ pushIncompleteSplit(RelFileNode node, BlockNumber leftBlkno, BlockNumber rightBl
incomplete_splits = lappend(incomplete_splits, split); incomplete_splits = lappend(incomplete_splits, split);
MemoryContextSwitchTo( opCtx ); MemoryContextSwitchTo(opCtx);
} }
static void static void
forgetIncompleteSplit(RelFileNode node, BlockNumber leftBlkno, BlockNumber updateBlkno) { forgetIncompleteSplit(RelFileNode node, BlockNumber leftBlkno, BlockNumber updateBlkno)
{
ListCell *l; ListCell *l;
foreach(l, incomplete_splits) { foreach(l, incomplete_splits)
{
ginIncompleteSplit *split = (ginIncompleteSplit *) lfirst(l); 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); incomplete_splits = list_delete_ptr(incomplete_splits, split);
break; break;
} }
@ -62,7 +67,8 @@ forgetIncompleteSplit(RelFileNode node, BlockNumber leftBlkno, BlockNumber updat
} }
static void static void
ginRedoCreateIndex(XLogRecPtr lsn, XLogRecord *record) { ginRedoCreateIndex(XLogRecPtr lsn, XLogRecord *record)
{
RelFileNode *node = (RelFileNode *) XLogRecGetData(record); RelFileNode *node = (RelFileNode *) XLogRecGetData(record);
Relation reln; Relation reln;
Buffer buffer; Buffer buffer;
@ -83,9 +89,10 @@ ginRedoCreateIndex(XLogRecPtr lsn, XLogRecord *record) {
} }
static void static void
ginRedoCreatePTree(XLogRecPtr lsn, XLogRecord *record) { ginRedoCreatePTree(XLogRecPtr lsn, XLogRecord *record)
ginxlogCreatePostingTree *data = (ginxlogCreatePostingTree*)XLogRecGetData(record); {
ItemPointerData *items = (ItemPointerData*)(XLogRecGetData(record) + sizeof(ginxlogCreatePostingTree)); ginxlogCreatePostingTree *data = (ginxlogCreatePostingTree *) XLogRecGetData(record);
ItemPointerData *items = (ItemPointerData *) (XLogRecGetData(record) + sizeof(ginxlogCreatePostingTree));
Relation reln; Relation reln;
Buffer buffer; Buffer buffer;
Page page; Page page;
@ -95,8 +102,8 @@ ginRedoCreatePTree(XLogRecPtr lsn, XLogRecord *record) {
Assert(BufferIsValid(buffer)); Assert(BufferIsValid(buffer));
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
GinInitBuffer(buffer, GIN_DATA|GIN_LEAF); GinInitBuffer(buffer, GIN_DATA | GIN_LEAF);
memcpy( GinDataPageGetData(page), items, sizeof(ItemPointerData) * data->nitem ); memcpy(GinDataPageGetData(page), items, sizeof(ItemPointerData) * data->nitem);
GinPageGetOpaque(page)->maxoff = data->nitem; GinPageGetOpaque(page)->maxoff = data->nitem;
PageSetLSN(page, lsn); PageSetLSN(page, lsn);
@ -107,8 +114,9 @@ ginRedoCreatePTree(XLogRecPtr lsn, XLogRecord *record) {
} }
static void static void
ginRedoInsert(XLogRecPtr lsn, XLogRecord *record) { ginRedoInsert(XLogRecPtr lsn, XLogRecord *record)
ginxlogInsert *data = (ginxlogInsert*)XLogRecGetData(record); {
ginxlogInsert *data = (ginxlogInsert *) XLogRecGetData(record);
Relation reln; Relation reln;
Buffer buffer; Buffer buffer;
Page page; Page page;
@ -122,64 +130,73 @@ ginRedoInsert(XLogRecPtr lsn, XLogRecord *record) {
Assert(BufferIsValid(buffer)); Assert(BufferIsValid(buffer));
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
if ( data->isData ) { if (data->isData)
Assert( data->isDelete == FALSE ); {
Assert( GinPageIsData( page ) ); Assert(data->isDelete == FALSE);
Assert(GinPageIsData(page));
if ( data->isLeaf ) { if (data->isLeaf)
{
OffsetNumber i; OffsetNumber i;
ItemPointerData *items = (ItemPointerData*)( XLogRecGetData(record) + sizeof(ginxlogInsert) ); ItemPointerData *items = (ItemPointerData *) (XLogRecGetData(record) + sizeof(ginxlogInsert));
Assert( GinPageIsLeaf( page ) ); Assert(GinPageIsLeaf(page));
Assert( data->updateBlkno == InvalidBlockNumber ); Assert(data->updateBlkno == InvalidBlockNumber);
for(i=0;i<data->nitem;i++) for (i = 0; i < data->nitem; i++)
GinDataPageAddItem( page, items+i, data->offset + i ); GinDataPageAddItem(page, items + i, data->offset + i);
} else { }
else
{
PostingItem *pitem; PostingItem *pitem;
Assert( !GinPageIsLeaf( page ) ); Assert(!GinPageIsLeaf(page));
if ( data->updateBlkno != InvalidBlockNumber ) { if (data->updateBlkno != InvalidBlockNumber)
{
/* update link to right page after split */ /* update link to right page after split */
pitem = (PostingItem*)GinDataPageGetItem(page, data->offset); pitem = (PostingItem *) GinDataPageGetItem(page, data->offset);
PostingItemSetBlockNumber( pitem, data->updateBlkno ); PostingItemSetBlockNumber(pitem, data->updateBlkno);
} }
pitem = (PostingItem*)( XLogRecGetData(record) + sizeof(ginxlogInsert) ); pitem = (PostingItem *) (XLogRecGetData(record) + sizeof(ginxlogInsert));
GinDataPageAddItem( page, pitem, data->offset ); GinDataPageAddItem(page, pitem, data->offset);
if ( data->updateBlkno != InvalidBlockNumber ) if (data->updateBlkno != InvalidBlockNumber)
forgetIncompleteSplit(data->node, PostingItemGetBlockNumber( pitem ), data->updateBlkno); forgetIncompleteSplit(data->node, PostingItemGetBlockNumber(pitem), data->updateBlkno);
} }
} else { }
else
{
IndexTuple itup; IndexTuple itup;
Assert( !GinPageIsData( page ) ); Assert(!GinPageIsData(page));
if ( data->updateBlkno != InvalidBlockNumber ) { if (data->updateBlkno != InvalidBlockNumber)
{
/* update link to right page after split */ /* update link to right page after split */
Assert( !GinPageIsLeaf( page ) ); Assert(!GinPageIsLeaf(page));
Assert( data->offset>=FirstOffsetNumber && data->offset<=PageGetMaxOffsetNumber(page) ); Assert(data->offset >= FirstOffsetNumber && data->offset <= PageGetMaxOffsetNumber(page));
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, data->offset)); itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, data->offset));
ItemPointerSet(&itup->t_tid, data->updateBlkno, InvalidOffsetNumber); ItemPointerSet(&itup->t_tid, data->updateBlkno, InvalidOffsetNumber);
} }
if ( data->isDelete ) { if (data->isDelete)
Assert( GinPageIsLeaf( page ) ); {
Assert( data->offset>=FirstOffsetNumber && data->offset<=PageGetMaxOffsetNumber(page) ); Assert(GinPageIsLeaf(page));
Assert(data->offset >= FirstOffsetNumber && data->offset <= PageGetMaxOffsetNumber(page));
PageIndexTupleDelete(page, data->offset); PageIndexTupleDelete(page, data->offset);
} }
itup = (IndexTuple)( XLogRecGetData(record) + sizeof(ginxlogInsert) ); itup = (IndexTuple) (XLogRecGetData(record) + sizeof(ginxlogInsert));
if ( PageAddItem( page, (Item)itup, IndexTupleSize(itup), data->offset, LP_USED) == InvalidOffsetNumber ) if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), data->offset, LP_USED) == InvalidOffsetNumber)
elog(ERROR, "failed to add item to index page in %u/%u/%u", elog(ERROR, "failed to add item to index page in %u/%u/%u",
data->node.spcNode, data->node.dbNode, data->node.relNode ); data->node.spcNode, data->node.dbNode, data->node.relNode);
if ( !data->isLeaf && data->updateBlkno != InvalidBlockNumber ) if (!data->isLeaf && data->updateBlkno != InvalidBlockNumber)
forgetIncompleteSplit(data->node, GinItemPointerGetBlockNumber( &itup->t_tid ), data->updateBlkno); forgetIncompleteSplit(data->node, GinItemPointerGetBlockNumber(&itup->t_tid), data->updateBlkno);
} }
PageSetLSN(page, lsn); PageSetLSN(page, lsn);
@ -190,18 +207,21 @@ ginRedoInsert(XLogRecPtr lsn, XLogRecord *record) {
} }
static void static void
ginRedoSplit(XLogRecPtr lsn, XLogRecord *record) { ginRedoSplit(XLogRecPtr lsn, XLogRecord *record)
ginxlogSplit *data = (ginxlogSplit*)XLogRecGetData(record); {
ginxlogSplit *data = (ginxlogSplit *) XLogRecGetData(record);
Relation reln; Relation reln;
Buffer lbuffer, rbuffer; Buffer lbuffer,
Page lpage, rpage; rbuffer;
Page lpage,
rpage;
uint32 flags = 0; uint32 flags = 0;
reln = XLogOpenRelation(data->node); reln = XLogOpenRelation(data->node);
if ( data->isLeaf ) if (data->isLeaf)
flags |= GIN_LEAF; flags |= GIN_LEAF;
if ( data->isData ) if (data->isData)
flags |= GIN_DATA; flags |= GIN_DATA;
lbuffer = XLogReadBuffer(reln, data->lblkno, data->isRootSplit); lbuffer = XLogReadBuffer(reln, data->lblkno, data->isRootSplit);
@ -214,50 +234,57 @@ ginRedoSplit(XLogRecPtr lsn, XLogRecord *record) {
rpage = (Page) BufferGetPage(rbuffer); rpage = (Page) BufferGetPage(rbuffer);
GinInitBuffer(rbuffer, flags); GinInitBuffer(rbuffer, flags);
GinPageGetOpaque(lpage)->rightlink = BufferGetBlockNumber( rbuffer ); GinPageGetOpaque(lpage)->rightlink = BufferGetBlockNumber(rbuffer);
GinPageGetOpaque(rpage)->rightlink = data->rrlink; GinPageGetOpaque(rpage)->rightlink = data->rrlink;
if ( data->isData ) { if (data->isData)
{
char *ptr = XLogRecGetData(record) + sizeof(ginxlogSplit); char *ptr = XLogRecGetData(record) + sizeof(ginxlogSplit);
Size sizeofitem = GinSizeOfItem(lpage); Size sizeofitem = GinSizeOfItem(lpage);
OffsetNumber i; OffsetNumber i;
ItemPointer bound; ItemPointer bound;
for(i=0;i<data->separator;i++) { for (i = 0; i < data->separator; i++)
GinDataPageAddItem( lpage, ptr, InvalidOffsetNumber ); {
GinDataPageAddItem(lpage, ptr, InvalidOffsetNumber);
ptr += sizeofitem; ptr += sizeofitem;
} }
for(i=data->separator;i<data->nitem;i++) { for (i = data->separator; i < data->nitem; i++)
GinDataPageAddItem( rpage, ptr, InvalidOffsetNumber ); {
GinDataPageAddItem(rpage, ptr, InvalidOffsetNumber);
ptr += sizeofitem; ptr += sizeofitem;
} }
/* set up right key */ /* set up right key */
bound = GinDataPageGetRightBound(lpage); bound = GinDataPageGetRightBound(lpage);
if ( data->isLeaf ) if (data->isLeaf)
*bound = *(ItemPointerData*)GinDataPageGetItem(lpage, GinPageGetOpaque(lpage)->maxoff); *bound = *(ItemPointerData *) GinDataPageGetItem(lpage, GinPageGetOpaque(lpage)->maxoff);
else else
*bound = ((PostingItem*)GinDataPageGetItem(lpage, GinPageGetOpaque(lpage)->maxoff))->key; *bound = ((PostingItem *) GinDataPageGetItem(lpage, GinPageGetOpaque(lpage)->maxoff))->key;
bound = GinDataPageGetRightBound(rpage); bound = GinDataPageGetRightBound(rpage);
*bound = data->rightbound; *bound = data->rightbound;
} else { }
IndexTuple itup = (IndexTuple)( XLogRecGetData(record) + sizeof(ginxlogSplit) ); else
{
IndexTuple itup = (IndexTuple) (XLogRecGetData(record) + sizeof(ginxlogSplit));
OffsetNumber i; 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 ) {
if (PageAddItem(lpage, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber)
elog(ERROR, "failed to add item to index page in %u/%u/%u", elog(ERROR, "failed to add item to index page in %u/%u/%u",
data->node.spcNode, data->node.dbNode, data->node.relNode ); data->node.spcNode, data->node.dbNode, data->node.relNode);
itup = (IndexTuple)( ((char*)itup) + MAXALIGN( IndexTupleSize(itup) ) ); 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 ) {
if (PageAddItem(rpage, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber)
elog(ERROR, "failed to add item to index page in %u/%u/%u", elog(ERROR, "failed to add item to index page in %u/%u/%u",
data->node.spcNode, data->node.dbNode, data->node.relNode ); data->node.spcNode, data->node.dbNode, data->node.relNode);
itup = (IndexTuple)( ((char*)itup) + MAXALIGN( IndexTupleSize(itup) ) ); itup = (IndexTuple) (((char *) itup) + MAXALIGN(IndexTupleSize(itup)));
} }
} }
@ -269,20 +296,24 @@ ginRedoSplit(XLogRecPtr lsn, XLogRecord *record) {
PageSetTLI(lpage, ThisTimeLineID); PageSetTLI(lpage, ThisTimeLineID);
MarkBufferDirty(lbuffer); MarkBufferDirty(lbuffer);
if ( !data->isLeaf && data->updateBlkno != InvalidBlockNumber ) if (!data->isLeaf && data->updateBlkno != InvalidBlockNumber)
forgetIncompleteSplit(data->node, data->leftChildBlkno, data->updateBlkno); forgetIncompleteSplit(data->node, data->leftChildBlkno, data->updateBlkno);
if ( data->isRootSplit ) { if (data->isRootSplit)
{
Buffer rootBuf = XLogReadBuffer(reln, data->rootBlkno, false); Buffer rootBuf = XLogReadBuffer(reln, data->rootBlkno, false);
Page rootPage = BufferGetPage( rootBuf ); Page rootPage = BufferGetPage(rootBuf);
GinInitBuffer( rootBuf, flags & ~GIN_LEAF ); GinInitBuffer(rootBuf, flags & ~GIN_LEAF);
if ( data->isData ) { if (data->isData)
Assert( data->rootBlkno != GIN_ROOT_BLKNO ); {
Assert(data->rootBlkno != GIN_ROOT_BLKNO);
dataFillRoot(NULL, rootBuf, lbuffer, rbuffer); dataFillRoot(NULL, rootBuf, lbuffer, rbuffer);
} else { }
Assert( data->rootBlkno == GIN_ROOT_BLKNO ); else
{
Assert(data->rootBlkno == GIN_ROOT_BLKNO);
entryFillRoot(NULL, rootBuf, lbuffer, rbuffer); entryFillRoot(NULL, rootBuf, lbuffer, rbuffer);
} }
@ -291,7 +322,8 @@ ginRedoSplit(XLogRecPtr lsn, XLogRecord *record) {
MarkBufferDirty(rootBuf); MarkBufferDirty(rootBuf);
UnlockReleaseBuffer(rootBuf); UnlockReleaseBuffer(rootBuf);
} else }
else
pushIncompleteSplit(data->node, data->lblkno, data->rblkno, data->rootBlkno); pushIncompleteSplit(data->node, data->lblkno, data->rblkno, data->rootBlkno);
UnlockReleaseBuffer(rbuffer); UnlockReleaseBuffer(rbuffer);
@ -299,8 +331,9 @@ ginRedoSplit(XLogRecPtr lsn, XLogRecord *record) {
} }
static void static void
ginRedoVacuumPage(XLogRecPtr lsn, XLogRecord *record) { ginRedoVacuumPage(XLogRecPtr lsn, XLogRecord *record)
ginxlogVacuumPage *data = (ginxlogVacuumPage*)XLogRecGetData(record); {
ginxlogVacuumPage *data = (ginxlogVacuumPage *) XLogRecGetData(record);
Relation reln; Relation reln;
Buffer buffer; Buffer buffer;
Page page; Page page;
@ -314,25 +347,30 @@ ginRedoVacuumPage(XLogRecPtr lsn, XLogRecord *record) {
Assert(BufferIsValid(buffer)); Assert(BufferIsValid(buffer));
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
if ( GinPageIsData( page ) ) { if (GinPageIsData(page))
memcpy( GinDataPageGetData(page), XLogRecGetData(record) + sizeof(ginxlogVacuumPage), {
GinSizeOfItem(page) * data->nitem ); memcpy(GinDataPageGetData(page), XLogRecGetData(record) + sizeof(ginxlogVacuumPage),
GinSizeOfItem(page) *data->nitem);
GinPageGetOpaque(page)->maxoff = data->nitem; GinPageGetOpaque(page)->maxoff = data->nitem;
} else { }
OffsetNumber i, *tod; else
IndexTuple itup = (IndexTuple)( XLogRecGetData(record) + sizeof(ginxlogVacuumPage) ); {
OffsetNumber i,
*tod;
IndexTuple itup = (IndexTuple) (XLogRecGetData(record) + sizeof(ginxlogVacuumPage));
tod = (OffsetNumber*)palloc( sizeof(OffsetNumber) * PageGetMaxOffsetNumber(page) ); tod = (OffsetNumber *) palloc(sizeof(OffsetNumber) * PageGetMaxOffsetNumber(page));
for(i=FirstOffsetNumber;i<=PageGetMaxOffsetNumber(page);i++) for (i = FirstOffsetNumber; i <= PageGetMaxOffsetNumber(page); i++)
tod[i-1] = i; tod[i - 1] = i;
PageIndexMultiDelete(page, tod, PageGetMaxOffsetNumber(page)); 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 ) {
if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber)
elog(ERROR, "failed to add item to index page in %u/%u/%u", elog(ERROR, "failed to add item to index page in %u/%u/%u",
data->node.spcNode, data->node.dbNode, data->node.relNode ); data->node.spcNode, data->node.dbNode, data->node.relNode);
itup = (IndexTuple)( ((char*)itup) + MAXALIGN( IndexTupleSize(itup) ) ); itup = (IndexTuple) (((char *) itup) + MAXALIGN(IndexTupleSize(itup)));
} }
} }
@ -344,17 +382,19 @@ ginRedoVacuumPage(XLogRecPtr lsn, XLogRecord *record) {
} }
static void static void
ginRedoDeletePage(XLogRecPtr lsn, XLogRecord *record) { ginRedoDeletePage(XLogRecPtr lsn, XLogRecord *record)
ginxlogDeletePage *data = (ginxlogDeletePage*)XLogRecGetData(record); {
ginxlogDeletePage *data = (ginxlogDeletePage *) XLogRecGetData(record);
Relation reln; Relation reln;
Buffer buffer; Buffer buffer;
Page page; Page page;
reln = XLogOpenRelation(data->node); 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); buffer = XLogReadBuffer(reln, data->blkno, false);
page = BufferGetPage( buffer ); page = BufferGetPage(buffer);
Assert(GinPageIsData(page)); Assert(GinPageIsData(page));
GinPageGetOpaque(page)->flags = GIN_DELETED; GinPageGetOpaque(page)->flags = GIN_DELETED;
PageSetLSN(page, lsn); PageSetLSN(page, lsn);
@ -363,9 +403,10 @@ ginRedoDeletePage(XLogRecPtr lsn, XLogRecord *record) {
UnlockReleaseBuffer(buffer); UnlockReleaseBuffer(buffer);
} }
if ( !( record->xl_info & XLR_BKP_BLOCK_2) ) { if (!(record->xl_info & XLR_BKP_BLOCK_2))
{
buffer = XLogReadBuffer(reln, data->parentBlkno, false); buffer = XLogReadBuffer(reln, data->parentBlkno, false);
page = BufferGetPage( buffer ); page = BufferGetPage(buffer);
Assert(GinPageIsData(page)); Assert(GinPageIsData(page));
Assert(!GinPageIsLeaf(page)); Assert(!GinPageIsLeaf(page));
PageDeletePostingItem(page, data->parentOffset); PageDeletePostingItem(page, data->parentOffset);
@ -375,9 +416,10 @@ ginRedoDeletePage(XLogRecPtr lsn, XLogRecord *record) {
UnlockReleaseBuffer(buffer); 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); buffer = XLogReadBuffer(reln, data->leftBlkno, false);
page = BufferGetPage( buffer ); page = BufferGetPage(buffer);
Assert(GinPageIsData(page)); Assert(GinPageIsData(page));
GinPageGetOpaque(page)->rightlink = data->rightLink; GinPageGetOpaque(page)->rightlink = data->rightLink;
PageSetLSN(page, lsn); PageSetLSN(page, lsn);
@ -388,11 +430,13 @@ ginRedoDeletePage(XLogRecPtr lsn, XLogRecord *record) {
} }
void void
gin_redo(XLogRecPtr lsn, XLogRecord *record) { gin_redo(XLogRecPtr lsn, XLogRecord *record)
{
uint8 info = record->xl_info & ~XLR_INFO_MASK; uint8 info = record->xl_info & ~XLR_INFO_MASK;
topCtx = MemoryContextSwitchTo(opCtx); topCtx = MemoryContextSwitchTo(opCtx);
switch (info) { switch (info)
{
case XLOG_GIN_CREATE_INDEX: case XLOG_GIN_CREATE_INDEX:
ginRedoCreateIndex(lsn, record); ginRedoCreateIndex(lsn, record);
break; break;
@ -419,49 +463,52 @@ gin_redo(XLogRecPtr lsn, XLogRecord *record) {
} }
static void 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", {
appendStringInfo(buf, "node: %u/%u/%u blkno: %u",
node.spcNode, node.dbNode, node.relNode, blkno); node.spcNode, node.dbNode, node.relNode, blkno);
} }
void 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; uint8 info = xl_info & ~XLR_INFO_MASK;
switch (info) { switch (info)
{
case XLOG_GIN_CREATE_INDEX: case XLOG_GIN_CREATE_INDEX:
appendStringInfo(buf,"Create index, "); appendStringInfo(buf, "Create index, ");
desc_node(buf, *(RelFileNode*)rec, GIN_ROOT_BLKNO ); desc_node(buf, *(RelFileNode *) rec, GIN_ROOT_BLKNO);
break; break;
case XLOG_GIN_CREATE_PTREE: case XLOG_GIN_CREATE_PTREE:
appendStringInfo(buf,"Create posting tree, "); appendStringInfo(buf, "Create posting tree, ");
desc_node(buf, ((ginxlogCreatePostingTree*)rec)->node, ((ginxlogCreatePostingTree*)rec)->blkno ); desc_node(buf, ((ginxlogCreatePostingTree *) rec)->node, ((ginxlogCreatePostingTree *) rec)->blkno);
break; break;
case XLOG_GIN_INSERT: case XLOG_GIN_INSERT:
appendStringInfo(buf,"Insert item, "); appendStringInfo(buf, "Insert item, ");
desc_node(buf, ((ginxlogInsert*)rec)->node, ((ginxlogInsert*)rec)->blkno ); desc_node(buf, ((ginxlogInsert *) rec)->node, ((ginxlogInsert *) rec)->blkno);
appendStringInfo(buf," offset: %u nitem: %u isdata: %c isleaf %c isdelete %c updateBlkno:%u", appendStringInfo(buf, " offset: %u nitem: %u isdata: %c isleaf %c isdelete %c updateBlkno:%u",
((ginxlogInsert*)rec)->offset, ((ginxlogInsert *) rec)->offset,
((ginxlogInsert*)rec)->nitem, ((ginxlogInsert *) rec)->nitem,
( ((ginxlogInsert*)rec)->isData ) ? 'T' : 'F', (((ginxlogInsert *) rec)->isData) ? 'T' : 'F',
( ((ginxlogInsert*)rec)->isLeaf ) ? 'T' : 'F', (((ginxlogInsert *) rec)->isLeaf) ? 'T' : 'F',
( ((ginxlogInsert*)rec)->isDelete ) ? 'T' : 'F', (((ginxlogInsert *) rec)->isDelete) ? 'T' : 'F',
((ginxlogInsert*)rec)->updateBlkno ((ginxlogInsert *) rec)->updateBlkno
); );
break; break;
case XLOG_GIN_SPLIT: case XLOG_GIN_SPLIT:
appendStringInfo(buf,"Page split, "); appendStringInfo(buf, "Page split, ");
desc_node(buf, ((ginxlogSplit*)rec)->node, ((ginxlogSplit*)rec)->lblkno ); desc_node(buf, ((ginxlogSplit *) rec)->node, ((ginxlogSplit *) rec)->lblkno);
appendStringInfo(buf," isrootsplit: %c", ( ((ginxlogSplit*)rec)->isRootSplit ) ? 'T' : 'F'); appendStringInfo(buf, " isrootsplit: %c", (((ginxlogSplit *) rec)->isRootSplit) ? 'T' : 'F');
break; break;
case XLOG_GIN_VACUUM_PAGE: case XLOG_GIN_VACUUM_PAGE:
appendStringInfo(buf,"Vacuum page, "); appendStringInfo(buf, "Vacuum page, ");
desc_node(buf, ((ginxlogVacuumPage*)rec)->node, ((ginxlogVacuumPage*)rec)->blkno ); desc_node(buf, ((ginxlogVacuumPage *) rec)->node, ((ginxlogVacuumPage *) rec)->blkno);
break; break;
case XLOG_GIN_DELETE_PAGE: case XLOG_GIN_DELETE_PAGE:
appendStringInfo(buf,"Delete page, "); appendStringInfo(buf, "Delete page, ");
desc_node(buf, ((ginxlogDeletePage*)rec)->node, ((ginxlogDeletePage*)rec)->blkno ); desc_node(buf, ((ginxlogDeletePage *) rec)->node, ((ginxlogDeletePage *) rec)->blkno);
break; break;
default: default:
elog(PANIC, "gin_desc: unknown op code %u", info); elog(PANIC, "gin_desc: unknown op code %u", info);
@ -469,7 +516,8 @@ gin_desc(StringInfo buf, uint8 xl_info, char *rec) {
} }
void void
gin_xlog_startup(void) { gin_xlog_startup(void)
{
incomplete_splits = NIL; incomplete_splits = NIL;
opCtx = AllocSetContextCreate(CurrentMemoryContext, opCtx = AllocSetContextCreate(CurrentMemoryContext,
@ -480,31 +528,38 @@ gin_xlog_startup(void) {
} }
static void static void
ginContinueSplit( ginIncompleteSplit *split ) { ginContinueSplit(ginIncompleteSplit *split)
{
GinBtreeData btree; GinBtreeData btree;
Relation reln; Relation reln;
Buffer buffer; Buffer buffer;
GinBtreeStack stack; 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); reln = XLogOpenRelation(split->node);
buffer = XLogReadBuffer(reln, split->leftBlkno, false); 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 ); prepareEntryScan(&btree, reln, (Datum) 0, NULL);
} else { btree.entry = ginPageGetLinkItup(buffer);
Page page = BufferGetPage( buffer ); }
else
{
Page page = BufferGetPage(buffer);
prepareDataScan( &btree, reln ); prepareDataScan(&btree, reln);
PostingItemSetBlockNumber( &(btree.pitem), split->leftBlkno ); PostingItemSetBlockNumber(&(btree.pitem), split->leftBlkno);
if ( GinPageIsLeaf(page) ) if (GinPageIsLeaf(page))
btree.pitem.key = *(ItemPointerData*)GinDataPageGetItem(page, btree.pitem.key = *(ItemPointerData *) GinDataPageGetItem(page,
GinPageGetOpaque(page)->maxoff); GinPageGetOpaque(page)->maxoff);
else else
btree.pitem.key = ((PostingItem*)GinDataPageGetItem(page, btree.pitem.key = ((PostingItem *) GinDataPageGetItem(page,
GinPageGetOpaque(page)->maxoff))->key; GinPageGetOpaque(page)->maxoff))->key;
} }
@ -515,14 +570,15 @@ ginContinueSplit( ginIncompleteSplit *split ) {
stack.off = InvalidOffsetNumber; stack.off = InvalidOffsetNumber;
stack.parent = NULL; stack.parent = NULL;
findParents( &btree, &stack, split->rootBlkno); findParents(&btree, &stack, split->rootBlkno);
ginInsertValue( &btree, stack.parent ); ginInsertValue(&btree, stack.parent);
UnlockReleaseBuffer( buffer ); UnlockReleaseBuffer(buffer);
} }
void void
gin_xlog_cleanup(void) { gin_xlog_cleanup(void)
{
ListCell *l; ListCell *l;
MemoryContext topCtx; MemoryContext topCtx;
@ -531,8 +587,9 @@ gin_xlog_cleanup(void) {
foreach(l, incomplete_splits) foreach(l, incomplete_splits)
{ {
ginIncompleteSplit *split = (ginIncompleteSplit *) lfirst(l); ginIncompleteSplit *split = (ginIncompleteSplit *) lfirst(l);
ginContinueSplit( split );
MemoryContextReset( opCtx ); ginContinueSplit(split);
MemoryContextReset(opCtx);
} }
MemoryContextSwitchTo(topCtx); MemoryContextSwitchTo(topCtx);

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -185,7 +185,7 @@ gistbuildCallback(Relation index,
/* form an index tuple and point it at the heap tuple */ /* form an index tuple and point it at the heap tuple */
itup = gistFormTuple(&buildstate->giststate, index, itup = gistFormTuple(&buildstate->giststate, index,
values, isnull, true /* size is currently bogus */); values, isnull, true /* size is currently bogus */ );
itup->t_tid = htup->t_self; itup->t_tid = htup->t_self;
/* /*
@ -236,7 +236,7 @@ gistinsert(PG_FUNCTION_ARGS)
initGISTstate(&giststate, r); initGISTstate(&giststate, r);
itup = gistFormTuple(&giststate, r, itup = gistFormTuple(&giststate, r,
values, isnull, true /* size is currently bogus */); values, isnull, true /* size is currently bogus */ );
itup->t_tid = *ht_ctid; itup->t_tid = *ht_ctid;
gistdoinsert(r, itup, 0, &giststate); gistdoinsert(r, itup, 0, &giststate);
@ -285,18 +285,17 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
bool is_leaf = (GistPageIsLeaf(state->stack->page)) ? true : false; bool is_leaf = (GistPageIsLeaf(state->stack->page)) ? true : false;
/* /*
* if (!is_leaf) remove old key: * if (!is_leaf) remove old key: This node's key has been modified, either
* This node's key has been modified, either because a child split * because a child split occurred or because we needed to adjust our key
* occurred or because we needed to adjust our key for an insert in a * for an insert in a child node. Therefore, remove the old version of
* child node. Therefore, remove the old version of this node's key. * this node's key.
* *
* for WAL replay, in the non-split case we handle this by * for WAL replay, in the non-split case we handle this by setting up a
* setting up a one-element todelete array; in the split case, it's * one-element todelete array; in the split case, it's handled implicitly
* handled implicitly because the tuple vector passed to gistSplit * because the tuple vector passed to gistSplit won't include this tuple.
* won't include this tuple.
* *
* XXX: If we want to change fillfactors between node and leaf, * XXX: If we want to change fillfactors between node and leaf, fillfactor
* fillfactor = (is_leaf ? state->leaf_fillfactor : state->node_fillfactor) * = (is_leaf ? state->leaf_fillfactor : state->node_fillfactor)
*/ */
if (gistnospace(state->stack->page, state->itup, state->ituplen, if (gistnospace(state->stack->page, state->itup, state->ituplen,
is_leaf ? InvalidOffsetNumber : state->stack->childoffnum, is_leaf ? InvalidOffsetNumber : state->stack->childoffnum,
@ -313,72 +312,80 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
is_splitted = true; is_splitted = true;
/* /*
* Form index tuples vector to split: * Form index tuples vector to split: remove old tuple if t's needed
* remove old tuple if t's needed and add new tuples to vector * and add new tuples to vector
*/ */
itvec = gistextractpage(state->stack->page, &tlen); itvec = gistextractpage(state->stack->page, &tlen);
if ( !is_leaf ) { if (!is_leaf)
{
/* on inner page we should remove old tuple */ /* on inner page we should remove old tuple */
int pos = state->stack->childoffnum - FirstOffsetNumber; int pos = state->stack->childoffnum - FirstOffsetNumber;
tlen--; tlen--;
if ( pos != tlen ) if (pos != tlen)
memmove( itvec+pos, itvec + pos + 1, sizeof( IndexTuple ) * (tlen-pos) ); memmove(itvec + pos, itvec + pos + 1, sizeof(IndexTuple) * (tlen - pos));
} }
itvec = gistjoinvector(itvec, &tlen, state->itup, state->ituplen); itvec = gistjoinvector(itvec, &tlen, state->itup, state->ituplen);
dist = gistSplit(state->r, state->stack->page, itvec, tlen, giststate); dist = gistSplit(state->r, state->stack->page, itvec, tlen, giststate);
state->itup = (IndexTuple*)palloc( sizeof(IndexTuple) * tlen); state->itup = (IndexTuple *) palloc(sizeof(IndexTuple) * tlen);
state->ituplen = 0; state->ituplen = 0;
if (state->stack->blkno != GIST_ROOT_BLKNO) { 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 non-root split then we should not allocate new buffer, but
* we must create temporary page to operate
*/
dist->buffer = state->stack->buffer; dist->buffer = state->stack->buffer;
dist->page = PageGetTempPage( BufferGetPage(dist->buffer), sizeof(GISTPageOpaqueData) ); dist->page = PageGetTempPage(BufferGetPage(dist->buffer), sizeof(GISTPageOpaqueData));
/*clean all flags except F_LEAF */ /* clean all flags except F_LEAF */
GistPageGetOpaque(dist->page)->flags = (is_leaf) ? F_LEAF : 0; GistPageGetOpaque(dist->page)->flags = (is_leaf) ? F_LEAF : 0;
} }
/* make new pages and fills them */ /* make new pages and fills them */
for (ptr = dist; ptr; ptr = ptr->next) { for (ptr = dist; ptr; ptr = ptr->next)
{
int i; int i;
char *data; char *data;
/* get new page */ /* 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->buffer = gistNewBuffer(state->r);
GISTInitBuffer(ptr->buffer, (is_leaf) ? F_LEAF : 0);
ptr->page = BufferGetPage(ptr->buffer); ptr->page = BufferGetPage(ptr->buffer);
} }
ptr->block.blkno = BufferGetBlockNumber( 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
data = (char*)(ptr->list); * linked in tree or masked by temp page
for(i=0;i<ptr->block.num;i++) { */
if ( PageAddItem(ptr->page, (Item)data, IndexTupleSize((IndexTuple)data), i+FirstOffsetNumber, LP_USED) == InvalidOffsetNumber ) data = (char *) (ptr->list);
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)); elog(ERROR, "failed to add item to index page in \"%s\"", RelationGetRelationName(state->r));
data += IndexTupleSize((IndexTuple)data); data += IndexTupleSize((IndexTuple) data);
} }
/* set up ItemPointer and remmeber it for parent */ /* set up ItemPointer and remmeber it for parent */
ItemPointerSetBlockNumber(&(ptr->itup->t_tid), ptr->block.blkno); ItemPointerSetBlockNumber(&(ptr->itup->t_tid), ptr->block.blkno);
state->itup[ state->ituplen ] = ptr->itup; state->itup[state->ituplen] = ptr->itup;
state->ituplen++; state->ituplen++;
} }
/* saves old rightlink */ /* saves old rightlink */
if ( state->stack->blkno != GIST_ROOT_BLKNO ) if (state->stack->blkno != GIST_ROOT_BLKNO)
rrlink = GistPageGetOpaque(dist->page)->rightlink; rrlink = GistPageGetOpaque(dist->page)->rightlink;
START_CRIT_SECTION(); START_CRIT_SECTION();
/* /*
* must mark buffers dirty before XLogInsert, even though we'll * must mark buffers dirty before XLogInsert, even though we'll still
* still be changing their opaque fields below. * be changing their opaque fields below. set up right links.
* set up right links.
*/ */
for (ptr = dist; ptr; ptr = ptr->next) for (ptr = dist; ptr; ptr = ptr->next)
{ {
@ -388,9 +395,10 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
} }
/* restore splitted non-root page */ /* 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 ); PageRestoreTempPage(dist->page, BufferGetPage(dist->buffer));
dist->page = BufferGetPage(dist->buffer);
} }
if (!state->r->rd_istemp) if (!state->r->rd_istemp)
@ -419,25 +427,27 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
/* set up NSN */ /* set up NSN */
oldnsn = GistPageGetOpaque(dist->page)->nsn; oldnsn = GistPageGetOpaque(dist->page)->nsn;
if ( state->stack->blkno == GIST_ROOT_BLKNO ) if (state->stack->blkno == GIST_ROOT_BLKNO)
/* if root split we should put initial value */ /* if root split we should put initial value */
oldnsn = PageGetLSN(dist->page); oldnsn = PageGetLSN(dist->page);
for (ptr = dist; ptr; ptr = ptr->next) { for (ptr = dist; ptr; ptr = ptr->next)
{
/* only for last set oldnsn */ /* only for last set oldnsn */
GistPageGetOpaque(ptr->page)->nsn = (ptr->next) ? GistPageGetOpaque(ptr->page)->nsn = (ptr->next) ?
PageGetLSN(ptr->page) : oldnsn; PageGetLSN(ptr->page) : oldnsn;
} }
/* /*
* release buffers, if it was a root split then * release buffers, if it was a root split then release all buffers
* release all buffers because we create all buffers * because we create all buffers
*/ */
ptr = ( state->stack->blkno == GIST_ROOT_BLKNO ) ? dist : dist->next; ptr = (state->stack->blkno == GIST_ROOT_BLKNO) ? dist : dist->next;
for(; ptr; ptr = ptr->next) for (; ptr; ptr = ptr->next)
UnlockReleaseBuffer(ptr->buffer); 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)); gistnewroot(state->r, state->stack->buffer, state->itup, state->ituplen, &(state->key));
state->needInsertComplete = false; state->needInsertComplete = false;
} }
@ -928,8 +938,8 @@ gistSplit(Relation r,
entryvec = palloc(GEVHDRSZ + (len + 1) * sizeof(GISTENTRY)); entryvec = palloc(GEVHDRSZ + (len + 1) * sizeof(GISTENTRY));
entryvec->n = len + 1; entryvec->n = len + 1;
memset( v.spl_lisnull, TRUE, sizeof(bool) * giststate->tupdesc->natts ); memset(v.spl_lisnull, TRUE, sizeof(bool) * giststate->tupdesc->natts);
memset( v.spl_risnull, TRUE, sizeof(bool) * giststate->tupdesc->natts ); memset(v.spl_risnull, TRUE, sizeof(bool) * giststate->tupdesc->natts);
gistSplitByKey(r, page, itup, len, giststate, gistSplitByKey(r, page, itup, len, giststate,
&v, entryvec, 0); &v, entryvec, 0);
@ -952,19 +962,20 @@ gistSplit(Relation r,
{ {
ROTATEDIST(res); ROTATEDIST(res);
res->block.num = v.splitVector.spl_nright; res->block.num = v.splitVector.spl_nright;
res->list = gistfillitupvec(rvectup, v.splitVector.spl_nright, &( res->lenlist ) ); res->list = gistfillitupvec(rvectup, v.splitVector.spl_nright, &(res->lenlist));
res->itup = (v.spl_rightvalid) ? gistFormTuple(giststate, r, v.spl_rattr, v.spl_risnull, false) res->itup = (v.spl_rightvalid) ? gistFormTuple(giststate, r, v.spl_rattr, v.spl_risnull, false)
: gist_form_invalid_tuple(GIST_ROOT_BLKNO); : gist_form_invalid_tuple(GIST_ROOT_BLKNO);
} }
if (!gistfitpage(lvectup, v.splitVector.spl_nleft)) if (!gistfitpage(lvectup, v.splitVector.spl_nleft))
{ {
SplitedPageLayout *resptr, *subres; SplitedPageLayout *resptr,
*subres;
resptr = subres = gistSplit(r, page, lvectup, v.splitVector.spl_nleft, giststate); resptr = subres = gistSplit(r, page, lvectup, v.splitVector.spl_nleft, giststate);
/* install on list's tail */ /* install on list's tail */
while( resptr->next ) while (resptr->next)
resptr = resptr->next; resptr = resptr->next;
resptr->next = res; resptr->next = res;
@ -974,7 +985,7 @@ gistSplit(Relation r,
{ {
ROTATEDIST(res); ROTATEDIST(res);
res->block.num = v.splitVector.spl_nleft; res->block.num = v.splitVector.spl_nleft;
res->list = gistfillitupvec(lvectup, v.splitVector.spl_nleft, &( res->lenlist ) ); res->list = gistfillitupvec(lvectup, v.splitVector.spl_nleft, &(res->lenlist));
res->itup = (v.spl_leftvalid) ? gistFormTuple(giststate, r, v.spl_lattr, v.spl_lisnull, false) res->itup = (v.spl_leftvalid) ? gistFormTuple(giststate, r, v.spl_lattr, v.spl_lisnull, false)
: gist_form_invalid_tuple(GIST_ROOT_BLKNO); : gist_form_invalid_tuple(GIST_ROOT_BLKNO);
} }

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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(); IncrIndexProcessed();
/* /*
* Tuple doesn't restore after crash recovery because of incomplete * Tuple doesn't restore after crash recovery because of incomplete insert
* insert
*/ */
if (!GistPageIsLeaf(p) && GistTupleIsInvalid(tuple)) if (!GistPageIsLeaf(p) && GistTupleIsInvalid(tuple))
return true; return true;
@ -378,14 +377,18 @@ gistindex_keytest(IndexTuple tuple,
giststate->tupdesc, giststate->tupdesc,
&isNull); &isNull);
if ( key->sk_flags & SK_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 :( */ /*
* is the compared-to datum NULL? on non-leaf page it's possible
* to have nulls in childs :(
*/
if ( isNull || !GistPageIsLeaf(p) ) if (isNull || !GistPageIsLeaf(p))
return true; return true;
return false; return false;
} else if ( isNull ) }
else if (isNull)
return false; return false;
gistdentryinit(giststate, key->sk_attno - 1, &de, gistdentryinit(giststate, key->sk_attno - 1, &de,

View File

@ -10,7 +10,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 static void
adjustBox( BOX *b, BOX *addon ) { adjustBox(BOX *b, BOX *addon)
{
if (b->high.x < addon->high.x) if (b->high.x < addon->high.x)
b->high.x = addon->high.x; b->high.x = addon->high.x;
if (b->low.x > addon->low.x) if (b->low.x > addon->low.x)
@ -146,7 +147,7 @@ gist_box_union(PG_FUNCTION_ARGS)
for (i = 1; i < numranges; i++) for (i = 1; i < numranges; i++)
{ {
cur = DatumGetBoxP(entryvec->vector[i].key); cur = DatumGetBoxP(entryvec->vector[i].key);
adjustBox( pageunion, cur ); adjustBox(pageunion, cur);
} }
*sizep = sizeof(BOX); *sizep = sizeof(BOX);
@ -210,34 +211,43 @@ compare_KB(const void *a, const void *b)
} }
static void static void
chooseLR( GIST_SPLITVEC *v, chooseLR(GIST_SPLITVEC *v,
OffsetNumber *list1, int nlist1, BOX *union1, OffsetNumber *list1, int nlist1, BOX *union1,
OffsetNumber *list2, int nlist2, BOX *union2 ) OffsetNumber *list2, int nlist2, BOX *union2)
{ {
bool firstToLeft = true; bool firstToLeft = true;
if ( v->spl_ldatum_exists || v->spl_rdatum_exists ) { if (v->spl_ldatum_exists || v->spl_rdatum_exists)
if ( v->spl_ldatum_exists && v->spl_rdatum_exists ) { {
BOX LRl = *union1, LRr = *union2; if (v->spl_ldatum_exists && v->spl_rdatum_exists)
BOX RLl = *union2, RLr = *union1; {
double sizeLR, sizeRL; BOX LRl = *union1,
LRr = *union2;
BOX RLl = *union2,
RLr = *union1;
double sizeLR,
sizeRL;
adjustBox( &LRl, DatumGetBoxP( v->spl_ldatum ) ); adjustBox(&LRl, DatumGetBoxP(v->spl_ldatum));
adjustBox( &LRr, DatumGetBoxP( v->spl_rdatum ) ); adjustBox(&LRr, DatumGetBoxP(v->spl_rdatum));
adjustBox( &RLl, DatumGetBoxP( v->spl_ldatum ) ); adjustBox(&RLl, DatumGetBoxP(v->spl_ldatum));
adjustBox( &RLr, DatumGetBoxP( v->spl_rdatum ) ); adjustBox(&RLr, DatumGetBoxP(v->spl_rdatum));
sizeLR = size_box( DirectFunctionCall2(rt_box_inter, BoxPGetDatum(&LRl), BoxPGetDatum(&LRr)) ); sizeLR = size_box(DirectFunctionCall2(rt_box_inter, BoxPGetDatum(&LRl), BoxPGetDatum(&LRr)));
sizeRL = size_box( DirectFunctionCall2(rt_box_inter, BoxPGetDatum(&RLl), BoxPGetDatum(&RLr)) ); sizeRL = size_box(DirectFunctionCall2(rt_box_inter, BoxPGetDatum(&RLl), BoxPGetDatum(&RLr)));
if ( sizeLR > sizeRL ) if (sizeLR > sizeRL)
firstToLeft = false; firstToLeft = false;
} else { }
float p1, p2; else
GISTENTRY oldUnion, addon; {
float p1,
p2;
GISTENTRY oldUnion,
addon;
gistentryinit(oldUnion, ( v->spl_ldatum_exists ) ? v->spl_ldatum : v->spl_rdatum, gistentryinit(oldUnion, (v->spl_ldatum_exists) ? v->spl_ldatum : v->spl_rdatum,
NULL, NULL, InvalidOffsetNumber, FALSE); NULL, NULL, InvalidOffsetNumber, FALSE);
gistentryinit(addon, BoxPGetDatum(union1), NULL, NULL, InvalidOffsetNumber, FALSE); gistentryinit(addon, BoxPGetDatum(union1), NULL, NULL, InvalidOffsetNumber, FALSE);
@ -245,32 +255,35 @@ chooseLR( GIST_SPLITVEC *v,
gistentryinit(addon, BoxPGetDatum(union2), NULL, NULL, InvalidOffsetNumber, FALSE); gistentryinit(addon, BoxPGetDatum(union2), NULL, NULL, InvalidOffsetNumber, FALSE);
DirectFunctionCall3(gist_box_penalty, PointerGetDatum(&oldUnion), PointerGetDatum(&union2), PointerGetDatum(&p2)); DirectFunctionCall3(gist_box_penalty, PointerGetDatum(&oldUnion), PointerGetDatum(&union2), PointerGetDatum(&p2));
if ( (v->spl_ldatum_exists && p1 > p2) || (v->spl_rdatum_exists && p1 < p2) ) if ((v->spl_ldatum_exists && p1 > p2) || (v->spl_rdatum_exists && p1 < p2))
firstToLeft = false; firstToLeft = false;
} }
} }
if ( firstToLeft ) { if (firstToLeft)
{
v->spl_left = list1; v->spl_left = list1;
v->spl_right = list2; v->spl_right = list2;
v->spl_nleft = nlist1; v->spl_nleft = nlist1;
v->spl_nright = nlist2; v->spl_nright = nlist2;
if ( v->spl_ldatum_exists ) if (v->spl_ldatum_exists)
adjustBox(union1, DatumGetBoxP( v->spl_ldatum ) ); adjustBox(union1, DatumGetBoxP(v->spl_ldatum));
v->spl_ldatum = BoxPGetDatum(union1); v->spl_ldatum = BoxPGetDatum(union1);
if ( v->spl_rdatum_exists ) if (v->spl_rdatum_exists)
adjustBox(union2, DatumGetBoxP( v->spl_rdatum ) ); adjustBox(union2, DatumGetBoxP(v->spl_rdatum));
v->spl_rdatum = BoxPGetDatum(union2); v->spl_rdatum = BoxPGetDatum(union2);
} else { }
else
{
v->spl_left = list2; v->spl_left = list2;
v->spl_right = list1; v->spl_right = list1;
v->spl_nleft = nlist2; v->spl_nleft = nlist2;
v->spl_nright = nlist1; v->spl_nright = nlist1;
if ( v->spl_ldatum_exists ) if (v->spl_ldatum_exists)
adjustBox(union2, DatumGetBoxP( v->spl_ldatum ) ); adjustBox(union2, DatumGetBoxP(v->spl_ldatum));
v->spl_ldatum = BoxPGetDatum(union2); v->spl_ldatum = BoxPGetDatum(union2);
if ( v->spl_rdatum_exists ) if (v->spl_rdatum_exists)
adjustBox(union1, DatumGetBoxP( v->spl_rdatum ) ); adjustBox(union1, DatumGetBoxP(v->spl_rdatum));
v->spl_rdatum = BoxPGetDatum(union1); v->spl_rdatum = BoxPGetDatum(union1);
} }
@ -326,7 +339,7 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
)) ))
allisequal = false; allisequal = false;
adjustBox( &pageunion, cur ); adjustBox(&pageunion, cur);
} }
nbytes = (maxoff + 2) * sizeof(OffsetNumber); nbytes = (maxoff + 2) * sizeof(OffsetNumber);
@ -359,12 +372,12 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
} }
} }
if ( v->spl_ldatum_exists ) if (v->spl_ldatum_exists)
adjustBox( unionL, DatumGetBoxP( v->spl_ldatum ) ); adjustBox(unionL, DatumGetBoxP(v->spl_ldatum));
v->spl_ldatum = BoxPGetDatum(unionL); v->spl_ldatum = BoxPGetDatum(unionL);
if ( v->spl_rdatum_exists ) if (v->spl_rdatum_exists)
adjustBox( unionR, DatumGetBoxP( v->spl_rdatum ) ); adjustBox(unionR, DatumGetBoxP(v->spl_rdatum));
v->spl_rdatum = BoxPGetDatum(unionR); v->spl_rdatum = BoxPGetDatum(unionR);
v->spl_ldatum_exists = v->spl_rdatum_exists = false; v->spl_ldatum_exists = v->spl_rdatum_exists = false;
@ -471,13 +484,13 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
} }
if (direction == 'x') if (direction == 'x')
chooseLR( v, chooseLR(v,
listL, posL, unionL, listL, posL, unionL,
listR, posR, unionR ); listR, posR, unionR);
else else
chooseLR( v, chooseLR(v,
listB, posB, unionB, listB, posB, unionB,
listT, posT, unionT ); listT, posT, unionT);
PG_RETURN_POINTER(v); PG_RETURN_POINTER(v);
} }

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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) while (s != NULL)
{ {
GISTSearchStack *p = s->next; GISTSearchStack *p = s->next;
pfree(s); pfree(s);
s = p; s = p;
} }
} }

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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" #include "access/gist_private.h"
typedef struct { typedef struct
{
Datum *attr; Datum *attr;
int len; int len;
OffsetNumber *entries; OffsetNumber *entries;
@ -31,14 +32,17 @@ typedef struct {
*/ */
static void static void
gistunionsubkeyvec(GISTSTATE *giststate, IndexTuple *itvec, gistunionsubkeyvec(GISTSTATE *giststate, IndexTuple *itvec,
GistSplitUnion *gsvp, int startkey) { GistSplitUnion *gsvp, int startkey)
{
IndexTuple *cleanedItVec; IndexTuple *cleanedItVec;
int i, cleanedLen=0; int i,
cleanedLen = 0;
cleanedItVec = (IndexTuple*)palloc(sizeof(IndexTuple) * gsvp->len); 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]]) {
if (gsvp->equiv && gsvp->equiv[gsvp->entries[i]])
continue; continue;
cleanedItVec[cleanedLen++] = itvec[gsvp->entries[i] - 1]; cleanedItVec[cleanedLen++] = itvec[gsvp->entries[i] - 1];
@ -47,7 +51,7 @@ gistunionsubkeyvec(GISTSTATE *giststate, IndexTuple *itvec,
gistMakeUnionItVec(giststate, cleanedItVec, cleanedLen, startkey, gistMakeUnionItVec(giststate, cleanedItVec, cleanedLen, startkey,
gsvp->attr, gsvp->isnull); gsvp->attr, gsvp->isnull);
pfree( cleanedItVec ); pfree(cleanedItVec);
} }
/* /*
@ -83,27 +87,33 @@ gistfindgroup(Relation r, GISTSTATE *giststate, GISTENTRY *valvec, GistSplitVect
{ {
int i; int i;
GISTENTRY entry; GISTENTRY entry;
int len=0; int len = 0;
/* /*
* attno key is always not null (see gistSplitByKey), so we may not check for * attno key is always not null (see gistSplitByKey), so we may not check
* nulls * for nulls
*/ */
gistentryinit(entry, spl->splitVector.spl_rdatum, r, NULL, (OffsetNumber) 0, FALSE); 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, float penalty = gistpenalty(giststate, attno, &entry, false,
&valvec[spl->splitVector.spl_left[i]], 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; spl->spl_equiv[spl->splitVector.spl_left[i]] = true;
len++; len++;
} }
} }
gistentryinit(entry, spl->splitVector.spl_ldatum, r, NULL, (OffsetNumber) 0, FALSE); 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, float penalty = gistpenalty(giststate, attno, &entry, false,
&valvec[spl->splitVector.spl_right[i]], 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; spl->spl_equiv[spl->splitVector.spl_right[i]] = true;
len++; len++;
} }
@ -113,24 +123,32 @@ gistfindgroup(Relation r, GISTSTATE *giststate, GISTENTRY *valvec, GistSplitVect
} }
static void static void
cleanupOffsets( OffsetNumber *a, int *len, bool *equiv, int *LenEquiv ) { cleanupOffsets(OffsetNumber *a, int *len, bool *equiv, int *LenEquiv)
int curlen,i; {
int curlen,
i;
OffsetNumber *curwpos; OffsetNumber *curwpos;
curlen = *len; curlen = *len;
curwpos = a; curwpos = a;
for (i = 0; i < *len; i++) { for (i = 0; i < *len; i++)
if ( equiv[ a[i] ] == FALSE ) { {
if (equiv[a[i]] == FALSE)
{
*curwpos = a[i]; *curwpos = a[i];
curwpos++; curwpos++;
} else { }
else
{
/* corner case: we shouldn't make void array */ /* corner case: we shouldn't make void array */
if ( curlen==1 ) { if (curlen == 1)
equiv[ a[i] ] = FALSE; /* mark item as non-equivalent */ {
equiv[a[i]] = FALSE; /* mark item as non-equivalent */
i--; /* redo the same */ i--; /* redo the same */
*LenEquiv -= 1; *LenEquiv -= 1;
continue; continue;
} else }
else
curlen--; curlen--;
} }
} }
@ -139,33 +157,37 @@ cleanupOffsets( OffsetNumber *a, int *len, bool *equiv, int *LenEquiv ) {
} }
static void 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]; GISTENTRY identry[INDEX_MAX_KEYS];
bool isnull[INDEX_MAX_KEYS]; bool isnull[INDEX_MAX_KEYS];
bool toLeft = true; bool toLeft = true;
gistDeCompressAtt(giststate, r, itup, NULL, (OffsetNumber) 0, identry, isnull); gistDeCompressAtt(giststate, r, itup, NULL, (OffsetNumber) 0, identry, isnull);
for(;attno<giststate->tupdesc->natts;attno++) { for (; attno < giststate->tupdesc->natts; attno++)
float lpenalty, rpenalty; {
float lpenalty,
rpenalty;
GISTENTRY entry; GISTENTRY entry;
gistentryinit(entry, v->spl_lattr[attno], r, NULL, 0, FALSE); gistentryinit(entry, v->spl_lattr[attno], r, NULL, 0, FALSE);
lpenalty = gistpenalty(giststate, attno, &entry, v->spl_lisnull[attno], identry+attno, isnull[ attno ]); lpenalty = gistpenalty(giststate, attno, &entry, v->spl_lisnull[attno], identry + attno, isnull[attno]);
gistentryinit(entry, v->spl_rattr[attno], r, NULL, 0, FALSE); gistentryinit(entry, v->spl_rattr[attno], r, NULL, 0, FALSE);
rpenalty = gistpenalty(giststate, attno, &entry, v->spl_risnull[attno], identry+attno, isnull[ attno ]); rpenalty = gistpenalty(giststate, attno, &entry, v->spl_risnull[attno], identry + attno, isnull[attno]);
if ( lpenalty != rpenalty ) { if (lpenalty != rpenalty)
if ( lpenalty > rpenalty ) {
if (lpenalty > rpenalty)
toLeft = false; toLeft = false;
break; break;
} }
} }
if ( toLeft ) if (toLeft)
v->splitVector.spl_left[ v->splitVector.spl_nleft++ ] = off; v->splitVector.spl_left[v->splitVector.spl_nleft++] = off;
else else
v->splitVector.spl_right[ v->splitVector.spl_nright++ ] = off; v->splitVector.spl_right[v->splitVector.spl_nright++] = off;
} }
#define SWAPVAR( s, d, t ) \ #define SWAPVAR( s, d, t ) \
@ -182,63 +204,75 @@ do { \
*/ */
static void static void
supportSecondarySplit( Relation r, GISTSTATE *giststate, int attno, GIST_SPLITVEC *sv, Datum oldL, Datum oldR ) { supportSecondarySplit(Relation r, GISTSTATE *giststate, int attno, GIST_SPLITVEC *sv, Datum oldL, Datum oldR)
bool leaveOnLeft = true, tmpBool; {
GISTENTRY entryL, entryR, entrySL, entrySR; bool leaveOnLeft = true,
tmpBool;
GISTENTRY entryL,
entryR,
entrySL,
entrySR;
gistentryinit(entryL, oldL, r, NULL, 0, FALSE); gistentryinit(entryL, oldL, r, NULL, 0, FALSE);
gistentryinit(entryR, oldR, r, NULL, 0, FALSE); gistentryinit(entryR, oldR, r, NULL, 0, FALSE);
gistentryinit(entrySL, sv->spl_ldatum , r, NULL, 0, FALSE); gistentryinit(entrySL, sv->spl_ldatum, r, NULL, 0, FALSE);
gistentryinit(entrySR, sv->spl_rdatum , r, NULL, 0, FALSE); gistentryinit(entrySR, sv->spl_rdatum, r, NULL, 0, FALSE);
if ( sv->spl_ldatum_exists && sv->spl_rdatum_exists ) { if (sv->spl_ldatum_exists && sv->spl_rdatum_exists)
float penalty1, penalty2; {
float penalty1,
penalty2;
penalty1 = gistpenalty(giststate, attno, &entryL, false, &entrySL, false) + penalty1 = gistpenalty(giststate, attno, &entryL, false, &entrySL, false) +
gistpenalty(giststate, attno, &entryR, false, &entrySR, false); gistpenalty(giststate, attno, &entryR, false, &entrySR, false);
penalty2 = gistpenalty(giststate, attno, &entryL, false, &entrySR, false) + penalty2 = gistpenalty(giststate, attno, &entryL, false, &entrySR, false) +
gistpenalty(giststate, attno, &entryR, false, &entrySL, false); gistpenalty(giststate, attno, &entryR, false, &entrySL, false);
if ( penalty1 > penalty2 ) if (penalty1 > penalty2)
leaveOnLeft = false; leaveOnLeft = false;
} else { }
else
{
GISTENTRY *entry1 = (sv->spl_ldatum_exists) ? &entryL : &entryR; GISTENTRY *entry1 = (sv->spl_ldatum_exists) ? &entryL : &entryR;
float penalty1, penalty2; float penalty1,
penalty2;
/* /*
* there is only one previously defined union, * there is only one previously defined union, so we just choose swap
* so we just choose swap or not by lowest penalty * or not by lowest penalty
*/ */
penalty1 = gistpenalty(giststate, attno, entry1, false, &entrySL, false); penalty1 = gistpenalty(giststate, attno, entry1, false, &entrySL, false);
penalty2 = gistpenalty(giststate, attno, entry1, false, &entrySR, false); penalty2 = gistpenalty(giststate, attno, entry1, false, &entrySR, false);
if ( penalty1 < penalty2 ) if (penalty1 < penalty2)
leaveOnLeft = ( sv->spl_ldatum_exists ) ? true : false; leaveOnLeft = (sv->spl_ldatum_exists) ? true : false;
else else
leaveOnLeft = ( sv->spl_rdatum_exists ) ? true : false; leaveOnLeft = (sv->spl_rdatum_exists) ? true : false;
} }
if ( leaveOnLeft == false ) { if (leaveOnLeft == false)
{
/* /*
* swap left and right * swap left and right
*/ */
OffsetNumber *off, noff; OffsetNumber *off,
noff;
Datum datum; Datum datum;
SWAPVAR( sv->spl_left, sv->spl_right, off ); SWAPVAR(sv->spl_left, sv->spl_right, off);
SWAPVAR( sv->spl_nleft, sv->spl_nright, noff ); SWAPVAR(sv->spl_nleft, sv->spl_nright, noff);
SWAPVAR( sv->spl_ldatum, sv->spl_rdatum, datum ); SWAPVAR(sv->spl_ldatum, sv->spl_rdatum, datum);
gistentryinit(entrySL, sv->spl_ldatum , r, NULL, 0, FALSE); gistentryinit(entrySL, sv->spl_ldatum, r, NULL, 0, FALSE);
gistentryinit(entrySR, sv->spl_rdatum , r, NULL, 0, FALSE); gistentryinit(entrySR, sv->spl_rdatum, r, NULL, 0, FALSE);
} }
if ( sv->spl_ldatum_exists ) if (sv->spl_ldatum_exists)
gistMakeUnionKey(giststate, attno, &entryL, false, &entrySL, false, gistMakeUnionKey(giststate, attno, &entryL, false, &entrySL, false,
&sv->spl_ldatum, &tmpBool); &sv->spl_ldatum, &tmpBool);
if ( sv->spl_rdatum_exists ) if (sv->spl_rdatum_exists)
gistMakeUnionKey(giststate, attno, &entryR, false, &entrySR, false, gistMakeUnionKey(giststate, attno, &entryR, false, &entrySR, false,
&sv->spl_rdatum, &tmpBool); &sv->spl_rdatum, &tmpBool);
@ -258,13 +292,14 @@ gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVec
IndexTuple *itup, int len, GISTSTATE *giststate) IndexTuple *itup, int len, GISTSTATE *giststate)
{ {
GIST_SPLITVEC *sv = &v->splitVector; GIST_SPLITVEC *sv = &v->splitVector;
/* /*
* now let the user-defined picksplit function set up the split vector; in * now let the user-defined picksplit function set up the split vector; in
* entryvec have no null value!! * entryvec have no null value!!
*/ */
sv->spl_ldatum_exists = ( v->spl_lisnull[ attno ] ) ? false : true; sv->spl_ldatum_exists = (v->spl_lisnull[attno]) ? false : true;
sv->spl_rdatum_exists = ( v->spl_risnull[ attno ] ) ? false : true; sv->spl_rdatum_exists = (v->spl_risnull[attno]) ? false : true;
sv->spl_ldatum = v->spl_lattr[attno]; sv->spl_ldatum = v->spl_lattr[attno];
sv->spl_rdatum = v->spl_rattr[attno]; sv->spl_rdatum = v->spl_rattr[attno];
@ -278,11 +313,12 @@ gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVec
if (sv->spl_right[sv->spl_nright - 1] == InvalidOffsetNumber) if (sv->spl_right[sv->spl_nright - 1] == InvalidOffsetNumber)
sv->spl_right[sv->spl_nright - 1] = (OffsetNumber) (entryvec->n - 1); 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) ); elog(LOG, "PickSplit method of %d columns of index '%s' doesn't support secondary split",
attno + 1, RelationGetRelationName(r));
supportSecondarySplit( r, giststate, attno, sv, v->spl_lattr[attno], v->spl_rattr[attno] ); supportSecondarySplit(r, giststate, attno, sv, v->spl_lattr[attno], v->spl_rattr[attno]);
} }
v->spl_lattr[attno] = sv->spl_ldatum; v->spl_lattr[attno] = sv->spl_ldatum;
@ -296,53 +332,64 @@ gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVec
*/ */
v->spl_equiv = NULL; v->spl_equiv = NULL;
if (giststate->tupdesc->natts > 1 && attno+1 != giststate->tupdesc->natts) 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 * Left and right key's unions are equial, so we can get better
* we can get better split by following columns. Note, * split by following columns. Note, unions for attno columns are
* unions for attno columns are already done. * already done.
*/ */
return true; return true;
} else { }
else
{
int LenEquiv; int LenEquiv;
v->spl_equiv = (bool *) palloc0(sizeof(bool) * (entryvec->n+1)); v->spl_equiv = (bool *) palloc0(sizeof(bool) * (entryvec->n + 1));
LenEquiv = gistfindgroup(r, giststate, entryvec->vector, v, attno); LenEquiv = gistfindgroup(r, giststate, entryvec->vector, v, attno);
/* /*
* if possible, we should distribute equivalent tuples * if possible, we should distribute equivalent tuples
*/ */
if (LenEquiv == 0 ) { if (LenEquiv == 0)
{
gistunionsubkey(giststate, itup, v, attno + 1); gistunionsubkey(giststate, itup, v, attno + 1);
} else { }
cleanupOffsets( sv->spl_left, &sv->spl_nleft, v->spl_equiv, &LenEquiv ); else
cleanupOffsets( sv->spl_right, &sv->spl_nright, v->spl_equiv, &LenEquiv ); {
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); gistunionsubkey(giststate, itup, v, attno + 1);
if (LenEquiv == 1 ) { if (LenEquiv == 1)
{
/* /*
* In case with one tuple we just choose left-right * In case with one tuple we just choose left-right by
* by penalty. It's simplify user-defined pickSplit * penalty. It's simplify user-defined pickSplit
*/ */
OffsetNumber toMove = InvalidOffsetNumber; OffsetNumber toMove = InvalidOffsetNumber;
for(toMove=FirstOffsetNumber;toMove<entryvec->n;toMove++) for (toMove = FirstOffsetNumber; toMove < entryvec->n; toMove++)
if ( v->spl_equiv[ toMove ] ) if (v->spl_equiv[toMove])
break; break;
Assert( toMove < entryvec->n ); Assert(toMove < entryvec->n);
placeOne( r, giststate, v, itup[ toMove-1 ], toMove, attno+1 ); 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; v->spl_equiv = NULL;
gistunionsubkey(giststate, itup, v, attno + 1); gistunionsubkey(giststate, itup, v, attno + 1);
return false; return false;
} else if ( LenEquiv > 1 ) }
else if (LenEquiv > 1)
return true; return true;
} }
} }
@ -355,17 +402,18 @@ gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVec
* simple split page * simple split page
*/ */
static void static void
gistSplitHalf(GIST_SPLITVEC *v, int len) { gistSplitHalf(GIST_SPLITVEC *v, int len)
{
int i; int i;
v->spl_nright = v->spl_nleft = 0; v->spl_nright = v->spl_nleft = 0;
v->spl_left = (OffsetNumber *) palloc(len * sizeof(OffsetNumber)); v->spl_left = (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
v->spl_right= (OffsetNumber *) palloc(len * sizeof(OffsetNumber)); v->spl_right = (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
for(i = 1; i <= len; i++) for (i = 1; i <= len; i++)
if ( i<len/2 ) if (i < len / 2)
v->spl_right[ v->spl_nright++ ] = i; v->spl_right[v->spl_nright++] = i;
else else
v->spl_left[ v->spl_nleft++ ] = i; v->spl_left[v->spl_nleft++] = i;
} }
/* /*
@ -379,20 +427,24 @@ gistSplitHalf(GIST_SPLITVEC *v, int len) {
* to get 'invalid' tuples (probability is low enough) * to get 'invalid' tuples (probability is low enough)
*/ */
static void static void
gistSplitByInvalid(GISTSTATE *giststate, GistSplitVector *v, IndexTuple *itup, int len) { gistSplitByInvalid(GISTSTATE *giststate, GistSplitVector *v, IndexTuple *itup, int len)
{
int i; int i;
static OffsetNumber offInvTuples[ MaxOffsetNumber ]; static OffsetNumber offInvTuples[MaxOffsetNumber];
int nOffInvTuples = 0; int nOffInvTuples = 0;
for (i = 1; i <= len; i++) for (i = 1; i <= len; i++)
if ( GistTupleIsInvalid(itup[i - 1]) ) if (GistTupleIsInvalid(itup[i - 1]))
offInvTuples[ nOffInvTuples++ ] = i; offInvTuples[nOffInvTuples++] = i;
if ( nOffInvTuples == len ) { if (nOffInvTuples == len)
{
/* corner case, all tuples are invalid */ /* corner case, all tuples are invalid */
v->spl_rightvalid= v->spl_leftvalid = false; v->spl_rightvalid = v->spl_leftvalid = false;
gistSplitHalf( &v->splitVector, len ); gistSplitHalf(&v->splitVector, len);
} else { }
else
{
GistSplitUnion gsvp; GistSplitUnion gsvp;
v->splitVector.spl_right = offInvTuples; v->splitVector.spl_right = offInvTuples;
@ -401,9 +453,9 @@ gistSplitByInvalid(GISTSTATE *giststate, GistSplitVector *v, IndexTuple *itup, i
v->splitVector.spl_left = (OffsetNumber *) palloc(len * sizeof(OffsetNumber)); v->splitVector.spl_left = (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
v->splitVector.spl_nleft = 0; v->splitVector.spl_nleft = 0;
for(i = 1; i <= len; i++) for (i = 1; i <= len; i++)
if ( !GistTupleIsInvalid(itup[i - 1]) ) if (!GistTupleIsInvalid(itup[i - 1]))
v->splitVector.spl_left[ v->splitVector.spl_nleft++ ] = i; v->splitVector.spl_left[v->splitVector.spl_nleft++] = i;
v->spl_leftvalid = true; v->spl_leftvalid = true;
gsvp.equiv = NULL; gsvp.equiv = NULL;
@ -422,48 +474,54 @@ gistSplitByInvalid(GISTSTATE *giststate, GistSplitVector *v, IndexTuple *itup, i
*/ */
void void
gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *giststate, 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; int i;
static OffsetNumber offNullTuples[ MaxOffsetNumber ]; static OffsetNumber offNullTuples[MaxOffsetNumber];
int nOffNullTuples = 0; int nOffNullTuples = 0;
for (i = 1; i <= len; i++) { for (i = 1; i <= len; i++)
{
Datum datum; Datum datum;
bool IsNull; bool IsNull;
if (!GistPageIsLeaf(page) && GistTupleIsInvalid(itup[i - 1])) { if (!GistPageIsLeaf(page) && GistTupleIsInvalid(itup[i - 1]))
{
gistSplitByInvalid(giststate, v, itup, len); gistSplitByInvalid(giststate, v, itup, len);
return; return;
} }
datum = index_getattr(itup[i - 1], attno+1, giststate->tupdesc, &IsNull); datum = index_getattr(itup[i - 1], attno + 1, giststate->tupdesc, &IsNull);
gistdentryinit(giststate, attno, &(entryvec->vector[i]), gistdentryinit(giststate, attno, &(entryvec->vector[i]),
datum, r, page, i, datum, r, page, i,
FALSE, IsNull); FALSE, IsNull);
if ( IsNull ) if (IsNull)
offNullTuples[ nOffNullTuples++ ] = i; offNullTuples[nOffNullTuples++] = i;
} }
v->spl_leftvalid = v->spl_rightvalid = true; 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 * 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 * split by keys in next column. It all keys in all columns are NULL
* are NULL just split page half by half * just split page half by half
*/ */
v->spl_risnull[attno] = v->spl_lisnull[attno] = TRUE; v->spl_risnull[attno] = v->spl_lisnull[attno] = TRUE;
if ( attno+1 == r->rd_att->natts ) if (attno + 1 == r->rd_att->natts)
gistSplitHalf( &v->splitVector, len ); gistSplitHalf(&v->splitVector, len);
else else
gistSplitByKey(r, page, itup, len, giststate, v, entryvec, attno+1); gistSplitByKey(r, page, itup, len, giststate, v, entryvec, attno + 1);
} else if ( nOffNullTuples > 0 ) { }
int j=0; else if (nOffNullTuples > 0)
{
int j = 0;
/* /*
* We don't want to mix NULLs and not-NULLs keys * We don't want to mix NULLs and not-NULLs keys on one page, so move
* on one page, so move nulls to right page * nulls to right page
*/ */
v->splitVector.spl_right = offNullTuples; v->splitVector.spl_right = offNullTuples;
v->splitVector.spl_nright = nOffNullTuples; v->splitVector.spl_nright = nOffNullTuples;
@ -471,56 +529,66 @@ gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *gist
v->splitVector.spl_left = (OffsetNumber *) palloc(len * sizeof(OffsetNumber)); v->splitVector.spl_left = (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
v->splitVector.spl_nleft = 0; v->splitVector.spl_nleft = 0;
for(i = 1; i <= len; i++) for (i = 1; i <= len; i++)
if ( j<v->splitVector.spl_nright && offNullTuples[j] == i ) if (j < v->splitVector.spl_nright && offNullTuples[j] == i)
j++; j++;
else else
v->splitVector.spl_left[ v->splitVector.spl_nleft++ ] = i; v->splitVector.spl_left[v->splitVector.spl_nleft++] = i;
v->spl_equiv = NULL; v->spl_equiv = NULL;
gistunionsubkey(giststate, itup, v, attno); gistunionsubkey(giststate, itup, v, attno);
} else { }
else
{
/* /*
* all keys are not-null * all keys are not-null
*/ */
entryvec->n = len+1; 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 * Splitting on attno column is not optimized: there is a tuples
* left or right page, we will try to split page by * which can be freely left or right page, we will try to split
* following columns * page by following columns
*/ */
if ( v->spl_equiv == NULL ) { 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 { * simple case: left and right keys for attno column are
* equial
*/
gistSplitByKey(r, page, itup, len, giststate, v, entryvec, attno + 1);
}
else
{
/* we should clean up vector from already distributed tuples */ /* we should clean up vector from already distributed tuples */
IndexTuple *newitup = (IndexTuple*)palloc((len + 1) * sizeof(IndexTuple)); IndexTuple *newitup = (IndexTuple *) palloc((len + 1) * sizeof(IndexTuple));
OffsetNumber *map = (OffsetNumber*)palloc((len + 1) * sizeof(IndexTuple)); OffsetNumber *map = (OffsetNumber *) palloc((len + 1) * sizeof(IndexTuple));
int newlen = 0; int newlen = 0;
GIST_SPLITVEC backupSplit = v->splitVector; GIST_SPLITVEC backupSplit = v->splitVector;
for(i=0; i<len; i++) 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]; map[newlen] = i + 1;
newitup[newlen++] = itup[i];
} }
Assert( newlen>0 ); Assert(newlen > 0);
backupSplit.spl_left = (OffsetNumber*)palloc(sizeof(OffsetNumber)*len); backupSplit.spl_left = (OffsetNumber *) palloc(sizeof(OffsetNumber) * len);
memcpy( backupSplit.spl_left, v->splitVector.spl_left, sizeof(OffsetNumber)*v->splitVector.spl_nleft); memcpy(backupSplit.spl_left, v->splitVector.spl_left, sizeof(OffsetNumber) * v->splitVector.spl_nleft);
backupSplit.spl_right = (OffsetNumber*)palloc(sizeof(OffsetNumber)*len); backupSplit.spl_right = (OffsetNumber *) palloc(sizeof(OffsetNumber) * len);
memcpy( backupSplit.spl_right, v->splitVector.spl_right, sizeof(OffsetNumber)*v->splitVector.spl_nright); memcpy(backupSplit.spl_right, v->splitVector.spl_right, sizeof(OffsetNumber) * v->splitVector.spl_nright);
gistSplitByKey(r, page, newitup, newlen, giststate, v, entryvec, attno+1); gistSplitByKey(r, page, newitup, newlen, giststate, v, entryvec, attno + 1);
/* merge result of subsplit */ /* merge result of subsplit */
for(i=0;i<v->splitVector.spl_nleft;i++) for (i = 0; i < v->splitVector.spl_nleft; i++)
backupSplit.spl_left[ backupSplit.spl_nleft++ ] = map[ v->splitVector.spl_left[i]-1 ]; backupSplit.spl_left[backupSplit.spl_nleft++] = map[v->splitVector.spl_left[i] - 1];
for(i=0;i<v->splitVector.spl_nright;i++) for (i = 0; i < v->splitVector.spl_nright; i++)
backupSplit.spl_right[ backupSplit.spl_nright++ ] = map[ v->splitVector.spl_right[i]-1 ]; backupSplit.spl_right[backupSplit.spl_nright++] = map[v->splitVector.spl_right[i] - 1];
v->splitVector = backupSplit; v->splitVector = backupSplit;
/* reunion left and right datums */ /* reunion left and right datums */

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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" #include "postgres.h"
@ -57,14 +57,17 @@ gistfillbuffer(Relation r, Page page, IndexTuple *itup,
bool bool
gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace) 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; int i;
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
size += IndexTupleSize(itvec[i]) + sizeof(ItemIdData); size += IndexTupleSize(itvec[i]) + sizeof(ItemIdData);
if ( todelete != InvalidOffsetNumber ) { if (todelete != InvalidOffsetNumber)
{
IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, todelete)); IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, todelete));
deleted = IndexTupleSize(itup) + sizeof(ItemIdData); deleted = IndexTupleSize(itup) + sizeof(ItemIdData);
} }
@ -72,11 +75,12 @@ gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size f
} }
bool bool
gistfitpage(IndexTuple *itvec, int len) { gistfitpage(IndexTuple *itvec, int len)
{
int i; int i;
Size size=0; Size size = 0;
for(i=0;i<len;i++) for (i = 0; i < len; i++)
size += IndexTupleSize(itvec[i]) + sizeof(ItemIdData); size += IndexTupleSize(itvec[i]) + sizeof(ItemIdData);
/* TODO: Consider fillfactor */ /* TODO: Consider fillfactor */
@ -119,23 +123,26 @@ gistjoinvector(IndexTuple *itvec, int *len, IndexTuple *additvec, int addlen)
*/ */
IndexTupleData * IndexTupleData *
gistfillitupvec(IndexTuple *vec, int veclen, int *memlen) { gistfillitupvec(IndexTuple *vec, int veclen, int *memlen)
char *ptr, *ret; {
char *ptr,
*ret;
int i; int i;
*memlen=0; *memlen = 0;
for (i = 0; i < veclen; i++) for (i = 0; i < veclen; i++)
*memlen += IndexTupleSize(vec[i]); *memlen += IndexTupleSize(vec[i]);
ptr = ret = palloc(*memlen); ptr = ret = palloc(*memlen);
for (i = 0; i < veclen; i++) { for (i = 0; i < veclen; i++)
{
memcpy(ptr, vec[i], IndexTupleSize(vec[i])); memcpy(ptr, vec[i], IndexTupleSize(vec[i]));
ptr += IndexTupleSize(vec[i]); ptr += IndexTupleSize(vec[i]);
} }
return (IndexTupleData*)ret; return (IndexTupleData *) ret;
} }
/* /*
@ -145,30 +152,35 @@ gistfillitupvec(IndexTuple *vec, int veclen, int *memlen) {
bool bool
gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len, int startkey, gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len, int startkey,
Datum *attr, bool *isnull ) { Datum *attr, bool *isnull)
{
int i; int i;
GistEntryVector *evec; GistEntryVector *evec;
int attrsize; int attrsize;
evec = (GistEntryVector *) palloc( ( len + 2 ) * sizeof(GISTENTRY) + GEVHDRSZ); 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; int j;
evec->n = 0; evec->n = 0;
if ( !isnull[i] ) { if (!isnull[i])
gistentryinit( evec->vector[evec->n], attr[i], {
gistentryinit(evec->vector[evec->n], attr[i],
NULL, NULL, (OffsetNumber) 0, NULL, NULL, (OffsetNumber) 0,
FALSE); FALSE);
evec->n++; evec->n++;
} }
for (j = 0; j < len; j++) { for (j = 0; j < len; j++)
{
Datum datum; Datum datum;
bool IsNull; bool IsNull;
if (GistTupleIsInvalid(itvec[j])) 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); datum = index_getattr(itvec[j], i + 1, giststate->tupdesc, &IsNull);
if (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 this tuple vector was all NULLs, the union is NULL */
if ( evec->n == 0 ) { if (evec->n == 0)
{
attr[i] = (Datum) 0; attr[i] = (Datum) 0;
isnull[i] = TRUE; isnull[i] = TRUE;
} else { }
if (evec->n == 1) { else
{
if (evec->n == 1)
{
evec->n = 2; evec->n = 2;
evec->vector[1] = evec->vector[0]; evec->vector[1] = evec->vector[0];
} }
@ -213,7 +229,7 @@ gistunion(Relation r, IndexTuple *itvec, int len, GISTSTATE *giststate)
{ {
memset(isnullS, TRUE, sizeof(bool) * giststate->tupdesc->natts); memset(isnullS, TRUE, sizeof(bool) * giststate->tupdesc->natts);
if ( !gistMakeUnionItVec(giststate, itvec, len, 0, attrS, isnullS ) ) if (!gistMakeUnionItVec(giststate, itvec, len, 0, attrS, isnullS))
return gist_form_invalid_tuple(InvalidBlockNumber); return gist_form_invalid_tuple(InvalidBlockNumber);
return gistFormTuple(giststate, r, attrS, isnullS, false); return gistFormTuple(giststate, r, attrS, isnullS, false);
@ -223,29 +239,38 @@ gistunion(Relation r, IndexTuple *itvec, int len, GISTSTATE *giststate)
* makes union of two key * makes union of two key
*/ */
void void
gistMakeUnionKey( GISTSTATE *giststate, int attno, gistMakeUnionKey(GISTSTATE *giststate, int attno,
GISTENTRY *entry1, bool isnull1, GISTENTRY *entry1, bool isnull1,
GISTENTRY *entry2, bool isnull2, GISTENTRY *entry2, bool isnull2,
Datum *dst, bool *dstisnull ) { Datum *dst, bool *dstisnull)
{
int dstsize; int dstsize;
static char storage[ 2 * sizeof(GISTENTRY) + GEVHDRSZ ]; static char storage[2 * sizeof(GISTENTRY) + GEVHDRSZ];
GistEntryVector *evec = (GistEntryVector*)storage; GistEntryVector *evec = (GistEntryVector *) storage;
evec->n = 2; evec->n = 2;
if ( isnull1 && isnull2 ) { if (isnull1 && isnull2)
{
*dstisnull = TRUE; *dstisnull = TRUE;
*dst = (Datum)0; *dst = (Datum) 0;
} else { }
if ( isnull1 == FALSE && isnull2 == FALSE ) { else
{
if (isnull1 == FALSE && isnull2 == FALSE)
{
evec->vector[0] = *entry1; evec->vector[0] = *entry1;
evec->vector[1] = *entry2; evec->vector[1] = *entry2;
} else if ( isnull1 == FALSE ) { }
else if (isnull1 == FALSE)
{
evec->vector[0] = *entry1; evec->vector[0] = *entry1;
evec->vector[1] = *entry1; evec->vector[1] = *entry1;
} else { }
else
{
evec->vector[0] = *entry2; evec->vector[0] = *entry2;
evec->vector[1] = *entry2; evec->vector[1] = *entry2;
} }
@ -258,7 +283,8 @@ gistMakeUnionKey( GISTSTATE *giststate, int attno,
} }
bool bool
gistKeyIsEQ(GISTSTATE *giststate, int attno, Datum a, Datum b) { gistKeyIsEQ(GISTSTATE *giststate, int attno, Datum a, Datum b)
{
bool result; bool result;
FunctionCall3(&giststate->equalFn[attno], FunctionCall3(&giststate->equalFn[attno],
@ -309,22 +335,24 @@ gistgetadjusted(Relation r, IndexTuple oldtup, IndexTuple addtup, GISTSTATE *gis
gistDeCompressAtt(giststate, r, addtup, NULL, gistDeCompressAtt(giststate, r, addtup, NULL,
(OffsetNumber) 0, addentries, addisnull); (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, {
gistMakeUnionKey(giststate, i,
oldentries + i, oldisnull[i], oldentries + i, oldisnull[i],
addentries + i, addisnull[i], addentries + i, addisnull[i],
attrS + i, isnullS + i ); attrS + i, isnullS + i);
if ( neednew ) if (neednew)
/* we already need new key, so we can skip check */ /* we already need new key, so we can skip check */
continue; continue;
if ( isnullS[i] ) if (isnullS[i])
/* union of key may be NULL if and only if both keys are NULL */ /* union of key may be NULL if and only if both keys are NULL */
continue; continue;
if ( !addisnull[i] ) { if (!addisnull[i])
if ( oldisnull[i] || gistKeyIsEQ(giststate, i, oldentries[i].key, attrS[i])==false ) {
if (oldisnull[i] || gistKeyIsEQ(giststate, i, oldentries[i].key, attrS[i]) == false)
neednew = true; neednew = true;
} }
} }
@ -363,8 +391,8 @@ gistchoose(Relation r, Page p, IndexTuple it, /* it has compressed entry */
it, NULL, (OffsetNumber) 0, it, NULL, (OffsetNumber) 0,
identry, isnull); identry, isnull);
Assert( maxoff >= FirstOffsetNumber ); Assert(maxoff >= FirstOffsetNumber);
Assert( !GistPageIsLeaf(p) ); Assert(!GistPageIsLeaf(p));
for (i = FirstOffsetNumber; i <= maxoff && sum_grow; i = OffsetNumberNext(i)) for (i = FirstOffsetNumber; i <= maxoff && sum_grow; i = OffsetNumberNext(i))
{ {
@ -502,15 +530,16 @@ gistpenalty(GISTSTATE *giststate, int attno,
{ {
float penalty = 0.0; float penalty = 0.0;
if ( giststate->penaltyFn[attno].fn_strict==FALSE || ( isNullOrig == FALSE && isNullAdd == FALSE ) ) if (giststate->penaltyFn[attno].fn_strict == FALSE || (isNullOrig == FALSE && isNullAdd == FALSE))
FunctionCall3(&giststate->penaltyFn[attno], FunctionCall3(&giststate->penaltyFn[attno],
PointerGetDatum(orig), PointerGetDatum(orig),
PointerGetDatum(add), PointerGetDatum(add),
PointerGetDatum(&penalty)); PointerGetDatum(&penalty));
else if ( isNullOrig && isNullAdd ) else if (isNullOrig && isNullAdd)
penalty = 0.0; penalty = 0.0;
else 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; return penalty;
} }

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 * Make union of keys on page
*/ */
static IndexTuple static IndexTuple
PageMakeUnionKey(GistVacuum *gv, Buffer buffer) { PageMakeUnionKey(GistVacuum *gv, Buffer buffer)
Page page = BufferGetPage( buffer ); {
Page page = BufferGetPage(buffer);
IndexTuple *vec, IndexTuple *vec,
tmp, res; tmp,
res;
int veclen = 0; int veclen = 0;
MemoryContext oldCtx = MemoryContextSwitchTo(gv->opCtx); MemoryContext oldCtx = MemoryContextSwitchTo(gv->opCtx);
vec = gistextractpage(page, &veclen); 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)); tmp = gistunion(gv->index, vec, veclen, &(gv->giststate));
MemoryContextSwitchTo(oldCtx); MemoryContextSwitchTo(oldCtx);
@ -73,7 +78,8 @@ PageMakeUnionKey(GistVacuum *gv, Buffer buffer) {
} }
static void static void
gistDeleteSubtree( GistVacuum *gv, BlockNumber blkno ) { gistDeleteSubtree(GistVacuum *gv, BlockNumber blkno)
{
Buffer buffer; Buffer buffer;
Page page; Page page;
@ -81,12 +87,15 @@ gistDeleteSubtree( GistVacuum *gv, BlockNumber blkno ) {
LockBuffer(buffer, GIST_EXCLUSIVE); LockBuffer(buffer, GIST_EXCLUSIVE);
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
if ( !GistPageIsLeaf(page) ) { if (!GistPageIsLeaf(page))
{
int i; 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); ItemId iid = PageGetItemId(page, i);
IndexTuple idxtuple = (IndexTuple) PageGetItem(page, iid); IndexTuple idxtuple = (IndexTuple) PageGetItem(page, iid);
gistDeleteSubtree(gv, ItemPointerGetBlockNumber(&(idxtuple->t_tid))); gistDeleteSubtree(gv, ItemPointerGetBlockNumber(&(idxtuple->t_tid)));
} }
} }
@ -132,23 +141,26 @@ gistDeleteSubtree( GistVacuum *gv, BlockNumber blkno ) {
} }
static Page static Page
GistPageGetCopyPage( Page page ) { GistPageGetCopyPage(Page page)
Size pageSize = PageGetPageSize( page ); {
Size pageSize = PageGetPageSize(page);
Page tmppage; Page tmppage;
tmppage=(Page)palloc( pageSize ); tmppage = (Page) palloc(pageSize);
memcpy( tmppage, page, pageSize ); memcpy(tmppage, page, pageSize);
return tmppage; return tmppage;
} }
static ArrayTuple 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}; ArrayTuple res = {NULL, 0, false};
IndexTuple *vec; IndexTuple *vec;
SplitedPageLayout *dist = NULL, SplitedPageLayout *dist = NULL,
*ptr; *ptr;
int i, veclen=0; int i,
veclen = 0;
BlockNumber blkno = BufferGetBlockNumber(buffer); BlockNumber blkno = BufferGetBlockNumber(buffer);
MemoryContext oldCtx = MemoryContextSwitchTo(gv->opCtx); MemoryContext oldCtx = MemoryContextSwitchTo(gv->opCtx);
@ -158,61 +170,67 @@ vacuumSplitPage(GistVacuum *gv, Page tempPage, Buffer buffer, IndexTuple *addon,
MemoryContextSwitchTo(oldCtx); MemoryContextSwitchTo(oldCtx);
if (blkno != GIST_ROOT_BLKNO) { if (blkno != GIST_ROOT_BLKNO)
{
/* if non-root split then we should not allocate new buffer */ /* if non-root split then we should not allocate new buffer */
dist->buffer = buffer; dist->buffer = buffer;
dist->page = tempPage; dist->page = tempPage;
/* during vacuum we never split leaf page */ /* during vacuum we never split leaf page */
GistPageGetOpaque(dist->page)->flags = 0; GistPageGetOpaque(dist->page)->flags = 0;
} else }
else
pfree(tempPage); pfree(tempPage);
res.itup = (IndexTuple *) palloc(sizeof(IndexTuple) * veclen); res.itup = (IndexTuple *) palloc(sizeof(IndexTuple) * veclen);
res.ituplen = 0; res.ituplen = 0;
/* make new pages and fills them */ /* make new pages and fills them */
for (ptr = dist; ptr; ptr = ptr->next) { for (ptr = dist; ptr; ptr = ptr->next)
{
char *data; char *data;
if ( ptr->buffer == InvalidBuffer ) { if (ptr->buffer == InvalidBuffer)
ptr->buffer = gistNewBuffer( gv->index ); {
GISTInitBuffer( ptr->buffer, 0 ); ptr->buffer = gistNewBuffer(gv->index);
GISTInitBuffer(ptr->buffer, 0);
ptr->page = BufferGetPage(ptr->buffer); ptr->page = BufferGetPage(ptr->buffer);
} }
ptr->block.blkno = BufferGetBlockNumber( ptr->buffer ); ptr->block.blkno = BufferGetBlockNumber(ptr->buffer);
data = (char*)(ptr->list); 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 ) {
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)); elog(ERROR, "failed to add item to index page in \"%s\"", RelationGetRelationName(gv->index));
data += IndexTupleSize((IndexTuple)data); data += IndexTupleSize((IndexTuple) data);
} }
ItemPointerSetBlockNumber(&(ptr->itup->t_tid), ptr->block.blkno); ItemPointerSetBlockNumber(&(ptr->itup->t_tid), ptr->block.blkno);
res.itup[ res.ituplen ] = (IndexTuple)palloc(IndexTupleSize(ptr->itup)); res.itup[res.ituplen] = (IndexTuple) palloc(IndexTupleSize(ptr->itup));
memcpy( res.itup[ res.ituplen ], ptr->itup, IndexTupleSize(ptr->itup) ); memcpy(res.itup[res.ituplen], ptr->itup, IndexTupleSize(ptr->itup));
res.ituplen++; res.ituplen++;
} }
START_CRIT_SECTION(); START_CRIT_SECTION();
for (ptr = dist; ptr; ptr = ptr->next) { for (ptr = dist; ptr; ptr = ptr->next)
{
MarkBufferDirty(ptr->buffer); MarkBufferDirty(ptr->buffer);
GistPageGetOpaque(ptr->page)->rightlink = InvalidBlockNumber; GistPageGetOpaque(ptr->page)->rightlink = InvalidBlockNumber;
} }
/* restore splitted non-root page */ /* 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 ); PageRestoreTempPage(dist->page, BufferGetPage(dist->buffer));
dist->page = BufferGetPage(dist->buffer);
} }
if (!gv->index->rd_istemp) if (!gv->index->rd_istemp)
{ {
XLogRecPtr recptr; XLogRecPtr recptr;
XLogRecData *rdata; XLogRecData *rdata;
ItemPointerData key; /* set key for incomplete ItemPointerData key; /* set key for incomplete insert */
* insert */
char *xlinfo; char *xlinfo;
ItemPointerSet(&key, blkno, TUPLE_IS_VALID); ItemPointerSet(&key, blkno, TUPLE_IS_VALID);
@ -241,13 +259,12 @@ vacuumSplitPage(GistVacuum *gv, Page tempPage, Buffer buffer, IndexTuple *addon,
{ {
/* we must keep the buffer pin on the head page */ /* we must keep the buffer pin on the head page */
if (BufferGetBlockNumber(ptr->buffer) != blkno) if (BufferGetBlockNumber(ptr->buffer) != blkno)
UnlockReleaseBuffer( ptr->buffer ); UnlockReleaseBuffer(ptr->buffer);
} }
if (blkno == GIST_ROOT_BLKNO) if (blkno == GIST_ROOT_BLKNO)
{ {
ItemPointerData key; /* set key for incomplete ItemPointerData key; /* set key for incomplete insert */
* insert */
ItemPointerSet(&key, blkno, TUPLE_IS_VALID); ItemPointerSet(&key, blkno, TUPLE_IS_VALID);
@ -266,7 +283,8 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
{ {
ArrayTuple res = {NULL, 0, false}; ArrayTuple res = {NULL, 0, false};
Buffer buffer; Buffer buffer;
Page page, tempPage = NULL; Page page,
tempPage = NULL;
OffsetNumber i, OffsetNumber i,
maxoff; maxoff;
ItemId iid; ItemId iid;
@ -322,7 +340,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
if (chldtuple.ituplen || chldtuple.emptypage) if (chldtuple.ituplen || chldtuple.emptypage)
{ {
/* update tuple or/and inserts new */ /* update tuple or/and inserts new */
if ( chldtuple.emptypage ) if (chldtuple.emptypage)
blkToDelete[nBlkToDelete++] = ItemPointerGetBlockNumber(&(idxtuple->t_tid)); blkToDelete[nBlkToDelete++] = ItemPointerGetBlockNumber(&(idxtuple->t_tid));
offToDelete[nOffToDelete++] = i; offToDelete[nOffToDelete++] = i;
PageIndexTupleDelete(tempPage, i); PageIndexTupleDelete(tempPage, i);
@ -333,7 +351,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
if (chldtuple.ituplen) if (chldtuple.ituplen)
{ {
Assert( chldtuple.emptypage == false ); Assert(chldtuple.emptypage == false);
while (curlenaddon + chldtuple.ituplen >= lenaddon) while (curlenaddon + chldtuple.ituplen >= lenaddon)
{ {
lenaddon *= 2; lenaddon *= 2;
@ -368,49 +386,56 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
} }
} }
Assert( maxoff == PageGetMaxOffsetNumber(tempPage) ); Assert(maxoff == PageGetMaxOffsetNumber(tempPage));
if (curlenaddon) if (curlenaddon)
{ {
/* insert updated tuples */ /* 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 */ /* there is no space on page to insert tuples */
res = vacuumSplitPage(gv, tempPage, buffer, addon, curlenaddon); res = vacuumSplitPage(gv, tempPage, buffer, addon, curlenaddon);
tempPage=NULL; /* vacuumSplitPage() free tempPage */ tempPage = NULL; /* vacuumSplitPage() free tempPage */
needwrite = needunion = false; /* gistSplit already forms unions and writes pages */ needwrite = needunion = false; /* gistSplit already forms
} else * unions and writes pages */
}
else
/* enough free space */ /* enough free space */
gistfillbuffer(gv->index, tempPage, addon, curlenaddon, InvalidOffsetNumber); gistfillbuffer(gv->index, tempPage, addon, curlenaddon, InvalidOffsetNumber);
} }
} }
/* /*
* If page is empty, we should remove pointer to it before * If page is empty, we should remove pointer to it before deleting page
* deleting page (except root) * (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, * New version of page is empty, so leave it unchanged, upper call
* upper call will mark our page as deleted. * will mark our page as deleted. In case of page split we never will
* In case of page split we never will be here... * be here...
* *
* If page was empty it can't become non-empty during processing * If page was empty it can't become non-empty during processing
*/ */
res.emptypage = true; res.emptypage = true;
UnlockReleaseBuffer(buffer); UnlockReleaseBuffer(buffer);
} else { }
else
{
/* write page and remove its childs if it need */ /* write page and remove its childs if it need */
START_CRIT_SECTION(); START_CRIT_SECTION();
if ( tempPage && needwrite ) { if (tempPage && needwrite)
{
PageRestoreTempPage(tempPage, page); PageRestoreTempPage(tempPage, page);
tempPage = NULL; tempPage = NULL;
} }
/* Empty index */ /* Empty index */
if (PageIsEmpty(page) && blkno == GIST_ROOT_BLKNO ) if (PageIsEmpty(page) && blkno == GIST_ROOT_BLKNO)
{ {
needwrite = true; needwrite = true;
GistPageSetLeaf(page); GistPageSetLeaf(page);
@ -446,7 +471,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
END_CRIT_SECTION(); END_CRIT_SECTION();
if ( needunion && !PageIsEmpty(page) ) if (needunion && !PageIsEmpty(page))
{ {
res.itup = (IndexTuple *) palloc(sizeof(IndexTuple)); res.itup = (IndexTuple *) palloc(sizeof(IndexTuple));
res.ituplen = 1; res.ituplen = 1;
@ -456,7 +481,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
UnlockReleaseBuffer(buffer); UnlockReleaseBuffer(buffer);
/* delete empty children, now we havn't any links to pointed subtrees */ /* delete empty children, now we havn't any links to pointed subtrees */
for(i=0;i<nBlkToDelete;i++) for (i = 0; i < nBlkToDelete; i++)
gistDeleteSubtree(gv, blkToDelete[i]); gistDeleteSubtree(gv, blkToDelete[i]);
if (ncompleted && !gv->index->rd_istemp) if (ncompleted && !gv->index->rd_istemp)
@ -506,9 +531,10 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
/* use heap's tuple count */ /* use heap's tuple count */
Assert(info->num_heap_tuples >= 0); Assert(info->num_heap_tuples >= 0);
stats->std.num_index_tuples = info->num_heap_tuples; stats->std.num_index_tuples = info->num_heap_tuples;
/* /*
* XXX the above is wrong if index is partial. Would it be OK to * XXX the above is wrong if index is partial. Would it be OK to just
* just return NULL, or is there work we must do below? * return NULL, or is there work we must do below?
*/ */
} }
@ -545,8 +571,8 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
RelationGetRelationName(rel)))); RelationGetRelationName(rel))));
/* /*
* If vacuum full, we already have exclusive lock on the index. * If vacuum full, we already have exclusive lock on the index. Otherwise,
* Otherwise, need lock unless it's local to this backend. * need lock unless it's local to this backend.
*/ */
if (info->vacuum_full) if (info->vacuum_full)
needLock = false; needLock = false;
@ -725,7 +751,7 @@ gistbulkdelete(PG_FUNCTION_ARGS)
if (callback(&(idxtuple->t_tid), callback_state)) if (callback(&(idxtuple->t_tid), callback_state))
{ {
todelete[ntodelete] = i-ntodelete; todelete[ntodelete] = i - ntodelete;
ntodelete++; ntodelete++;
stats->std.tuples_removed += 1; stats->std.tuples_removed += 1;
} }
@ -739,7 +765,7 @@ gistbulkdelete(PG_FUNCTION_ARGS)
MarkBufferDirty(buffer); MarkBufferDirty(buffer);
for(i=0;i<ntodelete;i++) for (i = 0; i < ntodelete; i++)
PageIndexTupleDelete(page, todelete[i]); PageIndexTupleDelete(page, todelete[i]);
GistMarkTuplesDeleted(page); GistMarkTuplesDeleted(page);

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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" #include "postgres.h"
@ -72,7 +72,8 @@ pushIncompleteInsert(RelFileNode node, XLogRecPtr lsn, ItemPointerData key,
MemoryContext oldCxt; MemoryContext oldCxt;
gistIncompleteInsert *ninsert; gistIncompleteInsert *ninsert;
if ( !ItemPointerIsValid(&key) ) if (!ItemPointerIsValid(&key))
/* /*
* if key is null then we should not store insertion as incomplete, * if key is null then we should not store insertion as incomplete,
* because it's a vacuum operation.. * 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 * Stick the new incomplete insert onto the front of the list, not the
* back. This is so that gist_xlog_cleanup will process incompletions * back. This is so that gist_xlog_cleanup will process incompletions in
* in last-in-first-out order. * last-in-first-out order.
*/ */
incomplete_inserts = lcons(ninsert, incomplete_inserts); incomplete_inserts = lcons(ninsert, incomplete_inserts);
@ -121,10 +122,10 @@ forgetIncompleteInsert(RelFileNode node, ItemPointerData key)
{ {
ListCell *l; ListCell *l;
if ( !ItemPointerIsValid(&key) ) if (!ItemPointerIsValid(&key))
return; return;
if (incomplete_inserts==NIL) if (incomplete_inserts == NIL)
return; return;
foreach(l, incomplete_inserts) foreach(l, incomplete_inserts)
@ -241,9 +242,12 @@ gistRedoPageUpdateRecord(XLogRecPtr lsn, XLogRecord *record, bool isnewroot)
if (GistPageIsLeaf(page) && xlrec.len == 0 && xlrec.data->ntodelete == 0) if (GistPageIsLeaf(page) && xlrec.len == 0 && xlrec.data->ntodelete == 0)
GistClearTuplesDeleted(page); GistClearTuplesDeleted(page);
if ( !GistPageIsLeaf(page) && PageGetMaxOffsetNumber(page) == InvalidOffsetNumber && xldata->blkno == GIST_ROOT_BLKNO ) 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); GistPageSetLeaf(page);
GistPageGetOpaque(page)->rightlink = InvalidBlockNumber; GistPageGetOpaque(page)->rightlink = InvalidBlockNumber;
@ -433,7 +437,7 @@ out_target(StringInfo buf, RelFileNode node, ItemPointerData key)
{ {
appendStringInfo(buf, "rel %u/%u/%u", appendStringInfo(buf, "rel %u/%u/%u",
node.spcNode, node.dbNode, node.relNode); node.spcNode, node.dbNode, node.relNode);
if ( ItemPointerIsValid( &key ) ) if (ItemPointerIsValid(&key))
appendStringInfo(buf, "; tid %u/%u", appendStringInfo(buf, "; tid %u/%u",
ItemPointerGetBlockNumber(&key), ItemPointerGetBlockNumber(&key),
ItemPointerGetOffsetNumber(&key)); ItemPointerGetOffsetNumber(&key));
@ -547,22 +551,25 @@ gistxlogFindPath(Relation index, gistIncompleteInsert *insert)
elog(ERROR, "lost parent for block %u", insert->origblkno); elog(ERROR, "lost parent for block %u", insert->origblkno);
} }
static SplitedPageLayout* static SplitedPageLayout *
gistMakePageLayout(Buffer *buffers, int nbuffers) { gistMakePageLayout(Buffer *buffers, int nbuffers)
SplitedPageLayout *res=NULL, *resptr; {
SplitedPageLayout *res = NULL,
*resptr;
while( nbuffers-- > 0 ) { while (nbuffers-- > 0)
Page page = BufferGetPage( buffers[ nbuffers ] ); {
IndexTuple* vec; Page page = BufferGetPage(buffers[nbuffers]);
IndexTuple *vec;
int veclen; int veclen;
resptr = (SplitedPageLayout*)palloc0( sizeof(SplitedPageLayout) ); resptr = (SplitedPageLayout *) palloc0(sizeof(SplitedPageLayout));
resptr->block.blkno = BufferGetBlockNumber( buffers[ nbuffers ] ); resptr->block.blkno = BufferGetBlockNumber(buffers[nbuffers]);
resptr->block.num = PageGetMaxOffsetNumber( page ); resptr->block.num = PageGetMaxOffsetNumber(page);
vec = gistextractpage( page, &veclen ); vec = gistextractpage(page, &veclen);
resptr->list = gistfillitupvec( vec, veclen, &(resptr->lenlist) ); resptr->list = gistfillitupvec(vec, veclen, &(resptr->lenlist));
resptr->next = res; resptr->next = res;
res = resptr; res = resptr;
@ -650,13 +657,14 @@ gistContinueInsert(gistIncompleteInsert *insert)
numbuffer = 1; numbuffer = 1;
buffers[0] = ReadBuffer(index, insert->path[i]); buffers[0] = ReadBuffer(index, insert->path[i]);
LockBuffer(buffers[0], GIST_EXCLUSIVE); LockBuffer(buffers[0], GIST_EXCLUSIVE);
/* /*
* we check buffer, because we restored page earlier * we check buffer, because we restored page earlier
*/ */
gistcheckpage(index, buffers[0]); gistcheckpage(index, buffers[0]);
pages[0] = BufferGetPage(buffers[0]); pages[0] = BufferGetPage(buffers[0]);
Assert( !GistPageIsLeaf(pages[0]) ); Assert(!GistPageIsLeaf(pages[0]));
pituplen = PageGetMaxOffsetNumber(pages[0]); pituplen = PageGetMaxOffsetNumber(pages[0]);
@ -678,12 +686,12 @@ gistContinueInsert(gistIncompleteInsert *insert)
} }
} }
if ( ntodelete == 0 ) if (ntodelete == 0)
elog(PANIC,"gistContinueInsert: can't find pointer to page(s)"); elog(PANIC, "gistContinueInsert: can't find pointer to page(s)");
/* /*
* we check space with subtraction only first tuple to delete, hope, * we check space with subtraction only first tuple to delete,
* that wiil be enough space.... * hope, that wiil be enough space....
*/ */
if (gistnospace(pages[0], itup, lenitup, *todelete, 0)) if (gistnospace(pages[0], itup, lenitup, *todelete, 0))
@ -713,29 +721,32 @@ gistContinueInsert(gistIncompleteInsert *insert)
/* fill new page, root will be changed later */ /* fill new page, root will be changed later */
tempbuffer = ReadBuffer(index, P_NEW); tempbuffer = ReadBuffer(index, P_NEW);
LockBuffer(tempbuffer, GIST_EXCLUSIVE); LockBuffer(tempbuffer, GIST_EXCLUSIVE);
memcpy( BufferGetPage(tempbuffer), pages[0], BufferGetPageSize(tempbuffer) ); memcpy(BufferGetPage(tempbuffer), pages[0], BufferGetPageSize(tempbuffer));
/* swap buffers[0] (was root) and temp buffer */ /* swap buffers[0] (was root) and temp buffer */
tmp = buffers[0]; tmp = buffers[0];
buffers[0] = tempbuffer; 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]); pages[0] = BufferGetPage(buffers[0]);
} }
START_CRIT_SECTION(); START_CRIT_SECTION();
for(j=0;j<ntodelete;j++) for (j = 0; j < ntodelete; j++)
PageIndexTupleDelete(pages[0], todelete[j]); PageIndexTupleDelete(pages[0], todelete[j]);
rdata = formSplitRdata(index->rd_node, insert->path[i], rdata = formSplitRdata(index->rd_node, insert->path[i],
false, &(insert->key), false, &(insert->key),
gistMakePageLayout( buffers, numbuffer ) ); gistMakePageLayout(buffers, numbuffer));
} else { }
else
{
START_CRIT_SECTION(); START_CRIT_SECTION();
for(j=0;j<ntodelete;j++) for (j = 0; j < ntodelete; j++)
PageIndexTupleDelete(pages[0], todelete[j]); PageIndexTupleDelete(pages[0], todelete[j]);
gistfillbuffer(index, pages[0], itup, lenitup, InvalidOffsetNumber); gistfillbuffer(index, pages[0], itup, lenitup, InvalidOffsetNumber);
@ -745,12 +756,13 @@ gistContinueInsert(gistIncompleteInsert *insert)
} }
/* /*
* use insert->key as mark for completion of insert (form*Rdata() above) * use insert->key as mark for completion of insert (form*Rdata()
* for following possible replays * above) for following possible replays
*/ */
/* write pages, we should mark it dirty befor XLogInsert() */ /* 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; GistPageGetOpaque(pages[j])->rightlink = InvalidBlockNumber;
MarkBufferDirty(buffers[j]); MarkBufferDirty(buffers[j]);
} }
@ -764,12 +776,14 @@ gistContinueInsert(gistIncompleteInsert *insert)
END_CRIT_SECTION(); END_CRIT_SECTION();
lenitup = numbuffer; lenitup = numbuffer;
for (j = 0; j < numbuffer; j++) { for (j = 0; j < numbuffer; j++)
{
itup[j] = gist_form_invalid_tuple(BufferGetBlockNumber(buffers[j])); itup[j] = gist_form_invalid_tuple(BufferGetBlockNumber(buffers[j]));
UnlockReleaseBuffer(buffers[j]); UnlockReleaseBuffer(buffers[j]);
} }
if ( tempbuffer != InvalidBuffer ) { if (tempbuffer != InvalidBuffer)
{
/* /*
* it was a root split, so fill it by new values * it was a root split, so fill it by new values
*/ */

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* These functions are stored in pg_amproc. For each operator class * These functions are stored in pg_amproc. For each operator class
@ -138,8 +138,8 @@ hashtext(PG_FUNCTION_ARGS)
Datum result; Datum result;
/* /*
* Note: this is currently identical in behavior to hashvarlena, but * Note: this is currently identical in behavior to hashvarlena, but keep
* keep it as a separate function in case we someday want to do something * it as a separate function in case we someday want to do something
* different in non-C locales. (See also hashbpchar, if so.) * different in non-C locales. (See also hashbpchar, if so.)
*/ */
result = hash_any((unsigned char *) VARDATA(key), result = hash_any((unsigned char *) VARDATA(key),

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* Postgres hash pages look like ordinary relation pages. The opaque * Postgres hash pages look like ordinary relation pages. The opaque

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * INTERFACE ROUTINES
@ -133,9 +133,9 @@ heapgetpage(HeapScanDesc scan, BlockNumber page)
snapshot = scan->rs_snapshot; snapshot = scan->rs_snapshot;
/* /*
* We must hold share lock on the buffer content while examining * We must hold share lock on the buffer content while examining tuple
* tuple visibility. Afterwards, however, the tuples we have found * visibility. Afterwards, however, the tuples we have found to be
* to be visible are guaranteed good as long as we hold the buffer pin. * visible are guaranteed good as long as we hold the buffer pin.
*/ */
LockBuffer(buffer, BUFFER_LOCK_SHARE); LockBuffer(buffer, BUFFER_LOCK_SHARE);
@ -721,8 +721,8 @@ try_relation_open(Oid relationId, LOCKMODE lockmode)
LockRelationOid(relationId, lockmode); LockRelationOid(relationId, lockmode);
/* /*
* Now that we have the lock, probe to see if the relation really * Now that we have the lock, probe to see if the relation really exists
* exists or not. * or not.
*/ */
if (!SearchSysCacheExists(RELOID, if (!SearchSysCacheExists(RELOID,
ObjectIdGetDatum(relationId), ObjectIdGetDatum(relationId),
@ -801,8 +801,8 @@ relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
/* /*
* Check for shared-cache-inval messages before trying to open the * Check for shared-cache-inval messages before trying to open the
* relation. This is needed to cover the case where the name identifies * relation. This is needed to cover the case where the name identifies a
* a rel that has been dropped and recreated since the start of our * 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 * 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. * 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 * 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)) if (!ItemPointerIsValid(&scan->rs_mctid))
{ {
scan->rs_ctup.t_data = NULL; scan->rs_ctup.t_data = NULL;
/* /*
* unpin scan buffers * unpin scan buffers
*/ */
@ -3308,6 +3309,7 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool move)
/* Set forward chain link in t_ctid */ /* Set forward chain link in t_ctid */
htup->t_ctid = xlrec->newtid; htup->t_ctid = xlrec->newtid;
} }
/* /*
* this test is ugly, but necessary to avoid thinking that insert change * this test is ugly, but necessary to avoid thinking that insert change
* is already applied * is already applied

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * INTERFACE ROUTINES

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* many of the old access method routines have been turned into * many of the old access method routines have been turned into

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * INTERFACE ROUTINES
* index_open - open an index relation by relation OID * index_open - open an index relation by relation OID

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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); sopaque = (BTPageOpaque) PageGetSpecialPointer(spage);
if (sopaque->btpo_prev != ropaque->btpo_prev) if (sopaque->btpo_prev != ropaque->btpo_prev)
elog(PANIC, "right sibling's left-link doesn't match"); 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 * 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 * 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 * 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 * sibling has a different cycleid: that means it could not be part of
* of a group of pages that were all split off from the same ancestor * 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 * 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 * 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 * 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 * 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 * 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 * scribbling on the original page yet, and we don't care about the new
* new sibling until it's linked into the btree. * sibling until it's linked into the btree.
*/ */
START_CRIT_SECTION(); 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 * Direct access to page is not good but faster - we should implement
* some new func in page API. Note we only store the tuples * some new func in page API. Note we only store the tuples
* themselves, knowing that the item pointers are in the same order * themselves, knowing that the item pointers are in the same order
* and can be reconstructed by scanning the tuples. See comments * and can be reconstructed by scanning the tuples. See comments for
* for _bt_restore_page(). * _bt_restore_page().
*/ */
xlrec.leftlen = ((PageHeader) leftpage)->pd_special - xlrec.leftlen = ((PageHeader) leftpage)->pd_special -
((PageHeader) leftpage)->pd_upper; ((PageHeader) leftpage)->pd_upper;
@ -1717,8 +1718,8 @@ _bt_vacuum_one_page(Relation rel, Buffer buffer)
BTPageOpaque opaque = (BTPageOpaque) PageGetSpecialPointer(page); BTPageOpaque opaque = (BTPageOpaque) PageGetSpecialPointer(page);
/* /*
* Scan over all items to see which ones need deleted * Scan over all items to see which ones need deleted according to
* according to LP_DELETE flags. * LP_DELETE flags.
*/ */
minoff = P_FIRSTDATAKEY(opaque); minoff = P_FIRSTDATAKEY(opaque);
maxoff = PageGetMaxOffsetNumber(page); maxoff = PageGetMaxOffsetNumber(page);
@ -1734,10 +1735,11 @@ _bt_vacuum_one_page(Relation rel, Buffer buffer)
if (ndeletable > 0) if (ndeletable > 0)
_bt_delitems(rel, buffer, deletable, ndeletable); _bt_delitems(rel, buffer, deletable, ndeletable);
/* /*
* Note: if we didn't find any LP_DELETE items, then the page's * 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 * BTP_HAS_GARBAGE hint bit is falsely set. We do not bother expending a
* expending a separate write to clear it, however. We will clear * separate write to clear it, however. We will clear it when we split
* it when we split the page. * the page.
*/ */
} }

View File

@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* Postgres btree pages look like ordinary relation pages. The opaque * 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 * Since the cache might be stale, we check the page more carefully
* here than normal. We *must* check that it's not deleted. * here than normal. We *must* check that it's not deleted. If it's
* If it's not alone on its level, then we reject too --- this * not alone on its level, then we reject too --- this may be overly
* may be overly paranoid but better safe than sorry. Note we * paranoid but better safe than sorry. Note we don't check P_ISROOT,
* don't check P_ISROOT, because that's not set in a "fast root". * because that's not set in a "fast root".
*/ */
if (!P_IGNORE(rootopaque) && if (!P_IGNORE(rootopaque) &&
rootopaque->btpo.level == rootlevel && rootopaque->btpo.level == rootlevel &&
@ -662,18 +662,18 @@ _bt_delitems(Relation rel, Buffer buf,
PageIndexMultiDelete(page, itemnos, nitems); PageIndexMultiDelete(page, itemnos, nitems);
/* /*
* We can clear the vacuum cycle ID since this page has certainly * We can clear the vacuum cycle ID since this page has certainly been
* been processed by the current vacuum scan. * processed by the current vacuum scan.
*/ */
opaque = (BTPageOpaque) PageGetSpecialPointer(page); opaque = (BTPageOpaque) PageGetSpecialPointer(page);
opaque->btpo_cycleid = 0; opaque->btpo_cycleid = 0;
/* /*
* Mark the page as not containing any LP_DELETE items. This is not * Mark the page as not containing any LP_DELETE items. This is not
* certainly true (there might be some that have recently been marked, * certainly true (there might be some that have recently been marked, but
* but weren't included in our target-item list), but it will almost * weren't included in our target-item list), but it will almost always be
* always be true and it doesn't seem worth an additional page scan * true and it doesn't seem worth an additional page scan to check it.
* to check it. Remember that BTP_HAS_GARBAGE is only a hint anyway. * Remember that BTP_HAS_GARBAGE is only a hint anyway.
*/ */
opaque->btpo_flags &= ~BTP_HAS_GARBAGE; opaque->btpo_flags &= ~BTP_HAS_GARBAGE;

View File

@ -12,7 +12,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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); buildstate.spool = _bt_spoolinit(index, indexInfo->ii_Unique, false);
/* /*
* If building a unique index, put dead tuples in a second spool to * If building a unique index, put dead tuples in a second spool to keep
* keep them out of the uniqueness check. * them out of the uniqueness check.
*/ */
if (indexInfo->ii_Unique) if (indexInfo->ii_Unique)
buildstate.spool2 = _bt_spoolinit(index, false, true); buildstate.spool2 = _bt_spoolinit(index, false, true);
@ -146,11 +146,11 @@ btbuild(PG_FUNCTION_ARGS)
#endif /* BTREE_BUILD_STATS */ #endif /* BTREE_BUILD_STATS */
/* /*
* If we are reindexing a pre-existing index, it is critical to send out * If we are reindexing a pre-existing index, it is critical to send out a
* a relcache invalidation SI message to ensure all backends re-read the * relcache invalidation SI message to ensure all backends re-read the
* index metapage. We expect that the caller will ensure that happens * index metapage. We expect that the caller will ensure that happens
* (typically as a side effect of updating index stats, but it must * (typically as a side effect of updating index stats, but it must happen
* happen even if the stats don't change!) * even if the stats don't change!)
*/ */
/* /*
@ -316,8 +316,8 @@ btgetmulti(PG_FUNCTION_ARGS)
while (ntids < max_tids) while (ntids < max_tids)
{ {
/* /*
* Advance to next tuple within page. This is the same as the * Advance to next tuple within page. This is the same as the easy
* easy case in _bt_next(). * case in _bt_next().
*/ */
if (++so->currPos.itemIndex > so->currPos.lastItem) 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 * Just record the current itemIndex. If we later step to next page
* before releasing the marked position, _bt_steppage makes a full copy * before releasing the marked position, _bt_steppage makes a full copy of
* of the currPos struct in markPos. If (as often happens) the mark is * the currPos struct in markPos. If (as often happens) the mark is moved
* moved before we leave the page, we don't have to do that work. * before we leave the page, we don't have to do that work.
*/ */
if (BTScanPosIsValid(so->currPos)) if (BTScanPosIsValid(so->currPos))
so->markItemIndex = so->currPos.itemIndex; so->markItemIndex = so->currPos.itemIndex;
@ -485,8 +485,8 @@ btrestrpos(PG_FUNCTION_ARGS)
if (so->markItemIndex >= 0) if (so->markItemIndex >= 0)
{ {
/* /*
* The mark position is on the same page we are currently on. * The mark position is on the same page we are currently on. Just
* Just restore the itemIndex. * restore the itemIndex.
*/ */
so->currPos.itemIndex = so->markItemIndex; so->currPos.itemIndex = so->markItemIndex;
} }
@ -527,7 +527,7 @@ Datum
btbulkdelete(PG_FUNCTION_ARGS) btbulkdelete(PG_FUNCTION_ARGS)
{ {
IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0); IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
IndexBulkDeleteResult * volatile stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1); IndexBulkDeleteResult *volatile stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(2); IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(2);
void *callback_state = (void *) PG_GETARG_POINTER(3); void *callback_state = (void *) PG_GETARG_POINTER(3);
Relation rel = info->index; Relation rel = info->index;
@ -569,10 +569,10 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1); IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
/* /*
* If btbulkdelete was called, we need not do anything, just return * If btbulkdelete was called, we need not do anything, just return the
* the stats from the latest btbulkdelete call. If it wasn't called, * stats from the latest btbulkdelete call. If it wasn't called, we must
* we must still do a pass over the index, to recycle any newly-recyclable * still do a pass over the index, to recycle any newly-recyclable pages
* pages and to obtain index statistics. * and to obtain index statistics.
* *
* Since we aren't going to actually delete any leaf items, there's no * Since we aren't going to actually delete any leaf items, there's no
* need to go through all the vacuum-cycle-ID pushups. * 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 * 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 * concurrent page splits into double-counting some index tuples, so
* disbelieve any total that exceeds the underlying heap's count. * disbelieve any total that exceeds the underlying heap's count. (We
* (We can't check this during btbulkdelete.) * can't check this during btbulkdelete.)
*/ */
if (!info->vacuum_full) if (!info->vacuum_full)
{ {
@ -622,8 +622,8 @@ btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
bool needLock; bool needLock;
/* /*
* Reset counts that will be incremented during the scan; needed in * Reset counts that will be incremented during the scan; needed in case
* case of multiple scans during a single VACUUM command * of multiple scans during a single VACUUM command
*/ */
stats->num_index_tuples = 0; stats->num_index_tuples = 0;
stats->pages_deleted = 0; stats->pages_deleted = 0;
@ -647,24 +647,24 @@ btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
ALLOCSET_DEFAULT_MAXSIZE); ALLOCSET_DEFAULT_MAXSIZE);
/* /*
* The outer loop iterates over all index pages except the metapage, * The outer loop iterates over all index pages except the metapage, in
* in physical order (we hope the kernel will cooperate in providing * physical order (we hope the kernel will cooperate in providing
* read-ahead for speed). It is critical that we visit all leaf pages, * 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 * including ones added after we start the scan, else we might fail to
* delete some deletable tuples. Hence, we must repeatedly check the * delete some deletable tuples. Hence, we must repeatedly check the
* relation length. We must acquire the relation-extension lock while * relation length. We must acquire the relation-extension lock while
* doing so to avoid a race condition: if someone else is extending the * 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 * 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(). * all-zero page but it hasn't yet been write-locked by _bt_getbuf(). If
* If we manage to scan such a page here, we'll improperly assume it can * we manage to scan such a page here, we'll improperly assume it can be
* be recycled. Taking the lock synchronizes things enough to prevent a * recycled. Taking the lock synchronizes things enough to prevent a
* problem: either num_pages won't include the new page, or _bt_getbuf * 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 * 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 * 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 * 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 * 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 * page before it adds a right page, so we must already have processed any
* any tuples due to be moved into such a page. * tuples due to be moved into such a page.
* *
* We can skip locking for new or temp relations, however, since no one * We can skip locking for new or temp relations, however, since no one
* else could be accessing them. * else could be accessing them.
@ -796,10 +796,10 @@ restart:
_bt_checkpage(rel, buf); _bt_checkpage(rel, buf);
/* /*
* If we are recursing, the only case we want to do anything with is * If we are recursing, the only case we want to do anything with is a
* a live leaf page having the current vacuum cycle ID. Any other state * live leaf page having the current vacuum cycle ID. Any other state
* implies we already saw the page (eg, deleted it as being empty). * implies we already saw the page (eg, deleted it as being empty). In
* In particular, we don't want to risk adding it to freePages twice. * particular, we don't want to risk adding it to freePages twice.
*/ */
if (blkno != orig_blkno) if (blkno != orig_blkno)
{ {
@ -842,21 +842,20 @@ restart:
maxoff; maxoff;
/* /*
* Trade in the initial read lock for a super-exclusive write * Trade in the initial read lock for a super-exclusive write lock on
* lock on this page. We must get such a lock on every leaf page * this page. We must get such a lock on every leaf page over the
* over the course of the vacuum scan, whether or not it actually * course of the vacuum scan, whether or not it actually contains any
* contains any deletable tuples --- see nbtree/README. * deletable tuples --- see nbtree/README.
*/ */
LockBuffer(buf, BUFFER_LOCK_UNLOCK); LockBuffer(buf, BUFFER_LOCK_UNLOCK);
LockBufferForCleanup(buf); LockBufferForCleanup(buf);
/* /*
* Check whether we need to recurse back to earlier pages. What * Check whether we need to recurse back to earlier pages. What we
* we are concerned about is a page split that happened since we * are concerned about is a page split that happened since we started
* started the vacuum scan. If the split moved some tuples to a * the vacuum scan. If the split moved some tuples to a lower page
* lower page then we might have missed 'em. If so, set up for * then we might have missed 'em. If so, set up for tail recursion.
* tail recursion. (Must do this before possibly clearing * (Must do this before possibly clearing btpo_cycleid below!)
* btpo_cycleid below!)
*/ */
if (vstate->cycleid != 0 && if (vstate->cycleid != 0 &&
opaque->btpo_cycleid == vstate->cycleid && opaque->btpo_cycleid == vstate->cycleid &&
@ -866,8 +865,8 @@ restart:
recurse_to = opaque->btpo_next; recurse_to = opaque->btpo_next;
/* /*
* Scan over all items to see which ones need deleted * Scan over all items to see which ones need deleted according to the
* according to the callback function. * callback function.
*/ */
ndeletable = 0; ndeletable = 0;
minoff = P_FIRSTDATAKEY(opaque); minoff = P_FIRSTDATAKEY(opaque);
@ -890,8 +889,8 @@ restart:
} }
/* /*
* Apply any needed deletes. We issue just one _bt_delitems() * Apply any needed deletes. We issue just one _bt_delitems() call
* call per page, so as to minimize WAL traffic. * per page, so as to minimize WAL traffic.
*/ */
if (ndeletable > 0) if (ndeletable > 0)
{ {
@ -908,8 +907,8 @@ restart:
* have any deletions to do. (If we do, _bt_delitems takes care * have any deletions to do. (If we do, _bt_delitems takes care
* of this.) This ensures we won't process the page again. * of this.) This ensures we won't process the page again.
* *
* We treat this like a hint-bit update because there's no need * We treat this like a hint-bit update because there's no need to
* to WAL-log it. * WAL-log it.
*/ */
if (vstate->cycleid != 0 && if (vstate->cycleid != 0 &&
opaque->btpo_cycleid == vstate->cycleid) opaque->btpo_cycleid == vstate->cycleid)
@ -920,10 +919,10 @@ restart:
} }
/* /*
* If it's now empty, try to delete; else count the live tuples. * If it's now empty, try to delete; else count the live tuples. We
* We don't delete when recursing, though, to avoid putting entries * don't delete when recursing, though, to avoid putting entries into
* into freePages out-of-order (doesn't seem worth any extra code to * freePages out-of-order (doesn't seem worth any extra code to handle
* handle the case). * the case).
*/ */
if (minoff > maxoff) if (minoff > maxoff)
delete_now = (blkno == orig_blkno); delete_now = (blkno == orig_blkno);
@ -947,13 +946,12 @@ restart:
stats->pages_deleted++; stats->pages_deleted++;
/* /*
* During VACUUM FULL it's okay to recycle deleted pages * During VACUUM FULL it's okay to recycle deleted pages immediately,
* immediately, since there can be no other transactions scanning * since there can be no other transactions scanning the index. Note
* the index. Note that we will only recycle the current page and * that we will only recycle the current page and not any parent pages
* not any parent pages that _bt_pagedel might have recursed to; * that _bt_pagedel might have recursed to; this seems reasonable in
* this seems reasonable in the name of simplicity. (Trying to do * the name of simplicity. (Trying to do otherwise would mean we'd
* otherwise would mean we'd have to sort the list of recyclable * have to sort the list of recyclable pages we're building.)
* pages we're building.)
*/ */
if (ndel && info->vacuum_full) if (ndel && info->vacuum_full)
{ {
@ -969,11 +967,11 @@ restart:
_bt_relbuf(rel, buf); _bt_relbuf(rel, buf);
/* /*
* This is really tail recursion, but if the compiler is too stupid * This is really tail recursion, but if the compiler is too stupid to
* to optimize it as such, we'd eat an uncomfortably large amount of * optimize it as such, we'd eat an uncomfortably large amount of stack
* stack space per recursion level (due to the deletable[] array). * space per recursion level (due to the deletable[] array). A failure is
* A failure is improbable since the number of levels isn't likely to be * improbable since the number of levels isn't likely to be large ... but
* large ... but just in case, let's hand-optimize into a loop. * just in case, let's hand-optimize into a loop.
*/ */
if (recurse_to != P_NONE) if (recurse_to != P_NONE)
{ {

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -604,7 +604,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
{ {
ScanKey cur = startKeys[i]; ScanKey cur = startKeys[i];
Assert(cur->sk_attno == i+1); Assert(cur->sk_attno == i + 1);
if (cur->sk_flags & SK_ROW_HEADER) if (cur->sk_flags & SK_ROW_HEADER)
{ {
@ -612,16 +612,17 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
* Row comparison header: look to the first row member instead. * Row comparison header: look to the first row member instead.
* *
* The member scankeys are already in insertion format (ie, they * The member scankeys are already in insertion format (ie, they
* have sk_func = 3-way-comparison function), but we have to * have sk_func = 3-way-comparison function), but we have to watch
* watch out for nulls, which _bt_preprocess_keys didn't check. * out for nulls, which _bt_preprocess_keys didn't check. A null
* A null in the first row member makes the condition unmatchable, * in the first row member makes the condition unmatchable, just
* just like qual_ok = false. * like qual_ok = false.
*/ */
cur = (ScanKey) DatumGetPointer(cur->sk_argument); cur = (ScanKey) DatumGetPointer(cur->sk_argument);
Assert(cur->sk_flags & SK_ROW_MEMBER); Assert(cur->sk_flags & SK_ROW_MEMBER);
if (cur->sk_flags & SK_ISNULL) if (cur->sk_flags & SK_ISNULL)
return false; return false;
memcpy(scankeys + i, cur, sizeof(ScanKeyData)); memcpy(scankeys + i, cur, sizeof(ScanKeyData));
/* /*
* If the row comparison is the last positioning key we accepted, * If the row comparison is the last positioning key we accepted,
* try to add additional keys from the lower-order row members. * 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 * 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 * 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. * the last item on this page. Adjust the starting offset if needed. (If
* (If this results in an offset before the first item or after the last * this results in an offset before the first item or after the last one,
* one, _bt_readpage will report no items found, and then we'll step to * _bt_readpage will report no items found, and then we'll step to the
* the next page as needed.) * next page as needed.)
*/ */
if (goback) if (goback)
offnum = OffsetNumberPrev(offnum); offnum = OffsetNumberPrev(offnum);
@ -882,8 +883,8 @@ _bt_next(IndexScanDesc scan, ScanDirection dir)
BTScanOpaque so = (BTScanOpaque) scan->opaque; BTScanOpaque so = (BTScanOpaque) scan->opaque;
/* /*
* Advance to next tuple on current page; or if there's no more, * Advance to next tuple on current page; or if there's no more, try to
* try to step to the next page with data. * step to the next page with data.
*/ */
if (ScanDirectionIsForward(dir)) 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 * 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 * where to step right to after we're done with these items. There is no
* no corresponding need for the left-link, since splits always go right. * corresponding need for the left-link, since splits always go right.
*/ */
so->currPos.nextPage = opaque->btpo_next; so->currPos.nextPage = opaque->btpo_next;
@ -1055,8 +1056,8 @@ _bt_steppage(IndexScanDesc scan, ScanDirection dir)
_bt_killitems(scan, true); _bt_killitems(scan, true);
/* /*
* Before we modify currPos, make a copy of the page data if there * Before we modify currPos, make a copy of the page data if there was a
* was a mark position that needs it. * mark position that needs it.
*/ */
if (so->markItemIndex >= 0) if (so->markItemIndex >= 0)
{ {
@ -1112,11 +1113,11 @@ _bt_steppage(IndexScanDesc scan, ScanDirection dir)
so->currPos.moreRight = true; so->currPos.moreRight = true;
/* /*
* Walk left to the next page with data. This is much more * Walk left to the next page with data. This is much more complex
* complex than the walk-right case because of the possibility * than the walk-right case because of the possibility that the page
* that the page to our left splits while we are in flight to it, * to our left splits while we are in flight to it, plus the
* plus the possibility that the page we were on gets deleted * possibility that the page we were on gets deleted after we leave
* after we leave it. See nbtree/README for details. * it. See nbtree/README for details.
*/ */
for (;;) for (;;)
{ {
@ -1136,9 +1137,9 @@ _bt_steppage(IndexScanDesc scan, ScanDirection dir)
return false; return false;
/* /*
* Okay, we managed to move left to a non-deleted page. * Okay, we managed to move left to a non-deleted page. Done if
* Done if it's not half-dead and contains matching tuples. * it's not half-dead and contains matching tuples. Else loop back
* Else loop back and do it all again. * and do it all again.
*/ */
page = BufferGetPage(so->currPos.buf); page = BufferGetPage(so->currPos.buf);
opaque = (BTPageOpaque) PageGetSpecialPointer(page); opaque = (BTPageOpaque) PageGetSpecialPointer(page);

View File

@ -57,7 +57,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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; Size itupsz;
/* /*
* This is a handy place to check for cancel interrupts during the * This is a handy place to check for cancel interrupts during the btree
* btree load phase of index creation. * load phase of index creation.
*/ */
CHECK_FOR_INTERRUPTS(); CHECK_FOR_INTERRUPTS();
@ -499,10 +499,10 @@ _bt_buildadd(BTWriteState *wstate, BTPageState *state, IndexTuple itup)
"or use full text indexing."))); "or use full text indexing.")));
/* /*
* Check to see if page is "full". It's definitely full if the item * Check to see if page is "full". It's definitely full if the item won't
* won't fit. Otherwise, compare to the target freespace derived from * fit. Otherwise, compare to the target freespace derived from the
* the fillfactor. However, we must put at least two items on each * fillfactor. However, we must put at least two items on each page, so
* page, so disregard fillfactor if we don't have that many. * disregard fillfactor if we don't have that many.
*/ */
if (pgspc < itupsz || (pgspc < state->btps_full && last_off > P_FIRSTKEY)) if (pgspc < itupsz || (pgspc < state->btps_full && last_off > P_FIRSTKEY))
{ {

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 */ *continuescan = true; /* default assumption */
/* /*
* If the scan specifies not to return killed tuples, then we treat * If the scan specifies not to return killed tuples, then we treat a
* a killed tuple as not passing the qual. Most of the time, it's a * killed tuple as not passing the qual. Most of the time, it's a win to
* win to not bother examining the tuple's index keys, but just return * not bother examining the tuple's index keys, but just return
* immediately with continuescan = true to proceed to the next tuple. * immediately with continuescan = true to proceed to the next tuple.
* However, if this is the last tuple on the page, we should check * However, if this is the last tuple on the page, we should check the
* the index keys to prevent uselessly advancing to the next page. * index keys to prevent uselessly advancing to the next page.
*/ */
if (scan->ignore_killed_tuples && ItemIdDeleted(iid)) if (scan->ignore_killed_tuples && ItemIdDeleted(iid))
{ {
@ -580,9 +580,10 @@ _bt_checkkeys(IndexScanDesc scan,
if (offnum > P_FIRSTDATAKEY(opaque)) if (offnum > P_FIRSTDATAKEY(opaque))
return false; return false;
} }
/* /*
* OK, we want to check the keys, but we'll return FALSE even * OK, we want to check the keys, but we'll return FALSE even if the
* if the tuple passes the key tests. * tuple passes the key tests.
*/ */
tuple_valid = false; 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. * Unlike the simple-scankey case, this isn't a disallowed case.
* But it can never match. If all the earlier row comparison * But it can never match. If all the earlier row comparison
* columns are required for the scan direction, we can stop * columns are required for the scan direction, we can stop the
* the scan, because there can't be another tuple that will * scan, because there can't be another tuple that will succeed.
* succeed.
*/ */
if (subkey != (ScanKey) DatumGetPointer(skey->sk_argument)) if (subkey != (ScanKey) DatumGetPointer(skey->sk_argument))
subkey--; 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 * Tuple fails this qual. If it's a required qual for the current
* scan direction, then we can conclude no further tuples will * scan direction, then we can conclude no further tuples will pass,
* pass, either. Note we have to look at the deciding column, not * either. Note we have to look at the deciding column, not
* necessarily the first or last column of the row condition. * necessarily the first or last column of the row condition.
*/ */
if ((subkey->sk_flags & SK_BT_REQFWD) && 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 * Since this can be redone later if needed, it's treated the same as a
* as a commit-hint-bit status update for heap tuples: we mark the * commit-hint-bit status update for heap tuples: we mark the buffer dirty
* buffer dirty but don't make a WAL log entry. * but don't make a WAL log entry.
* *
* Whenever we mark anything LP_DELETEd, we also set the page's * Whenever we mark anything LP_DELETEd, we also set the page's
* BTP_HAS_GARBAGE flag, which is likewise just a hint. * 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); LockBuffer(so->currPos.buf, BUFFER_LOCK_UNLOCK);
/* /*
* Always reset the scan state, so we don't look for same items * Always reset the scan state, so we don't look for same items on other
* on other pages. * pages.
*/ */
so->numKilled = 0; so->numKilled = 0;
} }
@ -987,7 +987,8 @@ _bt_start_vacuum(Relation rel)
LWLockAcquire(BtreeVacuumLock, LW_EXCLUSIVE); LWLockAcquire(BtreeVacuumLock, LW_EXCLUSIVE);
/* Assign the next cycle ID, being careful to avoid zero */ /* Assign the next cycle ID, being careful to avoid zero */
do { do
{
result = ++(btvacinfo->cycle_ctr); result = ++(btvacinfo->cycle_ctr);
} while (result == 0); } while (result == 0);

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 * Mark the page as not containing any LP_DELETE items --- see comments in
* in _bt_delitems(). * _bt_delitems().
*/ */
opaque = (BTPageOpaque) PageGetSpecialPointer(page); opaque = (BTPageOpaque) PageGetSpecialPointer(page);
opaque->btpo_flags &= ~BTP_HAS_GARBAGE; opaque->btpo_flags &= ~BTP_HAS_GARBAGE;

Some files were not shown because too many files have changed in this diff Show More