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;
@ -44,10 +43,10 @@ extern DLLIMPORT char *Log_filename;
PG_MODULE_MAGIC; PG_MODULE_MAGIC;
Datum pg_file_write(PG_FUNCTION_ARGS); Datum pg_file_write(PG_FUNCTION_ARGS);
Datum pg_file_rename(PG_FUNCTION_ARGS); Datum pg_file_rename(PG_FUNCTION_ARGS);
Datum pg_file_unlink(PG_FUNCTION_ARGS); Datum pg_file_unlink(PG_FUNCTION_ARGS);
Datum pg_logdir_ls(PG_FUNCTION_ARGS); Datum pg_logdir_ls(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(pg_file_write); PG_FUNCTION_INFO_V1(pg_file_write);
PG_FUNCTION_INFO_V1(pg_file_rename); PG_FUNCTION_INFO_V1(pg_file_rename);
@ -56,8 +55,8 @@ PG_FUNCTION_INFO_V1(pg_logdir_ls);
typedef struct typedef struct
{ {
char *location; char *location;
DIR *dirdesc; DIR *dirdesc;
} directory_fctx; } directory_fctx;
/*----------------------- /*-----------------------
@ -68,27 +67,28 @@ 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;
if (strstr(filename, "..") != NULL) if (strstr(filename, "..") != NULL)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("No .. allowed in filenames")))); (errmsg("No .. allowed in filenames"))));
if (is_absolute_path(filename)) if (is_absolute_path(filename))
{ {
if (logAllowed && !strncmp(filename, Log_directory, strlen(Log_directory))) if (logAllowed && !strncmp(filename, Log_directory, strlen(Log_directory)))
return filename; return filename;
if (strncmp(filename, DataDir, dlen)) if (strncmp(filename, DataDir, dlen))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("Absolute path not allowed")))); (errmsg("Absolute path not allowed"))));
@ -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;
@ -111,9 +112,9 @@ static void
requireSuperuser(void) requireSuperuser(void)
{ {
if (!superuser()) if (!superuser())
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("only superuser may access generic file functions")))); (errmsg("only superuser may access generic file functions"))));
} }
@ -122,12 +123,13 @@ 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;
text *data; text *data;
int64 count = 0; int64 count = 0;
requireSuperuser(); requireSuperuser();
@ -136,16 +138,17 @@ 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,
errmsg("file %s exists", filename))); errmsg("file %s exists", filename)));
f = fopen(filename, "wb"); f = fopen(filename, "wb");
} }
else else
f = fopen(filename, "ab"); f = fopen(filename, "ab");
if (!f) if (!f)
{ {
@ -159,7 +162,7 @@ Datum pg_file_write(PG_FUNCTION_ARGS)
count = fwrite(VARDATA(data), 1, VARSIZE(data) - VARHDRSZ, f); count = fwrite(VARDATA(data), 1, VARSIZE(data) - VARHDRSZ, f);
if (count != VARSIZE(data) - VARHDRSZ) if (count != VARSIZE(data) - VARHDRSZ)
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("error writing file %s: %m", filename))); errmsg("error writing file %s: %m", filename)));
} }
@ -169,22 +172,25 @@ 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,
int rc; *fn2,
*fn3;
int rc;
requireSuperuser(); requireSuperuser();
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)
{ {
@ -192,7 +198,7 @@ Datum pg_file_rename(PG_FUNCTION_ARGS)
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("file %s not accessible: %m", fn1))); errmsg("file %s not accessible: %m", fn1)));
PG_RETURN_BOOL(false); PG_RETURN_BOOL(false);
} }
if (fn3 && access(fn2, W_OK) < 0) if (fn3 && access(fn2, W_OK) < 0)
@ -201,7 +207,7 @@ Datum pg_file_rename(PG_FUNCTION_ARGS)
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("file %s not accessible: %m", fn2))); errmsg("file %s not accessible: %m", fn2)));
PG_RETURN_BOOL(false); PG_RETURN_BOOL(false);
} }
@ -215,7 +221,7 @@ Datum pg_file_rename(PG_FUNCTION_ARGS)
if (fn3) if (fn3)
{ {
if (rename(fn2, fn3) != 0) if (rename(fn2, fn3) != 0)
{ {
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
@ -231,7 +237,7 @@ Datum pg_file_rename(PG_FUNCTION_ARGS)
{ {
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not rename %s back to %s: %m", fn3, fn2))); errmsg("could not rename %s back to %s: %m", fn3, fn2)));
} }
else else
{ {
@ -244,9 +250,9 @@ Datum pg_file_rename(PG_FUNCTION_ARGS)
} }
else if (rename(fn1, fn2) != 0) else if (rename(fn1, fn2) != 0)
{ {
ereport(WARNING, ereport(WARNING,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("renaming %s to %s %m", fn1, fn2))); errmsg("renaming %s to %s %m", fn1, fn2)));
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not rename %s to %s: %m", fn1, fn2))); errmsg("could not rename %s to %s: %m", fn1, fn2)));
@ -256,20 +262,21 @@ 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;
requireSuperuser(); requireSuperuser();
filename = absClusterPath(PG_GETARG_TEXT_P(0), false); filename = absClusterPath(PG_GETARG_TEXT_P(0), false);
if (access(filename, W_OK) < 0) if (access(filename, W_OK) < 0)
{ {
if (errno == ENOENT) if (errno == ENOENT)
PG_RETURN_BOOL(false); PG_RETURN_BOOL(false);
else else
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("file %s not accessible: %m", filename))); errmsg("file %s not accessible: %m", 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;
@ -306,17 +314,17 @@ Datum pg_logdir_ls(PG_FUNCTION_ARGS)
if (SRF_IS_FIRSTCALL()) if (SRF_IS_FIRSTCALL())
{ {
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));
if (is_absolute_path(Log_directory)) if (is_absolute_path(Log_directory))
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);
@ -330,7 +338,7 @@ Datum pg_logdir_ls(PG_FUNCTION_ARGS)
fctx->dirdesc = AllocateDir(fctx->location); fctx->dirdesc = AllocateDir(fctx->location);
if (!fctx->dirdesc) if (!fctx->dirdesc)
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("%s is not browsable: %m", fctx->location))); errmsg("%s is not browsable: %m", fctx->location)));
@ -338,47 +346,47 @@ 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);
while ((de = readdir(fctx->dirdesc)) != NULL) while ((de = readdir(fctx->dirdesc)) != NULL)
{ {
char *values[2]; char *values[2];
HeapTuple tuple; HeapTuple tuple;
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)
|| de->d_name[21] != '_' || de->d_name[21] != '_'
|| strcmp(de->d_name + 28, ".log")) || strcmp(de->d_name + 28, ".log"))
continue; continue;
values[1] = palloc(strlen(fctx->location) + strlen(de->d_name) + 2); values[1] = palloc(strlen(fctx->location) + strlen(de->d_name) + 2);
sprintf(values[1], "%s/%s", fctx->location, de->d_name); sprintf(values[1], "%s/%s", fctx->location, de->d_name);
values[0] = de->d_name + 11; /* timestamp */ values[0] = de->d_name + 11; /* timestamp */
values[0][17] = 0; values[0][17] = 0;
/* parse and decode expected timestamp */ /* parse and decode expected timestamp */
if (ParseDateTime(values[0], lowstr, MAXDATELEN, field, ftype, MAXDATEFIELDS, &nf)) if (ParseDateTime(values[0], lowstr, MAXDATELEN, field, ftype, MAXDATEFIELDS, &nf))
continue; continue;
if (DecodeDateTime(field, ftype, nf, &dtype, &date, &fsec, &tz)) if (DecodeDateTime(field, ftype, nf, &dtype, &date, &fsec, &tz))
continue; continue;
/* Seems the format fits the expected format; feed it into the tuple */ /* Seems the format fits the expected format; feed it into the tuple */

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
@ -159,7 +159,7 @@ Datum
cube_in(PG_FUNCTION_ARGS) cube_in(PG_FUNCTION_ARGS)
{ {
void *result; void *result;
char *str; char *str;
str = PG_GETARG_CSTRING(0); str = PG_GETARG_CSTRING(0);
@ -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 */
@ -178,11 +178,11 @@ cube_in(PG_FUNCTION_ARGS)
Datum Datum
cube(PG_FUNCTION_ARGS) cube(PG_FUNCTION_ARGS)
{ {
char *cstring; char *cstring;
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)));
} }
@ -192,12 +192,14 @@ cube(PG_FUNCTION_ARGS)
Datum Datum
cube_a_f8_f8(PG_FUNCTION_ARGS) cube_a_f8_f8(PG_FUNCTION_ARGS)
{ {
int i; int i;
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);
@ -205,31 +207,31 @@ cube_a_f8_f8(PG_FUNCTION_ARGS)
if (ARR_HASNULL(ur) || ARR_HASNULL(ll)) if (ARR_HASNULL(ur) || ARR_HASNULL(ll))
{ {
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR), (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
errmsg("Cannot work with NULL arrays"))); errmsg("Cannot work with NULL arrays")));
} }
dim = ARRNELEMS(ur); dim = ARRNELEMS(ur);
if (ARRNELEMS(ll) != dim) if (ARRNELEMS(ll) != dim)
{ {
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR), (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
errmsg("UR and LL arrays must be of same length"))); errmsg("UR and LL arrays must be of same length")));
} }
dur = ARRPTR(ur); dur = ARRPTR(ur);
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);
@ -241,20 +243,20 @@ cube_a_f8_f8(PG_FUNCTION_ARGS)
Datum Datum
cube_a_f8(PG_FUNCTION_ARGS) cube_a_f8(PG_FUNCTION_ARGS)
{ {
int i; int i;
int dim; int dim;
int size; int size;
NDBOX *result; NDBOX *result;
ArrayType *ur; ArrayType *ur;
double *dur; double *dur;
ur = (ArrayType *) PG_GETARG_VARLENA_P(0); ur = (ArrayType *) PG_GETARG_VARLENA_P(0);
if (ARR_HASNULL(ur)) if (ARR_HASNULL(ur))
{ {
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR), (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
errmsg("Cannot work with NULL arrays"))); errmsg("Cannot work with NULL arrays")));
} }
dim = ARRNELEMS(ur); dim = ARRNELEMS(ur);
@ -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,10 +281,13 @@ cube_a_f8(PG_FUNCTION_ARGS)
Datum Datum
cube_subset(PG_FUNCTION_ARGS) cube_subset(PG_FUNCTION_ARGS)
{ {
NDBOX *c, *result; NDBOX *c,
ArrayType *idx; *result;
int size, dim, i; ArrayType *idx;
int *dx; int size,
dim,
i;
int *dx;
c = (NDBOX *) PG_GETARG_POINTER(0); c = (NDBOX *) PG_GETARG_POINTER(0);
idx = (ArrayType *) PG_GETARG_VARLENA_P(1); idx = (ArrayType *) PG_GETARG_VARLENA_P(1);
@ -290,30 +295,30 @@ cube_subset(PG_FUNCTION_ARGS)
if (ARR_HASNULL(idx)) if (ARR_HASNULL(idx))
{ {
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR), (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
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);
@ -327,11 +332,11 @@ cube_out(PG_FUNCTION_ARGS)
int dim; int dim;
int i; int i;
int ndig; int ndig;
NDBOX *cube; NDBOX *cube;
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);
} }
@ -386,8 +391,8 @@ cube_out(PG_FUNCTION_ARGS)
Datum Datum
g_cube_consistent(PG_FUNCTION_ARGS) g_cube_consistent(PG_FUNCTION_ARGS)
{ {
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
NDBOX *query = (NDBOX *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(1))); NDBOX *query = (NDBOX *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(1)));
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
/* /*
@ -414,7 +419,7 @@ g_cube_union(PG_FUNCTION_ARGS)
NDBOX *out = (NDBOX *) NULL; NDBOX *out = (NDBOX *) NULL;
NDBOX *tmp; NDBOX *tmp;
int *sizep; int *sizep;
GistEntryVector *entryvec; GistEntryVector *entryvec;
entryvec = (GistEntryVector *) PG_GETARG_POINTER(0); entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
sizep = (int *) PG_GETARG_POINTER(1); sizep = (int *) PG_GETARG_POINTER(1);
@ -446,15 +451,15 @@ 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,17 +468,17 @@ 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);
float *result = (float *) PG_GETARG_POINTER(2); float *result = (float *) PG_GETARG_POINTER(2);
NDBOX *ud; NDBOX *ud;
double tmp1, double tmp1,
tmp2; tmp2;
ud = cube_union_v0((NDBOX *) DatumGetPointer(origentry->key), ud = cube_union_v0((NDBOX *) DatumGetPointer(origentry->key),
(NDBOX *) DatumGetPointer(newentry->key)); (NDBOX *) DatumGetPointer(newentry->key));
rt_cube_size(ud, &tmp1); rt_cube_size(ud, &tmp1);
rt_cube_size((NDBOX *) DatumGetPointer(origentry->key), &tmp2); rt_cube_size((NDBOX *) DatumGetPointer(origentry->key), &tmp2);
*result = (float) (tmp1 - tmp2); *result = (float) (tmp1 - tmp2);
@ -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);
} }
@ -493,8 +498,8 @@ g_cube_penalty (PG_FUNCTION_ARGS)
Datum Datum
g_cube_picksplit(PG_FUNCTION_ARGS) g_cube_picksplit(PG_FUNCTION_ARGS)
{ {
GistEntryVector *entryvec; GistEntryVector *entryvec;
GIST_SPLITVEC *v; GIST_SPLITVEC *v;
OffsetNumber i, OffsetNumber i,
j; j;
NDBOX *datum_alpha, NDBOX *datum_alpha,
@ -546,9 +551,9 @@ 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);
size_waste = size_union - size_inter; size_waste = size_union - 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,
bool *result; *b2;
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,17 +883,17 @@ 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 */
Datum Datum
cube_size(PG_FUNCTION_ARGS) cube_size(PG_FUNCTION_ARGS)
{ {
NDBOX *a; NDBOX *a;
int i, int i,
j; j;
double result; double result;
a = (NDBOX *) PG_GETARG_POINTER(0); a = (NDBOX *) PG_GETARG_POINTER(0);
@ -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);
@ -1266,7 +1286,7 @@ cube_is_point(PG_FUNCTION_ARGS)
{ {
int i, int i,
j; j;
NDBOX *a; NDBOX *a;
a = (NDBOX *) PG_GETARG_POINTER(0); a = (NDBOX *) PG_GETARG_POINTER(0);
@ -1283,7 +1303,7 @@ cube_is_point(PG_FUNCTION_ARGS)
Datum Datum
cube_dim(PG_FUNCTION_ARGS) cube_dim(PG_FUNCTION_ARGS)
{ {
NDBOX *c; NDBOX *c;
c = (NDBOX *) PG_GETARG_POINTER(0); c = (NDBOX *) PG_GETARG_POINTER(0);
@ -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;
} }
@ -621,8 +621,8 @@ dblink_fetch(PG_FUNCTION_ARGS)
if (PQnfields(res) != tupdesc->natts) if (PQnfields(res) != tupdesc->natts)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH), (errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("remote query result rowtype does not match " errmsg("remote query result rowtype does not match "
"the specified FROM clause rowtype"))); "the specified FROM clause rowtype")));
/* fast track when no results */ /* fast track when no results */
if (funcctx->max_calls < 1) if (funcctx->max_calls < 1)
@ -827,7 +827,7 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async, bool do_get)
if (!res || if (!res ||
(PQresultStatus(res) != PGRES_COMMAND_OK && (PQresultStatus(res) != PGRES_COMMAND_OK &&
PQresultStatus(res) != PGRES_TUPLES_OK)) PQresultStatus(res) != PGRES_TUPLES_OK))
{ {
if (fail) if (fail)
DBLINK_RES_ERROR("sql error"); DBLINK_RES_ERROR("sql error");
@ -847,12 +847,12 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async, bool do_get)
/* need a tuple descriptor representing one TEXT column */ /* need a tuple descriptor representing one TEXT column */
tupdesc = CreateTemplateTupleDesc(1, false); tupdesc = CreateTemplateTupleDesc(1, false);
TupleDescInitEntry(tupdesc, (AttrNumber) 1, "status", TupleDescInitEntry(tupdesc, (AttrNumber) 1, "status",
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;
} }
@ -878,8 +878,8 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async, bool do_get)
/* failed to determine actual type of RECORD */ /* failed to determine actual type of RECORD */
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("function returning record called in context " errmsg("function returning record called in context "
"that cannot accept type record"))); "that cannot accept type record")));
break; break;
default: default:
/* result type isn't composite */ /* result type isn't composite */
@ -891,12 +891,15 @@ 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),
errmsg("remote query result rowtype does not match " errmsg("remote query result rowtype does not match "
"the specified FROM clause rowtype"))); "the specified FROM clause rowtype")));
/* fast track when no results */ /* fast track when no results */
if (funcctx->max_calls < 1) if (funcctx->max_calls < 1)
@ -991,9 +994,9 @@ PG_FUNCTION_INFO_V1(dblink_get_connections);
Datum Datum
dblink_get_connections(PG_FUNCTION_ARGS) dblink_get_connections(PG_FUNCTION_ARGS)
{ {
HASH_SEQ_STATUS status; HASH_SEQ_STATUS status;
remoteConnHashEnt *hentry; remoteConnHashEnt *hentry;
ArrayBuildState *astate = NULL; ArrayBuildState *astate = NULL;
if (remoteConnHash) if (remoteConnHash)
{ {
@ -1019,19 +1022,19 @@ dblink_get_connections(PG_FUNCTION_ARGS)
* *
* Returns 1 if the connection is busy, 0 otherwise * Returns 1 if the connection is busy, 0 otherwise
* Params: * Params:
* text connection_name - name of the connection to check * text connection_name - name of the connection to check
* *
*/ */
PG_FUNCTION_INFO_V1(dblink_is_busy); PG_FUNCTION_INFO_V1(dblink_is_busy);
Datum Datum
dblink_is_busy(PG_FUNCTION_ARGS) dblink_is_busy(PG_FUNCTION_ARGS)
{ {
char *msg; char *msg;
PGconn *conn = NULL; PGconn *conn = NULL;
char *conname = NULL; char *conname = NULL;
char *connstr = NULL; char *connstr = NULL;
remoteConn *rconn = NULL; remoteConn *rconn = NULL;
bool freeconn = false; bool freeconn = false;
DBLINK_INIT; DBLINK_INIT;
DBLINK_GET_CONN; DBLINK_GET_CONN;
@ -1047,25 +1050,25 @@ dblink_is_busy(PG_FUNCTION_ARGS)
* *
* Returns text: * Returns text:
* "OK" if the cancel request has been sent correctly, * "OK" if the cancel request has been sent correctly,
* an error message otherwise * an error message otherwise
* *
* Params: * Params:
* text connection_name - name of the connection to check * text connection_name - name of the connection to check
* *
*/ */
PG_FUNCTION_INFO_V1(dblink_cancel_query); PG_FUNCTION_INFO_V1(dblink_cancel_query);
Datum Datum
dblink_cancel_query(PG_FUNCTION_ARGS) dblink_cancel_query(PG_FUNCTION_ARGS)
{ {
char *msg; char *msg;
int res = 0; int res = 0;
PGconn *conn = NULL; PGconn *conn = NULL;
char *conname = NULL; char *conname = NULL;
char *connstr = NULL; char *connstr = NULL;
remoteConn *rconn = NULL; remoteConn *rconn = NULL;
bool freeconn = false; bool freeconn = false;
PGcancel *cancel; PGcancel *cancel;
char errbuf[256]; char errbuf[256];
DBLINK_INIT; DBLINK_INIT;
DBLINK_GET_CONN; DBLINK_GET_CONN;
@ -1090,19 +1093,19 @@ dblink_cancel_query(PG_FUNCTION_ARGS)
* "OK" if no error, an error message otherwise * "OK" if no error, an error message otherwise
* *
* Params: * Params:
* text connection_name - name of the connection to check * text connection_name - name of the connection to check
* *
*/ */
PG_FUNCTION_INFO_V1(dblink_error_message); PG_FUNCTION_INFO_V1(dblink_error_message);
Datum Datum
dblink_error_message(PG_FUNCTION_ARGS) dblink_error_message(PG_FUNCTION_ARGS)
{ {
char *msg; char *msg;
PGconn *conn = NULL; PGconn *conn = NULL;
char *conname = NULL; char *conname = NULL;
char *connstr = NULL; char *connstr = NULL;
remoteConn *rconn = NULL; remoteConn *rconn = NULL;
bool freeconn = false; bool freeconn = false;
DBLINK_INIT; DBLINK_INIT;
DBLINK_GET_CONN; DBLINK_GET_CONN;
@ -1859,7 +1862,7 @@ get_sql_delete(Oid relid, int2vector *pkattnums, int16 pknumatts, char **tgt_pka
char *relname; char *relname;
TupleDesc tupdesc; TupleDesc tupdesc;
int natts; int natts;
StringInfoData buf; StringInfoData buf;
int i; int i;
initStringInfo(&buf); initStringInfo(&buf);

View File

@ -11,39 +11,42 @@
#include "storage/bufpage.h" #include "storage/bufpage.h"
typedef struct { typedef struct
uint16 keylen; {
uint16 vallen; uint16 keylen;
uint16 vallen;
uint32 uint32
valisnull:1, valisnull:1,
pos:31; pos:31;
} HEntry; } HEntry;
typedef struct { typedef struct
int4 len; {
int4 size; int4 len;
char data[1]; int4 size;
} HStore; char data[1];
} HStore;
#define HSHRDSIZE (2*sizeof(int4)) #define HSHRDSIZE (2*sizeof(int4))
#define CALCDATASIZE(x, lenstr) ( (x) * sizeof(HEntry) + HSHRDSIZE + (lenstr) ) #define CALCDATASIZE(x, lenstr) ( (x) * sizeof(HEntry) + HSHRDSIZE + (lenstr) )
#define ARRPTR(x) ( (HEntry*) ( (char*)(x) + HSHRDSIZE ) ) #define ARRPTR(x) ( (HEntry*) ( (char*)(x) + HSHRDSIZE ) )
#define STRPTR(x) ( (char*)(x) + HSHRDSIZE + ( sizeof(HEntry) * ((HStore*)x)->size ) ) #define STRPTR(x) ( (char*)(x) + HSHRDSIZE + ( sizeof(HEntry) * ((HStore*)x)->size ) )
#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 *val; char *key;
uint16 keylen; char *val;
uint16 vallen; uint16 keylen;
bool isnull; uint16 vallen;
bool needfree; bool isnull;
} Pairs; bool needfree;
} Pairs;
int comparePairs(const void *a, const void *b); int comparePairs(const void *a, const void *b);
int uniquePairs(Pairs * a, int4 l, int4 *buflen); int uniquePairs(Pairs * a, int4 l, int4 *buflen);
#endif #endif

View File

@ -7,8 +7,8 @@
/* bigint defines */ /* bigint defines */
#define BITBYTE 8 #define BITBYTE 8
#define SIGLENINT 4 /* >122 => key will toast, so very slow!!! */ #define SIGLENINT 4 /* >122 => key will toast, so very slow!!! */
#define SIGLEN ( sizeof(int)*SIGLENINT ) #define SIGLEN ( sizeof(int)*SIGLENINT )
#define SIGLENBIT (SIGLEN*BITBYTE) #define SIGLENBIT (SIGLEN*BITBYTE)
typedef char BITVEC[SIGLEN]; typedef char BITVEC[SIGLEN];
@ -36,22 +36,23 @@ 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 flag; int4 len;
char data[1]; int4 flag;
} GISTTYPE; char data[1];
} GISTTYPE;
#define ALLISTRUE 0x04 #define ALLISTRUE 0x04
#define ISALLTRUE(x) ( ((GISTTYPE*)x)->flag & ALLISTRUE ) #define ISALLTRUE(x) ( ((GISTTYPE*)x)->flag & ALLISTRUE )
#define GTHDRSIZE ( sizeof(int4)*2 ) #define GTHDRSIZE ( sizeof(int4)*2 )
#define CALCGTSIZE(flag) ( GTHDRSIZE+(((flag) & ALLISTRUE) ? 0 : SIGLEN) ) #define CALCGTSIZE(flag) ( GTHDRSIZE+(((flag) & ALLISTRUE) ? 0 : SIGLEN) )
#define GETSIGN(x) ( (BITVECP)( (char*)x+GTHDRSIZE ) ) #define GETSIGN(x) ( (BITVECP)( (char*)x+GTHDRSIZE ) )
#define SUMBIT(val) ( \ #define SUMBIT(val) ( \
GETBITBYTE((val),0) + \ GETBITBYTE((val),0) + \
GETBITBYTE((val),1) + \ GETBITBYTE((val),1) + \
GETBITBYTE((val),2) + \ GETBITBYTE((val),2) + \
@ -67,20 +68,22 @@ typedef struct {
#define WISH_F(a,b,c) (double)( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) ) #define WISH_F(a,b,c) (double)( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) )
PG_FUNCTION_INFO_V1(ghstore_in); PG_FUNCTION_INFO_V1(ghstore_in);
Datum ghstore_in(PG_FUNCTION_ARGS); Datum ghstore_in(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(ghstore_out); PG_FUNCTION_INFO_V1(ghstore_out);
Datum ghstore_out(PG_FUNCTION_ARGS); 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);
} }
@ -93,36 +96,41 @@ PG_FUNCTION_INFO_V1(ghstore_picksplit);
PG_FUNCTION_INFO_V1(ghstore_union); PG_FUNCTION_INFO_V1(ghstore_union);
PG_FUNCTION_INFO_V1(ghstore_same); PG_FUNCTION_INFO_V1(ghstore_same);
Datum ghstore_consistent(PG_FUNCTION_ARGS); Datum ghstore_consistent(PG_FUNCTION_ARGS);
Datum ghstore_compress(PG_FUNCTION_ARGS); Datum ghstore_compress(PG_FUNCTION_ARGS);
Datum ghstore_decompress(PG_FUNCTION_ARGS); Datum ghstore_decompress(PG_FUNCTION_ARGS);
Datum ghstore_penalty(PG_FUNCTION_ARGS); Datum ghstore_penalty(PG_FUNCTION_ARGS);
Datum ghstore_picksplit(PG_FUNCTION_ARGS); Datum ghstore_picksplit(PG_FUNCTION_ARGS);
Datum ghstore_union(PG_FUNCTION_ARGS); 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)); {
HStore *toastedval = (HStore *) DatumGetPointer(entry->key); GISTTYPE *res = (GISTTYPE *) palloc(CALCGTSIZE(0));
HStore *val = (HStore *) DatumGetPointer(PG_DETOAST_DATUM(entry->key)); HStore *toastedval = (HStore *) DatumGetPointer(entry->key);
HEntry *ptr = ARRPTR(val); HStore *val = (HStore *) DatumGetPointer(PG_DETOAST_DATUM(entry->key));
char *words = STRPTR(val); HEntry *ptr = ARRPTR(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; {
h = crc32_sz((char*)(words+ptr->pos), ptr->keylen); int h;
HASH( GETSIGN(res), h);
if ( !ptr->valisnull ) { h = crc32_sz((char *) (words + ptr->pos), ptr->keylen);
h = crc32_sz((char *)(words+ptr->pos+ptr->keylen), ptr->vallen); HASH(GETSIGN(res), h);
HASH( GETSIGN(res), h); if (!ptr->valisnull)
{
h = crc32_sz((char *) (words + ptr->pos + ptr->keylen), ptr->vallen);
HASH(GETSIGN(res), h);
} }
ptr++; ptr++;
} }
@ -135,14 +143,16 @@ 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)) ) { }
int4 i; else if (!ISALLTRUE(DatumGetPointer(entry->key)))
{
int4 i;
GISTTYPE *res; GISTTYPE *res;
BITVECP sign = GETSIGN(DatumGetPointer(entry->key)); BITVECP sign = GETSIGN(DatumGetPointer(entry->key));
LOOPBYTE( LOOPBYTE(
if ((sign[i] & 0xff) != 0xff) if ((sign[i] & 0xff) != 0xff)
PG_RETURN_POINTER(retval); PG_RETURN_POINTER(retval);
); );
res = (GISTTYPE *) palloc(CALCGTSIZE(ALLISTRUE)); res = (GISTTYPE *) palloc(CALCGTSIZE(ALLISTRUE));
@ -160,15 +170,17 @@ 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);
if (ISALLTRUE(a) && ISALLTRUE(b)) if (ISALLTRUE(a) && ISALLTRUE(b))
*result = true; *result = true;
@ -176,83 +188,97 @@ 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; {
BITVECP sa = GETSIGN(a), int4 i;
sb = GETSIGN(b); BITVECP sa = GETSIGN(a),
sb = GETSIGN(b);
*result = true; *result = true;
LOOPBYTE( LOOPBYTE(
if (sa[i] != sb[i]) { if (sa[i] != sb[i])
*result = false; {
break; *result = false;
} break;
}
); );
} }
PG_RETURN_POINTER(result); PG_RETURN_POINTER(result);
} }
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);
); );
return size; return size;
} }
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
unionkey(BITVECP sbase, GISTTYPE * add) unionkey(BITVECP sbase, GISTTYPE * add)
{ {
int4 i; int4 i;
BITVECP sadd = GETSIGN(add); BITVECP sadd = GETSIGN(add);
if (ISALLTRUE(add)) if (ISALLTRUE(add))
return 1; return 1;
LOOPBYTE( LOOPBYTE(
sbase[i] |= sadd[i]; sbase[i] |= sadd[i];
); );
return 0; return 0;
} }
Datum Datum
ghstore_union(PG_FUNCTION_ARGS) { ghstore_union(PG_FUNCTION_ARGS)
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0); {
int4 len = entryvec->n; GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
int4 len = entryvec->n;
int *size = (int *) PG_GETARG_POINTER(1); int *size = (int *) PG_GETARG_POINTER(1);
BITVEC base; BITVEC base;
int4 i; int4 i;
int4 flag = 0; int4 flag = 0;
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,64 +295,72 @@ 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;
GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1); GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
OffsetNumber k, OffsetNumber k,
j; j;
GISTTYPE *datum_l, GISTTYPE *datum_l,
*datum_r; *datum_r;
BITVECP union_l, BITVECP union_l,
union_r; union_r;
int4 size_alpha, size_beta; int4 size_alpha,
int4 size_waste, size_beta;
int4 size_waste,
waste = -1; waste = -1;
int4 nbytes; int4 nbytes;
OffsetNumber seed_1 = 0, OffsetNumber seed_1 = 0,
seed_2 = 0; seed_2 = 0;
OffsetNumber *left, OffsetNumber *left,
*right; *right;
BITVECP ptr; BITVECP ptr;
int i; int i;
SPLITCOST *costvector; SPLITCOST *costvector;
GISTTYPE *_k, GISTTYPE *_k,
*_j; *_j;
nbytes = (maxoff + 2) * sizeof(OffsetNumber); nbytes = (maxoff + 2) * sizeof(OffsetNumber);
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,50 +415,63 @@ 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];
); );
} }
*right++ = j; *right++ = j;
@ -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);
HEntry *qe = ARRPTR(query); bool res = true;
char *qv = STRPTR(query); HEntry *qe = ARRPTR(query);
BITVECP sign; char *qv = STRPTR(query);
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,27 +3,28 @@
PG_MODULE_MAGIC; PG_MODULE_MAGIC;
typedef struct { typedef struct
char *begin; {
char *ptr; char *begin;
char *cur; char *ptr;
char *word; char *cur;
int wordlen; char *word;
int wordlen;
Pairs *pairs; Pairs *pairs;
int pcur; int pcur;
int plen; int plen;
} HSParser; } HSParser;
#define RESIZEPRSBUF \ #define RESIZEPRSBUF \
do { \ do { \
if ( state->cur - state->word + 1 >= state->wordlen ) \ if ( state->cur - state->word + 1 >= state->wordlen ) \
{ \ { \
int4 clen = state->cur - state->word; \ int4 clen = state->cur - state->word; \
state->wordlen *= 2; \ state->wordlen *= 2; \
state->word = (char*)repalloc( (void*)state->word, state->wordlen ); \ state->word = (char*)repalloc( (void*)state->word, state->wordlen ); \
state->cur = state->word + clen; \ state->cur = state->word + clen; \
} \ } \
} while (0) } while (0)
@ -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; {
state->wordlen=32; int st = GV_WAITVAL;
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++;
} }
@ -112,195 +153,246 @@ get_val( HSParser *state, bool ignoreeq, bool *escaped ) {
#define WKEY 0 #define WKEY 0
#define WVAL 1 #define WVAL 1
#define WEQ 2 #define WEQ 2
#define WGT 3 #define WGT 3
#define WDEL 4 #define WDEL 4
static void static void
parse_hstore( HSParser *state ) { parse_hstore(HSParser * state)
int st = WKEY; {
bool escaped=false; int st = WKEY;
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) == ',' ) { else if (st == WDEL)
{
if (*(state->ptr) == ',')
{
st = WKEY; 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 (*(state->ptr) == '\0')
elog(ERROR,"Unknown state %d at line %d in file '%s'", st, __LINE__, __FILE__); {
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 ) { {
int res = strncmp( if (((Pairs *) a)->keylen == ((Pairs *) b)->keylen)
((Pairs*)a)->key, {
((Pairs*)b)->key, int res = strncmp(
((Pairs*)a)->keylen ((Pairs *) a)->key,
); ((Pairs *) b)->key,
if ( res ) ((Pairs *) a)->keylen
);
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; {
int4 len,buflen,i; HSParser state;
HStore *out; int4 len,
HEntry *entries; buflen,
char *ptr; i;
HStore *out;
HEntry *entries;
char *ptr;
state.begin = PG_GETARG_CSTRING(0); state.begin = PG_GETARG_CSTRING(0);
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,63 +400,74 @@ 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;
} }
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); {
int buflen,i; HStore *in = PG_GETARG_HS(0);
char *out,*ptr; int buflen,
char *base = STRPTR(in); i;
HEntry *entries = ARRPTR(in); char *out,
*ptr;
char *base = STRPTR(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 *StopHigh = StopLow + hs->size; HEntry *StopLow = ARRPTR(hs);
HEntry *StopMiddle; HEntry *StopHigh = StopLow + hs->size;
int difference; HEntry *StopMiddle;
char *base = STRPTR(hs); int difference;
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;
@ -34,405 +36,454 @@ 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); {
text *key = PG_GETARG_TEXT_P(1); HStore *hs = PG_GETARG_HS(0);
HEntry *entry; text *key = PG_GETARG_TEXT_P(1);
text *out; HEntry *entry;
text *out;
if ((entry=findkey(hs,VARDATA(key), VARSIZE(key)-VARHDRSZ))==NULL || entry->valisnull) { if ((entry = findkey(hs, VARDATA(key), VARSIZE(key) - VARHDRSZ)) == NULL || entry->valisnull)
PG_FREE_IF_COPY(hs,0); {
PG_FREE_IF_COPY(key,1); PG_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); {
text *key = PG_GETARG_TEXT_P(1); HStore *hs = PG_GETARG_HS(0);
HEntry *entry; text *key = PG_GETARG_TEXT_P(1);
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);
} }
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); {
text *key = PG_GETARG_TEXT_P(1); HStore *hs = PG_GETARG_HS(0);
HEntry *entry; text *key = PG_GETARG_TEXT_P(1);
bool res; HEntry *entry;
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);
} }
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); {
text *key = PG_GETARG_TEXT_P(1); HStore *hs = PG_GETARG_HS(0);
HStore *out = palloc(hs->len); text *key = PG_GETARG_TEXT_P(1);
char *ptrs, *ptrd; HStore *out = palloc(hs->len);
HEntry *es, *ed; char *ptrs,
*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);
} }
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 *s2 = PG_GETARG_HS(1); HStore *s1 = PG_GETARG_HS(0);
HStore *out = palloc( s1->len + s2->len ); HStore *s2 = PG_GETARG_HS(1);
char *ps1, *ps2, *pd; HStore *out = palloc(s1->len + s2->len);
HEntry *es1, *es2, *ed; char *ps1,
*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; {
if ( es1->keylen == es2->keylen ) int difference;
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);
} }
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 *val = PG_GETARG_TEXT_P(1); text *key = PG_GETARG_TEXT_P(0);
int len; text *val = PG_GETARG_TEXT_P(1);
HStore *out; int len;
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);
} }
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); {
Datum *d; HStore *hs = PG_GETARG_HS(0);
ArrayType *a; Datum *d;
HEntry *ptr=ARRPTR(hs); ArrayType *a;
char *base=STRPTR(hs); HEntry *ptr = ARRPTR(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++;
} }
a = construct_array( a = construct_array(
d, d,
hs->size, hs->size,
TEXTOID, TEXTOID,
-1, -1,
false, false,
'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);
} }
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); {
Datum *d; HStore *hs = PG_GETARG_HS(0);
ArrayType *a; Datum *d;
HEntry *ptr=ARRPTR(hs); ArrayType *a;
char *base=STRPTR(hs); HEntry *ptr = ARRPTR(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; {
text *item=(text*)palloc(VARHDRSZ + vallen); int vallen = (ptr->valisnull) ? 0 : ptr->vallen;
VARATT_SIZEP(item) = VARHDRSZ+vallen; text *item = (text *) palloc(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++;
} }
a = construct_array( a = construct_array(
d, d,
hs->size, hs->size,
TEXTOID, TEXTOID,
-1, -1,
false, false,
'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; {
int i; HStore *hs;
} AKStore; int i;
} AKStore;
static void static void
setup_firstcall(FuncCallContext *funcctx, HStore *hs) { setup_firstcall(FuncCallContext *funcctx, HStore * hs)
MemoryContext oldcontext; {
AKStore *st; MemoryContext oldcontext;
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; {
AKStore *st; FuncCallContext *funcctx;
AKStore *st;
if (SRF_IS_FIRSTCALL())
{
HStore *hs = PG_GETARG_HS(0);
if (SRF_IS_FIRSTCALL()) {
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]); {
text *item=(text*)palloc(VARHDRSZ + ptr->keylen); HEntry *ptr = &(ARRPTR(st->hs)[st->i]);
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);
} }
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; {
AKStore *st; FuncCallContext *funcctx;
AKStore *st;
if (SRF_IS_FIRSTCALL())
{
HStore *hs = PG_GETARG_HS(0);
if (SRF_IS_FIRSTCALL()) {
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++;
(funcctx)->call_cntr++; (funcctx)->call_cntr++;
rsi = (ReturnSetInfo *) fcinfo->resultinfo; rsi = (ReturnSetInfo *) fcinfo->resultinfo;
rsi->isDone = ExprMultipleResult; rsi->isDone = ExprMultipleResult;
PG_RETURN_NULL(); PG_RETURN_NULL();
} else { }
int vallen = ptr->vallen; else
text *item=(text*)palloc(VARHDRSZ + vallen); {
int vallen = ptr->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,109 +491,123 @@ svals(PG_FUNCTION_ARGS) {
} }
} }
pfree( st->hs ); pfree(st->hs);
pfree( st ); pfree(st);
SRF_RETURN_DONE(funcctx); SRF_RETURN_DONE(funcctx);
} }
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 *tmpl = PG_GETARG_HS(1); HStore *val = PG_GETARG_HS(0);
bool res = true; HStore *tmpl = PG_GETARG_HS(1);
HEntry *te = ARRPTR(tmpl); bool res = true;
char *vv = STRPTR(val); HEntry *te = ARRPTR(tmpl);
char *tv = STRPTR(tmpl); char *vv = STRPTR(val);
char *tv = STRPTR(tmpl);
while(res && te-ARRPTR(tmpl) < tmpl->size) { while (res && te - ARRPTR(tmpl) < tmpl->size)
HEntry *entry = findkey(val, tv + te->pos, te->keylen); {
if ( entry ) { HEntry *entry = findkey(val, tv + te->pos, te->keylen);
if ( ! te->valisnull ) {
if ( entry->valisnull || !( if (entry)
te->vallen==entry->vallen && {
strncmp( if (!te->valisnull)
vv + entry->pos + entry->keylen, {
tv + te->pos + te->keylen, if (entry->valisnull || !(
te->vallen ) == 0 te->vallen == entry->vallen &&
) ) strncmp(
res=false; vv + entry->pos + entry->keylen,
tv + te->pos + te->keylen,
te->vallen) == 0
))
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);
} }
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( {
hs_contains, PG_RETURN_DATUM(DirectFunctionCall2(
PG_GETARG_DATUM(1), hs_contains,
PG_GETARG_DATUM(0) PG_GETARG_DATUM(1),
)); PG_GETARG_DATUM(0)
));
} }
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; {
AKStore *st; FuncCallContext *funcctx;
AKStore *st;
if (SRF_IS_FIRSTCALL()) { if (SRF_IS_FIRSTCALL())
TupleDesc tupdesc; {
MemoryContext oldcontext; TupleDesc tupdesc;
HStore *hs = PG_GETARG_HS(0); MemoryContext oldcontext;
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]); {
Datum res, dvalues[2]; HEntry *ptr = &(ARRPTR(st->hs)[st->i]);
char nulls[] = {' ', ' '}; Datum res,
text *item; dvalues[2];
HeapTuple tuple; char nulls[] = {' ', ' '};
text *item;
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';
int vallen = ptr->vallen; }
else
{
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

@ -154,17 +154,17 @@ typedef struct
#define COMPUTESIZE(size) ( HDRSIZEQT + size * sizeof(ITEM) ) #define COMPUTESIZE(size) ( HDRSIZEQT + size * sizeof(ITEM) )
#define GETQUERY(x) (ITEM*)( (char*)(x)+HDRSIZEQT ) #define GETQUERY(x) (ITEM*)( (char*)(x)+HDRSIZEQT )
#define END 0 #define END 0
#define ERR 1 #define ERR 1
#define VAL 2 #define VAL 2
#define OPR 3 #define OPR 3
#define OPEN 4 #define OPEN 4
#define CLOSE 5 #define CLOSE 5
bool signconsistent(QUERYTYPE * query, BITVEC sign, bool calcnot); bool signconsistent(QUERYTYPE * query, BITVEC sign, bool calcnot);
bool execconsistent(QUERYTYPE * query, ArrayType *array, bool calcnot); bool execconsistent(QUERYTYPE * query, ArrayType *array, bool calcnot);
bool ginconsistent(QUERYTYPE * query, bool *check); bool ginconsistent(QUERYTYPE * query, bool *check);
int4 shorterquery(ITEM * q, int4 len); int4 shorterquery(ITEM * q, int4 len);
int compASC(const void *a, const void *b); int compASC(const void *a, const void *b);

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,38 +319,42 @@ execconsistent(QUERYTYPE * query, ArrayType *array, bool calcnot)
); );
} }
typedef struct { typedef struct
ITEM *first; {
bool *mapped_check; ITEM *first;
} GinChkVal; bool *mapped_check;
} 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; {
ITEM *items = GETQUERY(query); GinChkVal gcv;
int i, j=0; ITEM *items = GETQUERY(query);
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,
(void *) &gcv, true, (void *) &gcv, true,
checkcondition_gin checkcondition_gin
); );
} }
/* /*

View File

@ -1,102 +1,118 @@
#include "_int.h" #include "_int.h"
PG_FUNCTION_INFO_V1(ginint4_queryextract); 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); {
StrategyNumber strategy = PG_GETARG_UINT16(2); uint32 *nentries = (uint32 *) PG_GETARG_POINTER(1);
Datum *res = NULL; StrategyNumber strategy = PG_GETARG_UINT16(2);
Datum *res = NULL;
*nentries = 0; *nentries = 0;
if ( strategy == BooleanSearchStrategy ) { if (strategy == BooleanSearchStrategy)
QUERYTYPE *query = (QUERYTYPE*)PG_DETOAST_DATUM_COPY(PG_GETARG_POINTER(0)); {
ITEM *items = GETQUERY(query); QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM_COPY(PG_GETARG_POINTER(0));
int i; ITEM *items = GETQUERY(query);
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 { }
ArrayType *query = PG_GETARG_ARRAYTYPE_P(0); else
int4 *arr; {
uint32 i; ArrayType *query = PG_GETARG_ARRAYTYPE_P(0);
int4 *arr;
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); {
StrategyNumber strategy = PG_GETARG_UINT16(1); bool *check = (bool *) PG_GETARG_POINTER(0);
int res=FALSE; StrategyNumber strategy = PG_GETARG_UINT16(1);
int res = FALSE;
/* we can do not check array carefully, it's done by previous ginarrayextract call */ /*
* we can do not check array carefully, it's done by previous
* ginarrayextract call
*/
switch( strategy ) { switch (strategy)
case RTOverlapStrategyNumber: {
case RTContainedByStrategyNumber: case RTOverlapStrategyNumber:
case RTOldContainedByStrategyNumber: case RTContainedByStrategyNumber:
/* at least one element in check[] is true, so result = true */ case RTOldContainedByStrategyNumber:
/* at least one element in check[] is true, so result = true */
res = TRUE; res = TRUE;
break;
case RTSameStrategyNumber:
case RTContainsStrategyNumber:
case RTOldContainsStrategyNumber:
res = TRUE;
do {
ArrayType *query = PG_GETARG_ARRAYTYPE_P(2);
int i, nentries=ARRNELEMS(query);
for(i=0;i<nentries;i++)
if ( !check[i] ) {
res = FALSE;
break;
}
} while(0);
break;
case BooleanSearchStrategy:
do {
QUERYTYPE *query = (QUERYTYPE*)PG_DETOAST_DATUM(PG_GETARG_POINTER(2));
res = ginconsistent( query, check );
} while(0);
break; break;
default: case RTSameStrategyNumber:
elog(ERROR, "ginint4_consistent: unknown strategy number: %d", strategy); case RTContainsStrategyNumber:
} case RTOldContainsStrategyNumber:
res = TRUE;
do
{
ArrayType *query = PG_GETARG_ARRAYTYPE_P(2);
int i,
nentries = ARRNELEMS(query);
PG_RETURN_BOOL(res); for (i = 0; i < nentries; i++)
if (!check[i])
{
res = FALSE;
break;
}
} while (0);
break;
case BooleanSearchStrategy:
do
{
QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_POINTER(2));
res = ginconsistent(query, check);
} while (0);
break;
default:
elog(ERROR, "ginint4_consistent: unknown strategy number: %d", strategy);
}
PG_RETURN_BOOL(res);
} }

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);
} }
@ -156,7 +158,7 @@ g_int_compress(PG_FUNCTION_ARGS)
retval = palloc(sizeof(GISTENTRY)); retval = palloc(sizeof(GISTENTRY));
gistentryinit(*retval, PointerGetDatum(r), gistentryinit(*retval, PointerGetDatum(r),
entry->rel, entry->page, entry->offset, FALSE); entry->rel, entry->page, entry->offset, FALSE);
PG_RETURN_POINTER(retval); PG_RETURN_POINTER(retval);
} }
@ -203,7 +205,7 @@ g_int_compress(PG_FUNCTION_ARGS)
r = resize_intArrayType(r, len); r = resize_intArrayType(r, len);
retval = palloc(sizeof(GISTENTRY)); retval = palloc(sizeof(GISTENTRY));
gistentryinit(*retval, PointerGetDatum(r), gistentryinit(*retval, PointerGetDatum(r),
entry->rel, entry->page, entry->offset, FALSE); entry->rel, entry->page, entry->offset, FALSE);
PG_RETURN_POINTER(retval); PG_RETURN_POINTER(retval);
} }
else else
@ -240,7 +242,7 @@ g_int_decompress(PG_FUNCTION_ARGS)
{ {
retval = palloc(sizeof(GISTENTRY)); retval = palloc(sizeof(GISTENTRY));
gistentryinit(*retval, PointerGetDatum(in), gistentryinit(*retval, PointerGetDatum(in),
entry->rel, entry->page, entry->offset, FALSE); entry->rel, entry->page, entry->offset, FALSE);
PG_RETURN_POINTER(retval); PG_RETURN_POINTER(retval);
} }
@ -331,7 +333,7 @@ typedef struct
{ {
OffsetNumber pos; OffsetNumber pos;
float cost; float cost;
} SPLITCOST; } SPLITCOST;
static int static int
comparecost(const void *a, const void *b) comparecost(const void *a, const void *b)

View File

@ -89,22 +89,27 @@ inner_int_union(ArrayType *a, ArrayType *b)
if (!r) if (!r)
{ {
int na = ARRNELEMS(a), int na = ARRNELEMS(a),
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

@ -214,7 +214,7 @@ sizebitvec(BITVECP sign)
i; i;
LOOPBYTE( LOOPBYTE(
size += number_of_ones[(unsigned char) sign[i]]; size += number_of_ones[(unsigned char) sign[i]];
); );
return size; return size;
} }
@ -227,8 +227,8 @@ hemdistsign(BITVECP a, BITVECP b)
dist = 0; dist = 0;
LOOPBYTE( LOOPBYTE(
diff = (unsigned char) (a[i] ^ b[i]); diff = (unsigned char) (a[i] ^ b[i]);
dist += number_of_ones[diff]; dist += number_of_ones[diff];
); );
return dist; return dist;
} }
@ -318,7 +318,7 @@ 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)
@ -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,142 +6,143 @@
* 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 $
* *
*/ */
/* where the digit set begins, and how many of them are in the table */ /* where the digit set begins, and how many of them are in the table */
const unsigned EAN13_index[10][2] = { const unsigned EAN13_index[10][2] = {
{0, 6}, {0, 6},
{6, 1}, {6, 1},
{7, 1}, {7, 1},
{8, 5}, {8, 5},
{13, 20}, {13, 20},
{33, 15}, {33, 15},
{48, 19}, {48, 19},
{67, 23}, {67, 23},
{90, 17}, {90, 17},
{107, 12}, {107, 12},
}; };
const char *EAN13_range[][2] = { const char *EAN13_range[][2] = {
{"000", "019"}, /* GS1 US */ {"000", "019"}, /* GS1 US */
{"020", "029"}, /* Restricted distribution (MO defined) */ {"020", "029"}, /* Restricted distribution (MO defined) */
{"030", "039"}, /* GS1 US */ {"030", "039"}, /* GS1 US */
{"040", "049"}, /* Restricted distribution (MO defined) */ {"040", "049"}, /* Restricted distribution (MO defined) */
{"050", "059"}, /* Coupons */ {"050", "059"}, /* Coupons */
{"060", "099"}, /* GS1 US */ {"060", "099"}, /* GS1 US */
{"100", "139"}, /* GS1 US */ {"100", "139"}, /* GS1 US */
{"200", "299"}, /* Restricted distribution (MO defined) */ {"200", "299"}, /* Restricted distribution (MO defined) */
{"300", "379"}, /* GS1 France */ {"300", "379"}, /* GS1 France */
{"380", "380"}, /* GS1 Bulgaria */ {"380", "380"}, /* GS1 Bulgaria */
{"383", "383"}, /* GS1 Slovenija */ {"383", "383"}, /* GS1 Slovenija */
{"385", "385"}, /* GS1 Croatia */ {"385", "385"}, /* GS1 Croatia */
{"387", "387"}, /* GS1 BIH (Bosnia-Herzegovina) */ {"387", "387"}, /* GS1 BIH (Bosnia-Herzegovina) */
{"400", "440"}, /* GS1 Germany */ {"400", "440"}, /* GS1 Germany */
{"450", "459"}, /* GS1 Japan */ {"450", "459"}, /* GS1 Japan */
{"460", "469"}, /* GS1 Russia */ {"460", "469"}, /* GS1 Russia */
{"470", "470"}, /* GS1 Kyrgyzstan */ {"470", "470"}, /* GS1 Kyrgyzstan */
{"471", "471"}, /* GS1 Taiwan */ {"471", "471"}, /* GS1 Taiwan */
{"474", "474"}, /* GS1 Estonia */ {"474", "474"}, /* GS1 Estonia */
{"475", "475"}, /* GS1 Latvia */ {"475", "475"}, /* GS1 Latvia */
{"476", "476"}, /* GS1 Azerbaijan */ {"476", "476"}, /* GS1 Azerbaijan */
{"477", "477"}, /* GS1 Lithuania */ {"477", "477"}, /* GS1 Lithuania */
{"478", "478"}, /* GS1 Uzbekistan */ {"478", "478"}, /* GS1 Uzbekistan */
{"479", "479"}, /* GS1 Sri Lanka */ {"479", "479"}, /* GS1 Sri Lanka */
{"480", "480"}, /* GS1 Philippines */ {"480", "480"}, /* GS1 Philippines */
{"481", "481"}, /* GS1 Belarus */ {"481", "481"}, /* GS1 Belarus */
{"482", "482"}, /* GS1 Ukraine */ {"482", "482"}, /* GS1 Ukraine */
{"484", "484"}, /* GS1 Moldova */ {"484", "484"}, /* GS1 Moldova */
{"485", "485"}, /* GS1 Armenia */ {"485", "485"}, /* GS1 Armenia */
{"486", "486"}, /* GS1 Georgia */ {"486", "486"}, /* GS1 Georgia */
{"487", "487"}, /* GS1 Kazakstan */ {"487", "487"}, /* GS1 Kazakstan */
{"489", "489"}, /* GS1 Hong Kong */ {"489", "489"}, /* GS1 Hong Kong */
{"490", "499"}, /* GS1 Japan */ {"490", "499"}, /* GS1 Japan */
{"500", "509"}, /* GS1 UK */ {"500", "509"}, /* GS1 UK */
{"520", "520"}, /* GS1 Greece */ {"520", "520"}, /* GS1 Greece */
{"528", "528"}, /* GS1 Lebanon */ {"528", "528"}, /* GS1 Lebanon */
{"529", "529"}, /* GS1 Cyprus */ {"529", "529"}, /* GS1 Cyprus */
{"530", "530"}, /* GS1 Albania */ {"530", "530"}, /* GS1 Albania */
{"531", "531"}, /* GS1 MAC (FYR Macedonia) */ {"531", "531"}, /* GS1 MAC (FYR Macedonia) */
{"535", "535"}, /* GS1 Malta */ {"535", "535"}, /* GS1 Malta */
{"539", "539"}, /* GS1 Ireland */ {"539", "539"}, /* GS1 Ireland */
{"540", "549"}, /* GS1 Belgium & Luxembourg */ {"540", "549"}, /* GS1 Belgium & Luxembourg */
{"560", "560"}, /* GS1 Portugal */ {"560", "560"}, /* GS1 Portugal */
{"569", "569"}, /* GS1 Iceland */ {"569", "569"}, /* GS1 Iceland */
{"570", "579"}, /* GS1 Denmark */ {"570", "579"}, /* GS1 Denmark */
{"590", "590"}, /* GS1 Poland */ {"590", "590"}, /* GS1 Poland */
{"594", "594"}, /* GS1 Romania */ {"594", "594"}, /* GS1 Romania */
{"599", "599"}, /* GS1 Hungary */ {"599", "599"}, /* GS1 Hungary */
{"600", "601"}, /* GS1 South Africa */ {"600", "601"}, /* GS1 South Africa */
{"603", "603"}, /* GS1 Ghana */ {"603", "603"}, /* GS1 Ghana */
{"608", "608"}, /* GS1 Bahrain */ {"608", "608"}, /* GS1 Bahrain */
{"609", "609"}, /* GS1 Mauritius */ {"609", "609"}, /* GS1 Mauritius */
{"611", "611"}, /* GS1 Morocco */ {"611", "611"}, /* GS1 Morocco */
{"613", "613"}, /* GS1 Algeria */ {"613", "613"}, /* GS1 Algeria */
{"616", "616"}, /* GS1 Kenya */ {"616", "616"}, /* GS1 Kenya */
{"618", "618"}, /* GS1 Ivory Coast */ {"618", "618"}, /* GS1 Ivory Coast */
{"619", "619"}, /* GS1 Tunisia */ {"619", "619"}, /* GS1 Tunisia */
{"621", "621"}, /* GS1 Syria */ {"621", "621"}, /* GS1 Syria */
{"622", "622"}, /* GS1 Egypt */ {"622", "622"}, /* GS1 Egypt */
{"624", "624"}, /* GS1 Libya */ {"624", "624"}, /* GS1 Libya */
{"625", "625"}, /* GS1 Jordan */ {"625", "625"}, /* GS1 Jordan */
{"626", "626"}, /* GS1 Iran */ {"626", "626"}, /* GS1 Iran */
{"627", "627"}, /* GS1 Kuwait */ {"627", "627"}, /* GS1 Kuwait */
{"628", "628"}, /* GS1 Saudi Arabia */ {"628", "628"}, /* GS1 Saudi Arabia */
{"629", "629"}, /* GS1 Emirates */ {"629", "629"}, /* GS1 Emirates */
{"640", "649"}, /* GS1 Finland */ {"640", "649"}, /* GS1 Finland */
{"690", "695"}, /* GS1 China */ {"690", "695"}, /* GS1 China */
{"700", "709"}, /* GS1 Norway */ {"700", "709"}, /* GS1 Norway */
{"729", "729"}, /* GS1 Israel */ {"729", "729"}, /* GS1 Israel */
{"730", "739"}, /* GS1 Sweden */ {"730", "739"}, /* GS1 Sweden */
{"740", "740"}, /* GS1 Guatemala */ {"740", "740"}, /* GS1 Guatemala */
{"741", "741"}, /* GS1 El Salvador */ {"741", "741"}, /* GS1 El Salvador */
{"742", "742"}, /* GS1 Honduras */ {"742", "742"}, /* GS1 Honduras */
{"743", "743"}, /* GS1 Nicaragua */ {"743", "743"}, /* GS1 Nicaragua */
{"744", "744"}, /* GS1 Costa Rica */ {"744", "744"}, /* GS1 Costa Rica */
{"745", "745"}, /* GS1 Panama */ {"745", "745"}, /* GS1 Panama */
{"746", "746"}, /* GS1 Republica Dominicana */ {"746", "746"}, /* GS1 Republica Dominicana */
{"750", "750"}, /* GS1 Mexico */ {"750", "750"}, /* GS1 Mexico */
{"754", "755"}, /* GS1 Canada */ {"754", "755"}, /* GS1 Canada */
{"759", "759"}, /* GS1 Venezuela */ {"759", "759"}, /* GS1 Venezuela */
{"760", "769"}, /* GS1 Schweiz, Suisse, Svizzera */ {"760", "769"}, /* GS1 Schweiz, Suisse, Svizzera */
{"770", "770"}, /* GS1 Colombia */ {"770", "770"}, /* GS1 Colombia */
{"773", "773"}, /* GS1 Uruguay */ {"773", "773"}, /* GS1 Uruguay */
{"775", "775"}, /* GS1 Peru */ {"775", "775"}, /* GS1 Peru */
{"777", "777"}, /* GS1 Bolivia */ {"777", "777"}, /* GS1 Bolivia */
{"779", "779"}, /* GS1 Argentina */ {"779", "779"}, /* GS1 Argentina */
{"780", "780"}, /* GS1 Chile */ {"780", "780"}, /* GS1 Chile */
{"784", "784"}, /* GS1 Paraguay */ {"784", "784"}, /* GS1 Paraguay */
{"786", "786"}, /* GS1 Ecuador */ {"786", "786"}, /* GS1 Ecuador */
{"789", "790"}, /* GS1 Brasil */ {"789", "790"}, /* GS1 Brasil */
{"800", "839"}, /* GS1 Italy */ {"800", "839"}, /* GS1 Italy */
{"840", "849"}, /* GS1 Spain */ {"840", "849"}, /* GS1 Spain */
{"850", "850"}, /* GS1 Cuba */ {"850", "850"}, /* GS1 Cuba */
{"858", "858"}, /* GS1 Slovakia */ {"858", "858"}, /* GS1 Slovakia */
{"859", "859"}, /* GS1 Czech */ {"859", "859"}, /* GS1 Czech */
{"860", "860"}, /* GS1 YU (Serbia & Montenegro) */ {"860", "860"}, /* GS1 YU (Serbia & Montenegro) */
{"865", "865"}, /* GS1 Mongolia */ {"865", "865"}, /* GS1 Mongolia */
{"867", "867"}, /* GS1 North Korea */ {"867", "867"}, /* GS1 North Korea */
{"869", "869"}, /* GS1 Turkey */ {"869", "869"}, /* GS1 Turkey */
{"870", "879"}, /* GS1 Netherlands */ {"870", "879"}, /* GS1 Netherlands */
{"880", "880"}, /* GS1 South Korea */ {"880", "880"}, /* GS1 South Korea */
{"884", "884"}, /* GS1 Cambodia */ {"884", "884"}, /* GS1 Cambodia */
{"885", "885"}, /* GS1 Thailand */ {"885", "885"}, /* GS1 Thailand */
{"888", "888"}, /* GS1 Singapore */ {"888", "888"}, /* GS1 Singapore */
{"890", "890"}, /* GS1 India */ {"890", "890"}, /* GS1 India */
{"893", "893"}, /* GS1 Vietnam */ {"893", "893"}, /* GS1 Vietnam */
{"899", "899"}, /* GS1 Indonesia */ {"899", "899"}, /* GS1 Indonesia */
{"900", "919"}, /* GS1 Austria */ {"900", "919"}, /* GS1 Austria */
{"930", "939"}, /* GS1 Australia */ {"930", "939"}, /* GS1 Australia */
{"940", "949"}, /* GS1 New Zealand */ {"940", "949"}, /* GS1 New Zealand */
{"950", "950"}, /* GS1 Head Office */ {"950", "950"}, /* GS1 Head Office */
{"955", "955"}, /* GS1 Malaysia */ {"955", "955"}, /* GS1 Malaysia */
{"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)
{"980", "980"}, /* Refund receipts */ * and ISBN contingent */
{"981", "982"}, /* Common Currency Coupons */ {"980", "980"}, /* Refund receipts */
{"990", "999"}, /* Coupons */ {"981", "982"}, /* Common Currency Coupons */
{"990", "999"}, /* Coupons */
{NULL, NULL} {NULL, NULL}
}; };

View File

@ -7,39 +7,39 @@
* 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
* *
* *
* ISBN 0 3 9 3 0 4 0 0 2 * ISBN 0 3 9 3 0 4 0 0 2
* Weight 10 9 8 7 6 5 4 3 2 * Weight 10 9 8 7 6 5 4 3 2
* Product 0 + 27 + 72 + 21 + 0 + 20 + 0 + 0 + 4 = 144 * Product 0 + 27 + 72 + 21 + 0 + 20 + 0 + 0 + 4 = 144
* 144 / 11 = 13 remainder 1 * 144 / 11 = 13 remainder 1
* Check digit 11 - 1 = 10 = X * Check digit 11 - 1 = 10 = X
* => 0-393-04002-X * => 0-393-04002-X
* *
* ISBN 9 7 8 0 3 9 3 0 4 0 0 2 * ISBN 9 7 8 0 3 9 3 0 4 0 0 2
* Weight 1 3 1 3 1 3 1 3 1 3 1 3 * Weight 1 3 1 3 1 3 1 3 1 3 1 3
* Product 9 + 21 + 8 + 0 + 3 + 27 + 3 + 0 + 4 + 0 + 0 + 6 = 81 * Product 9 + 21 + 8 + 0 + 3 + 27 + 3 + 0 + 4 + 0 + 0 + 6 = 81
* 81 / 10 = 8 remainder 1 * 81 / 10 = 8 remainder 1
* Check digit 10 - 1 = 9 * Check digit 10 - 1 = 9
* => 978-0-393-04002-9 * => 978-0-393-04002-9
* *
*/ */
/* where the digit set begins, and how many of them are in the table */ /* where the digit set begins, and how many of them are in the table */
const unsigned ISBN_index[10][2] = { const unsigned ISBN_index[10][2] = {
{0, 6}, {0, 6},
{6, 6}, {6, 6},
{12, 8}, {12, 8},
{20, 10}, {20, 10},
{30, 6}, {30, 6},
{36, 12}, {36, 12},
{48, 0}, {48, 0},
{48, 5}, {48, 5},
{53, 59}, {53, 59},
{112, 573}, {112, 573},
}; };
const char *ISBN_range[][2] = { const char *ISBN_range[][2] = {

View File

@ -6,23 +6,23 @@
* 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
* *
* (M counts as 3) * (M counts as 3)
* ISMN M 3 4 5 2 4 6 8 0 * ISMN M 3 4 5 2 4 6 8 0
* Weight 3 1 3 1 3 1 3 1 3 * Weight 3 1 3 1 3 1 3 1 3
* Product 9 + 3 + 12 + 5 + 6 + 4 + 18 + 8 + 0 = 65 * Product 9 + 3 + 12 + 5 + 6 + 4 + 18 + 8 + 0 = 65
* 65 / 10 = 6 remainder 5 * 65 / 10 = 6 remainder 5
* Check digit 10 - 5 = 5 * Check digit 10 - 5 = 5
* => M-3452-4680-5 * => M-3452-4680-5
* *
* ISMN 9 7 9 0 3 4 5 2 4 6 8 0 * ISMN 9 7 9 0 3 4 5 2 4 6 8 0
* Weight 1 3 1 3 1 3 1 3 1 3 1 3 * Weight 1 3 1 3 1 3 1 3 1 3 1 3
* Product 9 + 21 + 9 + 0 + 3 + 12 + 5 + 6 + 4 + 18 + 8 + 0 = 95 * Product 9 + 21 + 9 + 0 + 3 + 12 + 5 + 6 + 4 + 18 + 8 + 0 = 95
* 95 / 10 = 9 remainder 5 * 95 / 10 = 9 remainder 5
* Check digit 10 - 5 = 5 * Check digit 10 - 5 = 5
* => 979-0-3452-4680-5 * => 979-0-3452-4680-5
* *
* Since mod10(9*1 + 7*3 + 9*1 + 0*3) = mod10(M*3) = mod10(3*3) = 9; the check digit remains the same. * Since mod10(9*1 + 7*3 + 9*1 + 0*3) = mod10(M*3) = mod10(3*3) = 9; the check digit remains the same.
@ -31,16 +31,16 @@
/* where the digit set begins, and how many of them are in the table */ /* where the digit set begins, and how many of them are in the table */
const unsigned ISMN_index[10][2] = { const unsigned ISMN_index[10][2] = {
{0, 5}, {0, 5},
{5, 0}, {5, 0},
{5, 0}, {5, 0},
{5, 0}, {5, 0},
{5, 0}, {5, 0},
{5, 0}, {5, 0},
{5, 0}, {5, 0},
{5, 0}, {5, 0},
{5, 0}, {5, 0},
{5, 0}, {5, 0},
}; };
const char *ISMN_range[][2] = { const char *ISMN_range[][2] = {
{"0-000", "0-099"}, {"0-000", "0-099"},

View File

@ -6,25 +6,25 @@
* 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
* *
* *
* ISSN 1 1 4 4 8 7 5 * ISSN 1 1 4 4 8 7 5
* Weight 8 7 6 5 4 3 2 * Weight 8 7 6 5 4 3 2
* Product 8 + 7 + 24 + 20 + 32 + 21 + 10 = 122 * Product 8 + 7 + 24 + 20 + 32 + 21 + 10 = 122
* 122 / 11 = 11 remainder 1 * 122 / 11 = 11 remainder 1
* Check digit 11 - 1 = 10 = X * Check digit 11 - 1 = 10 = X
* => 1144-875X * => 1144-875X
* *
* ISSN 9 7 7 1 1 4 4 8 7 5 0 0 * ISSN 9 7 7 1 1 4 4 8 7 5 0 0
* Weight 1 3 1 3 1 3 1 3 1 3 1 3 * Weight 1 3 1 3 1 3 1 3 1 3 1 3
* Product 9 + 21 + 7 + 3 + 1 + 12 + 4 + 24 + 7 + 15 + 0 + 0 = 103 * Product 9 + 21 + 7 + 3 + 1 + 12 + 4 + 24 + 7 + 15 + 0 + 0 = 103
* 103 / 10 = 10 remainder 3 * 103 / 10 = 10 remainder 3
* Check digit 10 - 3 = 7 * Check digit 10 - 3 = 7
* => 977-1144875-00-7 ?? <- suplemental number (number of the week, month, etc.) * => 977-1144875-00-7 ?? <- suplemental number (number of the week, month, etc.)
* ^^ 00 for non-daily publications (01=Monday, 02=Tuesday, ...) * ^^ 00 for non-daily publications (01=Monday, 02=Tuesday, ...)
* *
* The hyphenation is always in after the four digits of the ISSN code. * The hyphenation is always in after the four digits of the ISSN code.
* *
@ -32,16 +32,16 @@
/* where the digit set begins, and how many of them are in the table */ /* where the digit set begins, and how many of them are in the table */
const unsigned ISSN_index[10][2] = { const unsigned ISSN_index[10][2] = {
{0, 1}, {0, 1},
{0, 1}, {0, 1},
{0, 1}, {0, 1},
{0, 1}, {0, 1},
{0, 1}, {0, 1},
{0, 1}, {0, 1},
{0, 1}, {0, 1},
{0, 1}, {0, 1},
{0, 1}, {0, 1},
{0, 1}, {0, 1},
}; };
const char *ISSN_range[][2] = { const char *ISSN_range[][2] = {
{"0000-000", "9999-999"}, {"0000-000", "9999-999"},

View File

@ -6,22 +6,22 @@
* *
* *
* 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 $
* *
*/ */
/* where the digit set begins, and how many of them are in the table */ /* where the digit set begins, and how many of them are in the table */
const unsigned UPC_index[10][2] = { const unsigned UPC_index[10][2] = {
{0, 0}, {0, 0},
{0, 0}, {0, 0},
{0, 0}, {0, 0},
{0, 0}, {0, 0},
{0, 0}, {0, 0},
{0, 0}, {0, 0},
{0, 0}, {0, 0},
{0, 0}, {0, 0},
{0, 0}, {0, 0},
{0, 0}, {0, 0},
}; };
const char *UPC_range[][2] = { const char *UPC_range[][2] = {
{NULL, NULL} {NULL, NULL}

File diff suppressed because it is too large Load Diff

View File

@ -219,7 +219,7 @@ sizebitvec(BITVECP sign)
i; i;
ALOOPBYTE( ALOOPBYTE(
size += number_of_ones[(unsigned char) sign[i]]; size += number_of_ones[(unsigned char) sign[i]];
); );
return size; return size;
} }
@ -232,8 +232,8 @@ hemdistsign(BITVECP a, BITVECP b)
dist = 0; dist = 0;
ALOOPBYTE( ALOOPBYTE(
diff = (unsigned char) (a[i] ^ b[i]); diff = (unsigned char) (a[i] ^ b[i]);
dist += number_of_ones[diff]; dist += number_of_ones[diff];
); );
return dist; return dist;
} }
@ -270,7 +270,7 @@ 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)
@ -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__
@ -163,7 +163,7 @@ bool compare_subnode(ltree_level * t, char *q, int len,
ltree *lca_inner(ltree ** a, int len); ltree *lca_inner(ltree ** a, int len);
#define PG_GETARG_LTREE(x) ((ltree*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(x)))) #define PG_GETARG_LTREE(x) ((ltree*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(x))))
#define PG_GETARG_LTREE_COPY(x) ((ltree*)DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(x)))) #define PG_GETARG_LTREE_COPY(x) ((ltree*)DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(x))))
#define PG_GETARG_LQUERY(x) ((lquery*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(x)))) #define PG_GETARG_LQUERY(x) ((lquery*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(x))))
#define PG_GETARG_LQUERY_COPY(x) ((lquery*)DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(x)))) #define PG_GETARG_LQUERY_COPY(x) ((lquery*)DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(x))))
#define PG_GETARG_LTXTQUERY(x) ((ltxtquery*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(x)))) #define PG_GETARG_LTXTQUERY(x) ((ltxtquery*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(x))))

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;
} }
@ -466,9 +468,9 @@ copy_ltree( ltree *src ) {
static bool static bool
gist_ischild(ltree_gist * key, ltree * query) gist_ischild(ltree_gist * key, ltree * query)
{ {
ltree *left = copy_ltree(LTG_GETLNODE(key)); ltree *left = copy_ltree(LTG_GETLNODE(key));
ltree *right = copy_ltree(LTG_GETRNODE(key)); ltree *right = copy_ltree(LTG_GETRNODE(key));
bool res = true; bool res = true;
if (left->numlevel > query->numlevel) if (left->numlevel > query->numlevel)
left->numlevel = query->numlevel; left->numlevel = query->numlevel;
@ -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"
@ -74,7 +74,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
if (SRF_IS_FIRSTCALL()) if (SRF_IS_FIRSTCALL())
{ {
int i; int i;
volatile BufferDesc *bufHdr; volatile BufferDesc *bufHdr;
funcctx = SRF_FIRSTCALL_INIT(); funcctx = SRF_FIRSTCALL_INIT();
@ -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"
@ -14,13 +14,13 @@
#include "storage/freespace.h" #include "storage/freespace.h"
#define NUM_FREESPACE_PAGES_ELEM 5 #define NUM_FREESPACE_PAGES_ELEM 5
#define NUM_FREESPACE_RELATIONS_ELEM 7 #define NUM_FREESPACE_RELATIONS_ELEM 7
#if defined(WIN32) || defined(__CYGWIN__) #if defined(WIN32) || defined(__CYGWIN__)
/* Need DLLIMPORT for some things that are not so marked in main headers */ /* Need DLLIMPORT for some things that are not so marked in main headers */
extern DLLIMPORT int MaxFSMPages; extern DLLIMPORT int MaxFSMPages;
extern DLLIMPORT int MaxFSMRelations; extern DLLIMPORT int MaxFSMRelations;
extern DLLIMPORT volatile uint32 InterruptHoldoffCount; extern DLLIMPORT volatile uint32 InterruptHoldoffCount;
#endif #endif
@ -35,12 +35,12 @@ Datum pg_freespacemap_relations(PG_FUNCTION_ARGS);
*/ */
typedef struct typedef struct
{ {
Oid reltablespace; Oid reltablespace;
Oid reldatabase; Oid reldatabase;
Oid relfilenode; Oid relfilenode;
BlockNumber relblocknumber; BlockNumber relblocknumber;
Size bytes; Size bytes;
bool isindex; bool isindex;
} FreeSpacePagesRec; } FreeSpacePagesRec;
@ -49,14 +49,14 @@ typedef struct
*/ */
typedef struct typedef struct
{ {
Oid reltablespace; Oid reltablespace;
Oid reldatabase; Oid reldatabase;
Oid relfilenode; Oid relfilenode;
Size avgrequest; Size avgrequest;
BlockNumber interestingpages; BlockNumber interestingpages;
int storedpages; int storedpages;
int nextpage; int nextpage;
bool isindex; bool isindex;
} FreeSpaceRelationsRec; } FreeSpaceRelationsRec;
@ -66,8 +66,8 @@ typedef struct
*/ */
typedef struct typedef struct
{ {
TupleDesc tupdesc; TupleDesc tupdesc;
FreeSpacePagesRec *record; FreeSpacePagesRec *record;
} FreeSpacePagesContext; } FreeSpacePagesContext;
@ -76,8 +76,8 @@ typedef struct
*/ */
typedef struct typedef struct
{ {
TupleDesc tupdesc; TupleDesc tupdesc;
FreeSpaceRelationsRec *record; FreeSpaceRelationsRec *record;
} FreeSpaceRelationsContext; } FreeSpaceRelationsContext;
@ -89,20 +89,20 @@ PG_FUNCTION_INFO_V1(pg_freespacemap_pages);
Datum Datum
pg_freespacemap_pages(PG_FUNCTION_ARGS) pg_freespacemap_pages(PG_FUNCTION_ARGS)
{ {
FuncCallContext *funcctx; FuncCallContext *funcctx;
Datum result; Datum result;
MemoryContext oldcontext; MemoryContext oldcontext;
FreeSpacePagesContext *fctx; /* User function context. */ FreeSpacePagesContext *fctx; /* User function context. */
TupleDesc tupledesc; TupleDesc tupledesc;
HeapTuple tuple; HeapTuple tuple;
FSMHeader *FreeSpaceMap; /* FSM main structure. */ FSMHeader *FreeSpaceMap; /* FSM main structure. */
FSMRelation *fsmrel; /* Individual relation. */ FSMRelation *fsmrel; /* Individual relation. */
if (SRF_IS_FIRSTCALL()) if (SRF_IS_FIRSTCALL())
{ {
int i; int i;
int numPages; /* Max possible no. of pages in map. */ int numPages; /* Max possible no. of pages in map. */
int nPages; /* Mapped pages for a relation. */ int nPages; /* Mapped pages for a relation. */
/* /*
* Get the free space map data structure. * Get the free space map data structure.
@ -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);
@ -216,7 +216,7 @@ pg_freespacemap_pages(PG_FUNCTION_ARGS)
if (funcctx->call_cntr < funcctx->max_calls) if (funcctx->call_cntr < funcctx->max_calls)
{ {
int i = funcctx->call_cntr; int i = funcctx->call_cntr;
FreeSpacePagesRec *record = &fctx->record[i]; FreeSpacePagesRec *record = &fctx->record[i];
Datum values[NUM_FREESPACE_PAGES_ELEM]; Datum values[NUM_FREESPACE_PAGES_ELEM];
bool nulls[NUM_FREESPACE_PAGES_ELEM]; bool nulls[NUM_FREESPACE_PAGES_ELEM];
@ -261,19 +261,19 @@ PG_FUNCTION_INFO_V1(pg_freespacemap_relations);
Datum Datum
pg_freespacemap_relations(PG_FUNCTION_ARGS) pg_freespacemap_relations(PG_FUNCTION_ARGS)
{ {
FuncCallContext *funcctx; FuncCallContext *funcctx;
Datum result; Datum result;
MemoryContext oldcontext; MemoryContext oldcontext;
FreeSpaceRelationsContext *fctx; /* User function context. */ FreeSpaceRelationsContext *fctx; /* User function context. */
TupleDesc tupledesc; TupleDesc tupledesc;
HeapTuple tuple; HeapTuple tuple;
FSMHeader *FreeSpaceMap; /* FSM main structure. */ FSMHeader *FreeSpaceMap; /* FSM main structure. */
FSMRelation *fsmrel; /* Individual relation. */ FSMRelation *fsmrel; /* Individual relation. */
if (SRF_IS_FIRSTCALL()) if (SRF_IS_FIRSTCALL())
{ {
int i; int i;
int numRelations; /* Max no. of Relations in map. */ int numRelations; /* Max no. of Relations in map. */
/* /*
* Get the free space map data structure. * Get the free space map data structure.
@ -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;
@ -358,7 +358,7 @@ pg_freespacemap_relations(PG_FUNCTION_ARGS)
if (funcctx->call_cntr < funcctx->max_calls) if (funcctx->call_cntr < funcctx->max_calls)
{ {
int i = funcctx->call_cntr; int i = funcctx->call_cntr;
FreeSpaceRelationsRec *record = &fctx->record[i]; FreeSpaceRelationsRec *record = &fctx->record[i];
Datum values[NUM_FREESPACE_RELATIONS_ELEM]; Datum values[NUM_FREESPACE_RELATIONS_ELEM];
bool nulls[NUM_FREESPACE_RELATIONS_ELEM]; bool nulls[NUM_FREESPACE_RELATIONS_ELEM];
@ -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

@ -307,7 +307,7 @@ sizebitvec(BITVECP sign)
i; i;
LOOPBYTE( LOOPBYTE(
size += number_of_ones[(unsigned char) sign[i]]; size += number_of_ones[(unsigned char) sign[i]];
); );
return size; return size;
} }
@ -320,8 +320,8 @@ hemdistsign(BITVECP a, BITVECP b)
dist = 0; dist = 0;
LOOPBYTE( LOOPBYTE(
diff = (unsigned char) (a[i] ^ b[i]); diff = (unsigned char) (a[i] ^ b[i]);
dist += number_of_ones[diff]; dist += number_of_ones[diff];
); );
return dist; return dist;
} }
@ -393,7 +393,7 @@ 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)

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
@ -136,7 +136,7 @@ int num_files; /* its number */
static char *tpc_b = { static char *tpc_b = {
"\\set nbranches :scale\n" "\\set nbranches :scale\n"
"\\set ntellers 10 * :scale\n" "\\set ntellers 10 * :scale\n"
"\\set naccounts 100000 * :scale\n" "\\set naccounts 100000 * :scale\n"
"\\setrandom aid 1 :naccounts\n" "\\setrandom aid 1 :naccounts\n"
"\\setrandom bid 1 :nbranches\n" "\\setrandom bid 1 :nbranches\n"
"\\setrandom tid 1 :ntellers\n" "\\setrandom tid 1 :ntellers\n"
@ -154,7 +154,7 @@ static char *tpc_b = {
static char *simple_update = { static char *simple_update = {
"\\set nbranches :scale\n" "\\set nbranches :scale\n"
"\\set ntellers 10 * :scale\n" "\\set ntellers 10 * :scale\n"
"\\set naccounts 100000 * :scale\n" "\\set naccounts 100000 * :scale\n"
"\\setrandom aid 1 :naccounts\n" "\\setrandom aid 1 :naccounts\n"
"\\setrandom bid 1 :nbranches\n" "\\setrandom bid 1 :nbranches\n"
"\\setrandom tid 1 :ntellers\n" "\\setrandom tid 1 :ntellers\n"
@ -168,7 +168,7 @@ static char *simple_update = {
/* -S case */ /* -S case */
static char *select_only = { static char *select_only = {
"\\set naccounts 100000 * :scale\n" "\\set naccounts 100000 * :scale\n"
"\\setrandom aid 1 :naccounts\n" "\\setrandom aid 1 :naccounts\n"
"SELECT abalance FROM accounts WHERE aid = :aid;\n" "SELECT abalance FROM accounts WHERE aid = :aid;\n"
}; };
@ -338,7 +338,7 @@ putVariable(CState * st, char *name, char *value)
} }
else else
{ {
char *val; char *val;
if ((val = strdup(value)) == NULL) if ((val = strdup(value)) == NULL)
return false; return false;
@ -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;
@ -1530,7 +1532,7 @@ main(int argc, char **argv)
if (state[i].ecnt > prev_ecnt && commands[state[i].state]->type == META_COMMAND) if (state[i].ecnt > prev_ecnt && commands[state[i].state]->type == META_COMMAND)
{ {
fprintf(stderr, "Client %d aborted in state %d. Execution meta-command failed.\n", i, state[i].state); fprintf(stderr, "Client %d aborted in state %d. Execution meta-command failed.\n", i, state[i].state);
remains--; /* I've aborted */ remains--; /* I've aborted */
PQfinish(state[i].con); PQfinish(state[i].con);
state[i].con = NULL; state[i].con = NULL;
} }
@ -1610,7 +1612,7 @@ main(int argc, char **argv)
if (state[i].ecnt > prev_ecnt && commands[state[i].state]->type == META_COMMAND) if (state[i].ecnt > prev_ecnt && commands[state[i].state]->type == META_COMMAND)
{ {
fprintf(stderr, "Client %d aborted in state %d. Execution meta-command failed.\n", i, state[i].state); fprintf(stderr, "Client %d aborted in state %d. Execution meta-command failed.\n", i, state[i].state);
remains--; /* I've aborted */ remains--; /* I've aborted */
PQfinish(state[i].con); PQfinish(state[i].con);
state[i].con = NULL; state[i].con = NULL;
} }

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"
@ -24,7 +24,7 @@ static const char _crypt_a64[] =
static void static void
_crypt_to64(char *s, unsigned long v, int n) _crypt_to64(char *s, unsigned long v, int n)
{ {
while (--n >= 0) while (--n >= 0)
{ {
*s++ = _crypt_a64[v & 0x3f]; *s++ = _crypt_a64[v & 0x3f];
v >>= 6; v >>= 6;

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"
@ -365,8 +365,8 @@ rekey(FState * st)
static void static void
startup_tricks(FState * st) startup_tricks(FState * st)
{ {
int i; int i;
uint8 buf[BLOCK]; uint8 buf[BLOCK];
/* Use next block as counter. */ /* Use next block as counter. */
encrypt_counter(st, st->counter); encrypt_counter(st, st->counter);

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
/* /*
Name: imath.h Name: imath.h
Purpose: Arbitrary precision integer arithmetic routines. Purpose: Arbitrary precision integer arithmetic routines.
Author: M. J. Fromberger <http://www.dartmouth.edu/~sting/> Author: M. J. Fromberger <http://www.dartmouth.edu/~sting/>
Info: Id: imath.h 21 2006-04-02 18:58:36Z sting Info: Id: imath.h 21 2006-04-02 18:58:36Z sting
Copyright (C) 2002 Michael J. Fromberger, All Rights Reserved. Copyright (C) 2002 Michael J. Fromberger, All Rights Reserved.
@ -20,13 +20,13 @@
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
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_
@ -36,32 +36,36 @@
#include <limits.h> #include <limits.h>
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_WORD_MAX 0xFFFFFFFFFFFFFFFFULL #define MP_DIGIT_MAX 0xFFFFFFFFULL
#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_WORD_MAX 0xFFFFFFFFUL #define MP_DIGIT_MAX 0xFFFFUL
#define MP_WORD_MAX 0xFFFFFFFFUL
#endif #endif
typedef struct mpz { typedef struct mpz
mp_digit *digits; {
mp_size alloc; mp_digit *digits;
mp_size used; mp_size alloc;
mp_sign sign; mp_size used;
} mpz_t, *mp_int; mp_sign sign;
} mpz_t, *mp_int;
#define MP_DIGITS(Z) ((Z)->digits) #define MP_DIGITS(Z) ((Z)->digits)
#define MP_ALLOC(Z) ((Z)->alloc) #define MP_ALLOC(Z) ((Z)->alloc)
#define MP_USED(Z) ((Z)->used) #define MP_USED(Z) ((Z)->used)
#define MP_SIGN(Z) ((Z)->sign) #define MP_SIGN(Z) ((Z)->sign)
extern const mp_result MP_OK; extern const mp_result MP_OK;
extern const mp_result MP_FALSE; extern const mp_result MP_FALSE;
@ -72,131 +76,140 @@ extern const mp_result MP_UNDEF;
extern const mp_result MP_TRUNC; extern const mp_result MP_TRUNC;
extern const mp_result MP_BADARG; extern const mp_result MP_BADARG;
#define MP_DIGIT_BIT (sizeof(mp_digit) * CHAR_BIT) #define MP_DIGIT_BIT (sizeof(mp_digit) * CHAR_BIT)
#define MP_WORD_BIT (sizeof(mp_word) * CHAR_BIT) #define MP_WORD_BIT (sizeof(mp_word) * CHAR_BIT)
#define MP_MIN_RADIX 2 #define MP_MIN_RADIX 2
#define MP_MAX_RADIX 36 #define MP_MAX_RADIX 36
extern const mp_sign MP_NEG; extern const mp_sign MP_NEG;
extern const mp_sign MP_ZPOS; extern const mp_sign MP_ZPOS;
#define mp_int_is_odd(Z) ((Z)->digits[0] & 1) #define mp_int_is_odd(Z) ((Z)->digits[0] & 1)
#define mp_int_is_even(Z) !((Z)->digits[0] & 1) #define mp_int_is_even(Z) !((Z)->digits[0] & 1)
mp_size mp_get_default_precision(void); mp_size mp_get_default_precision(void);
void mp_set_default_precision(mp_size s); void mp_set_default_precision(mp_size s);
mp_size mp_get_multiply_threshold(void); mp_size mp_get_multiply_threshold(void);
void mp_set_multiply_threshold(mp_size s); void mp_set_multiply_threshold(mp_size s);
mp_result mp_int_init(mp_int z); mp_result mp_int_init(mp_int z);
mp_int mp_int_alloc(void); mp_int mp_int_alloc(void);
mp_result mp_int_init_size(mp_int z, mp_size prec); mp_result mp_int_init_size(mp_int z, mp_size prec);
mp_result mp_int_init_copy(mp_int z, mp_int old); mp_result mp_int_init_copy(mp_int z, mp_int old);
mp_result mp_int_init_value(mp_int z, int value); mp_result mp_int_init_value(mp_int z, int value);
mp_result mp_int_set_value(mp_int z, int value); mp_result mp_int_set_value(mp_int z, int value);
void mp_int_clear(mp_int z); void mp_int_clear(mp_int z);
void mp_int_free(mp_int z); void mp_int_free(mp_int z);
mp_result mp_int_copy(mp_int a, mp_int c); /* c = a */
void mp_int_swap(mp_int a, mp_int c); /* swap a, c */
void mp_int_zero(mp_int z); /* z = 0 */
mp_result mp_int_abs(mp_int a, mp_int c); /* c = |a| */
mp_result mp_int_neg(mp_int a, mp_int c); /* c = -a */
mp_result mp_int_add(mp_int a, mp_int b, mp_int c); /* c = a + b */
mp_result mp_int_add_value(mp_int a, int value, mp_int c);
mp_result mp_int_sub(mp_int a, mp_int b, mp_int c); /* c = a - b */
mp_result mp_int_sub_value(mp_int a, int value, mp_int c);
mp_result mp_int_mul(mp_int a, mp_int b, mp_int c); /* c = a * b */
mp_result mp_int_mul_value(mp_int a, int value, mp_int c);
mp_result mp_int_mul_pow2(mp_int a, int p2, mp_int c);
mp_result mp_int_sqr(mp_int a, mp_int c); /* c = a * a */
mp_result
mp_int_div(mp_int a, mp_int b, /* q = a / b */
mp_int q, mp_int r); /* r = a % b */
mp_result
mp_int_div_value(mp_int a, int value, /* q = a / value */
mp_int q, int *r); /* r = a % value */
mp_result
mp_int_div_pow2(mp_int a, int p2, /* q = a / 2^p2 */
mp_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_copy(mp_int a, mp_int c); /* c = a */
void mp_int_swap(mp_int a, mp_int c); /* swap a, c */
void mp_int_zero(mp_int z); /* z = 0 */
mp_result mp_int_abs(mp_int a, mp_int c); /* c = |a| */
mp_result mp_int_neg(mp_int a, mp_int c); /* c = -a */
mp_result mp_int_add(mp_int a, mp_int b, mp_int c); /* c = a + b */
mp_result mp_int_add_value(mp_int a, int value, mp_int c);
mp_result mp_int_sub(mp_int a, mp_int b, mp_int c); /* c = a - b */
mp_result mp_int_sub_value(mp_int a, int value, mp_int c);
mp_result mp_int_mul(mp_int a, mp_int b, mp_int c); /* c = a * b */
mp_result mp_int_mul_value(mp_int a, int value, mp_int c);
mp_result mp_int_mul_pow2(mp_int a, int p2, mp_int c);
mp_result mp_int_sqr(mp_int a, mp_int c); /* c = a * a */
mp_result mp_int_div(mp_int a, mp_int b, /* q = a / b */
mp_int q, mp_int r); /* r = a % b */
mp_result mp_int_div_value(mp_int a, int value, /* q = a / value */
mp_int q, int *r); /* r = a % value */
mp_result mp_int_div_pow2(mp_int a, int p2, /* q = a / 2^p2 */
mp_int q, mp_int r); /* r = q % 2^p2 */
mp_result mp_int_mod(mp_int a, mp_int m, mp_int c); /* c = a % m */
#define mp_int_mod_value(A, V, R) mp_int_div_value((A), (V), 0, (R)) #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 */
int mp_int_compare(mp_int a, mp_int b); /* a <=> b */ int mp_int_compare(mp_int a, mp_int b); /* a <=> b */
int mp_int_compare_unsigned(mp_int a, mp_int b); /* |a| <=> |b| */ int mp_int_compare_unsigned(mp_int a, mp_int b); /* |a| <=> |b| */
int mp_int_compare_zero(mp_int z); /* a <=> 0 */ int mp_int_compare_zero(mp_int z); /* a <=> 0 */
int mp_int_compare_value(mp_int z, int value); /* a <=> v */ int mp_int_compare_value(mp_int z, int value); /* a <=> v */
/* Returns true if v|a, false otherwise (including errors) */ /* Returns true if v|a, false otherwise (including errors) */
int mp_int_divisible_value(mp_int a, int v); 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 c); /* c = a^b (mod m) */ mp_int_exptmod(mp_int a, mp_int b, mp_int m,
mp_result mp_int_exptmod_evalue(mp_int a, int value, mp_int c); /* c = a^b (mod m) */
mp_int m, mp_int c); /* c = a^v (mod m) */ mp_result
mp_result mp_int_exptmod_bvalue(int value, mp_int b, mp_int_exptmod_evalue(mp_int a, int value,
mp_int m, mp_int c); /* c = v^b (mod m) */ mp_int m, mp_int c); /* c = a^v (mod m) */
mp_result mp_int_exptmod_known(mp_int a, mp_int b, mp_result
mp_int m, mp_int mu, mp_int_exptmod_bvalue(int value, mp_int b,
mp_int c); /* c = a^b (mod m) */ mp_int m, mp_int c); /* c = v^b (mod m) */
mp_result mp_int_redux_const(mp_int m, mp_int c); mp_result
mp_int_exptmod_known(mp_int a, mp_int b,
mp_int m, mp_int mu,
mp_int c); /* c = a^b (mod m) */
mp_result mp_int_redux_const(mp_int m, mp_int c);
mp_result mp_int_invmod(mp_int a, mp_int m, mp_int c); /* c = 1/a (mod m) */ 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 x, mp_int y); /* c = ax + by */ mp_int_egcd(mp_int a, mp_int b, mp_int c, /* c = gcd(a, b) */
mp_int x, mp_int y); /* c = ax + by */
mp_result mp_int_sqrt(mp_int a, mp_int c); /* c = floor(sqrt(q)) */ mp_result mp_int_sqrt(mp_int a, mp_int c); /* c = floor(sqrt(q)) */
/* Convert to an int, if representable (returns MP_RANGE if not). */ /* Convert to an int, if representable (returns MP_RANGE if not). */
mp_result mp_int_to_int(mp_int z, int *out); mp_result mp_int_to_int(mp_int z, int *out);
/* Convert to nul-terminated string with the specified radix, writing at /* Convert to nul-terminated string with the specified radix, writing at
most limit characters including the nul terminator */ most limit characters including the nul terminator */
mp_result mp_int_to_string(mp_int z, mp_size radix, mp_result mp_int_to_string(mp_int z, mp_size radix,
char *str, int limit); char *str, int limit);
/* Return the number of characters required to represent /* Return the number of characters required to represent
z in the given radix. May over-estimate. */ z in the given radix. May over-estimate. */
mp_result mp_int_string_len(mp_int z, mp_size radix); mp_result mp_int_string_len(mp_int z, mp_size radix);
/* Read zero-terminated string into z */ /* Read zero-terminated string into z */
mp_result mp_int_read_string(mp_int z, mp_size radix, const char *str); mp_result mp_int_read_string(mp_int z, mp_size radix, const char *str);
mp_result mp_int_read_cstring(mp_int z, mp_size radix, const char *str, mp_result mp_int_read_cstring(mp_int z, mp_size radix, const char *str,
char **end); char **end);
/* Return the number of significant bits in z */ /* Return the number of significant bits in z */
mp_result mp_int_count_bits(mp_int z); mp_result mp_int_count_bits(mp_int z);
/* Convert z to two's complement binary, writing at most limit bytes */ /* Convert z to two's complement binary, writing at most limit bytes */
mp_result mp_int_to_binary(mp_int z, unsigned char *buf, int limit); mp_result mp_int_to_binary(mp_int z, unsigned char *buf, int limit);
/* Read a two's complement binary value into z from the given buffer */ /* Read a two's complement binary value into z from the given buffer */
mp_result mp_int_read_binary(mp_int z, unsigned char *buf, int len); mp_result mp_int_read_binary(mp_int z, unsigned char *buf, int len);
/* Return the number of bytes required to represent z in binary. */ /* Return the number of bytes required to represent z in binary. */
mp_result mp_int_binary_len(mp_int z); mp_result mp_int_binary_len(mp_int z);
/* Convert z to unsigned binary, writing at most limit bytes */ /* Convert z to unsigned binary, writing at most limit bytes */
mp_result mp_int_to_unsigned(mp_int z, unsigned char *buf, int limit); mp_result mp_int_to_unsigned(mp_int z, unsigned char *buf, int limit);
/* Read an unsigned binary value into z from the given buffer */ /* Read an unsigned binary value into z from the given buffer */
mp_result mp_int_read_unsigned(mp_int z, unsigned char *buf, int len); mp_result mp_int_read_unsigned(mp_int z, unsigned char *buf, int len);
/* Return the number of bytes required to represent z as unsigned output */ /* Return the number of bytes required to represent z as unsigned output */
mp_result mp_int_unsigned_len(mp_int z); mp_result mp_int_unsigned_len(mp_int z);
/* Return a statically allocated string describing error code res */ /* Return a statically allocated string describing error code res */
const char *mp_error_string(mp_result res); 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"
@ -36,10 +36,10 @@
#include "px.h" #include "px.h"
#include "sha2.h" #include "sha2.h"
void init_sha224(PX_MD * h); void init_sha224(PX_MD * h);
void init_sha256(PX_MD * h); void init_sha256(PX_MD * h);
void init_sha384(PX_MD * h); void init_sha384(PX_MD * h);
void init_sha512(PX_MD * h); void init_sha512(PX_MD * h);
/* SHA224 */ /* SHA224 */
@ -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"
@ -78,10 +78,10 @@
static void init_md5(PX_MD * h); static void init_md5(PX_MD * h);
static void init_sha1(PX_MD * h); static void init_sha1(PX_MD * h);
void init_sha224(PX_MD * h); void init_sha224(PX_MD * h);
void init_sha256(PX_MD * h); void init_sha256(PX_MD * h);
void init_sha384(PX_MD * h); void init_sha384(PX_MD * h);
void init_sha512(PX_MD * h); void init_sha512(PX_MD * h);
struct int_digest struct int_digest
{ {

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,11 +156,12 @@ 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;
if (pg_strcasecmp(name, "sha224") == 0) if (pg_strcasecmp(name, "sha224") == 0)
init = init_sha224; init = init_sha224;
@ -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,29 +186,32 @@ 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;
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"
@ -491,9 +491,9 @@ PG_FUNCTION_INFO_V1(pg_random_bytes);
Datum Datum
pg_random_bytes(PG_FUNCTION_ARGS) pg_random_bytes(PG_FUNCTION_ARGS)
{ {
int err; int err;
int len = PG_GETARG_INT32(0); int len = PG_GETARG_INT32(0);
bytea *res; bytea *res;
if (len < 1 || len > 1024) if (len < 1 || len > 1024)
ereport(ERROR, ereport(ERROR,
@ -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,25 +55,29 @@ 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;
int last_bits = bits & 7; int last_bits = bits & 7;
uint8 *buf; uint8 *buf;
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,11 +117,11 @@ 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;
int bytes; int bytes;
res = pgp_mpi_alloc(mp_int_count_bits(bn), &n); res = pgp_mpi_alloc(mp_int_count_bits(bn), &n);
if (res < 0) if (res < 0)

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,11 +63,12 @@ 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;
} MyData; } MyData;
Datum Datum
pgrowlocks(PG_FUNCTION_ARGS) pgrowlocks(PG_FUNCTION_ARGS)
@ -78,7 +79,7 @@ pgrowlocks(PG_FUNCTION_ARGS)
TupleDesc tupdesc; TupleDesc tupdesc;
AttInMetadata *attinmeta; AttInMetadata *attinmeta;
Datum result; Datum result;
MyData *mydata; MyData *mydata;
Relation rel; Relation rel;
if (SRF_IS_FIRSTCALL()) if (SRF_IS_FIRSTCALL())
@ -96,8 +97,7 @@ 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 */
@ -124,16 +124,16 @@ pgrowlocks(PG_FUNCTION_ARGS)
LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE); LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
if (HeapTupleSatisfiesUpdate(tuple->t_data, GetCurrentCommandId(), scan->rs_cbuf) if (HeapTupleSatisfiesUpdate(tuple->t_data, GetCurrentCommandId(), scan->rs_cbuf)
== HeapTupleBeingUpdated) == HeapTupleBeingUpdated)
{ {
char **values; char **values;
int i; int i;
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,15 +143,15 @@ 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)
{ {
TransactionId *xids; TransactionId *xids;
int nxids; int nxids;
int j; int j;
int isValidXid = 0; /* any valid xid ever exists? */ int isValidXid = 0; /* any valid xid ever exists? */
values[i++] = pstrdup("true"); values[i++] = pstrdup("true");
nxids = GetMultiXactIdMembers(HeapTupleHeaderGetXmax(tuple->t_data), &xids); nxids = GetMultiXactIdMembers(HeapTupleHeaderGetXmax(tuple->t_data), &xids);
@ -160,45 +160,44 @@ 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];
if (TransactionIdIsInProgress(xids[j])) if (TransactionIdIsInProgress(xids[j]))
{ {
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
* *
@ -51,36 +51,36 @@ extern Datum pgstattuplebyid(PG_FUNCTION_ARGS);
*/ */
typedef struct pgstattuple_type typedef struct pgstattuple_type
{ {
uint64 table_len; uint64 table_len;
uint64 tuple_count; uint64 tuple_count;
uint64 tuple_len; uint64 tuple_len;
uint64 dead_tuple_count; uint64 dead_tuple_count;
uint64 dead_tuple_len; uint64 dead_tuple_len;
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
@ -91,7 +91,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
int i; int i;
double tuple_percent; double tuple_percent;
double dead_tuple_percent; double dead_tuple_percent;
double free_percent; /* free/reusable space in % */ double free_percent; /* free/reusable space in % */
TupleDesc tupdesc; TupleDesc tupdesc;
AttInMetadata *attinmeta; AttInMetadata *attinmeta;
@ -190,49 +190,49 @@ 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:
case RELKIND_UNCATALOGED: case RELKIND_UNCATALOGED:
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,
pgstat_btree_page, fcinfo); pgstat_btree_page, fcinfo);
case HASH_AM_OID: case HASH_AM_OID:
return pgstat_index(rel, HASH_METAPAGE + 1, return pgstat_index(rel, HASH_METAPAGE + 1,
pgstat_hash_page, fcinfo); pgstat_hash_page, fcinfo);
case GIST_AM_OID: case GIST_AM_OID:
return pgstat_index(rel, GIST_ROOT_BLKNO + 1, return pgstat_index(rel, GIST_ROOT_BLKNO + 1,
pgstat_gist_page, fcinfo); pgstat_gist_page, fcinfo);
case GIN_AM_OID: case GIN_AM_OID:
err = "gin index"; err = "gin index";
break;
default:
err = "unknown index";
break;
}
break;
case RELKIND_VIEW:
err = "view";
break;
case RELKIND_COMPOSITE_TYPE:
err = "composite type";
break; break;
default: default:
err = "unknown index"; err = "unknown";
break; break;
}
break;
case RELKIND_VIEW:
err = "view";
break;
case RELKIND_COMPOSITE_TYPE:
err = "composite type";
break;
default:
err = "unknown";
break;
} }
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("\"%s\" (%s) is not supported", errmsg("\"%s\" (%s) is not supported",
RelationGetRelationName(rel), err))); RelationGetRelationName(rel), err)));
return 0; /* should not happen */ return 0; /* should not happen */
} }
/* /*
@ -241,13 +241,13 @@ pgstat_relation(Relation rel, FunctionCallInfo fcinfo)
static Datum static Datum
pgstat_heap(Relation rel, FunctionCallInfo fcinfo) pgstat_heap(Relation rel, FunctionCallInfo fcinfo)
{ {
HeapScanDesc scan; HeapScanDesc scan;
HeapTuple tuple; HeapTuple tuple;
BlockNumber nblocks; BlockNumber nblocks;
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,10 +311,10 @@ 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;
buf = ReadBuffer(rel, blkno); buf = ReadBuffer(rel, blkno);
LockBuffer(buf, BT_READ); LockBuffer(buf, BT_READ);
@ -328,7 +328,8 @@ 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))
{ {
@ -338,7 +339,7 @@ pgstat_btree_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno)
else if (P_ISLEAF(opaque)) else if (P_ISLEAF(opaque))
{ {
pgstat_index_page(stat, page, P_FIRSTDATAKEY(opaque), pgstat_index_page(stat, page, P_FIRSTDATAKEY(opaque),
PageGetMaxOffsetNumber(page)); PageGetMaxOffsetNumber(page));
} }
else else
{ {
@ -353,10 +354,10 @@ 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;
_hash_getlock(rel, blkno, HASH_SHARE); _hash_getlock(rel, blkno, HASH_SHARE);
buf = _hash_getbuf(rel, blkno, HASH_READ); buf = _hash_getbuf(rel, blkno, HASH_READ);
@ -364,22 +365,23 @@ 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)
{ {
case LH_UNUSED_PAGE: case LH_UNUSED_PAGE:
stat->free_space += BLCKSZ; stat->free_space += BLCKSZ;
break; break;
case LH_BUCKET_PAGE: case LH_BUCKET_PAGE:
case LH_OVERFLOW_PAGE: case LH_OVERFLOW_PAGE:
pgstat_index_page(stat, page, FirstOffsetNumber, pgstat_index_page(stat, page, FirstOffsetNumber,
PageGetMaxOffsetNumber(page)); PageGetMaxOffsetNumber(page));
break; break;
case LH_BITMAP_PAGE: case LH_BITMAP_PAGE:
case LH_META_PAGE: case LH_META_PAGE:
default: default:
break; break;
} }
} }
else else
@ -395,10 +397,10 @@ 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;
buf = ReadBuffer(rel, blkno); buf = ReadBuffer(rel, blkno);
LockBuffer(buf, GIST_SHARE); LockBuffer(buf, GIST_SHARE);
@ -408,7 +410,7 @@ pgstat_gist_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno)
if (GistPageIsLeaf(page)) if (GistPageIsLeaf(page))
{ {
pgstat_index_page(stat, page, FirstOffsetNumber, pgstat_index_page(stat, page, FirstOffsetNumber,
PageGetMaxOffsetNumber(page)); PageGetMaxOffsetNumber(page));
} }
else else
{ {
@ -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,16 +460,16 @@ 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;
stat->free_space += PageGetFreeSpace(page); stat->free_space += PageGetFreeSpace(page);
for (i = minoff; i <= maxoff; i = OffsetNumberNext(i)) for (i = minoff; i <= maxoff; i = OffsetNumberNext(i))
{ {
ItemId itemid = PageGetItemId(page, i); ItemId itemid = PageGetItemId(page, i);
if (ItemIdDeleted(itemid)) if (ItemIdDeleted(itemid))
{ {

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"
@ -22,16 +22,16 @@
PG_MODULE_MAGIC; PG_MODULE_MAGIC;
Datum ssl_is_used(PG_FUNCTION_ARGS); Datum ssl_is_used(PG_FUNCTION_ARGS);
Datum ssl_client_cert_present(PG_FUNCTION_ARGS); Datum ssl_client_cert_present(PG_FUNCTION_ARGS);
Datum ssl_client_serial(PG_FUNCTION_ARGS); Datum ssl_client_serial(PG_FUNCTION_ARGS);
Datum ssl_client_dn_field(PG_FUNCTION_ARGS); Datum ssl_client_dn_field(PG_FUNCTION_ARGS);
Datum ssl_issuer_field(PG_FUNCTION_ARGS); Datum ssl_issuer_field(PG_FUNCTION_ARGS);
Datum ssl_client_dn(PG_FUNCTION_ARGS); Datum ssl_client_dn(PG_FUNCTION_ARGS);
Datum ssl_issuer_dn(PG_FUNCTION_ARGS); Datum ssl_issuer_dn(PG_FUNCTION_ARGS);
Datum X509_NAME_field_to_text(X509_NAME *name, text *fieldName); Datum X509_NAME_field_to_text(X509_NAME *name, text *fieldName);
Datum X509_NAME_to_text(X509_NAME *name); Datum X509_NAME_to_text(X509_NAME *name);
Datum ASN1_STRING_to_text(ASN1_STRING *str); Datum ASN1_STRING_to_text(ASN1_STRING *str);
/* /*
@ -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,20 +71,22 @@ 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;
X509 *peer = port->peer; X509 *peer = port->peer;
ASN1_INTEGER *serial = NULL; ASN1_INTEGER *serial = NULL;
BIGNUM *b; BIGNUM *b;
char *decimal; char *decimal;
if (!peer) if (!peer)
PG_RETURN_NULL(); PG_RETURN_NULL();
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),
@ -100,23 +104,25 @@ Datum ssl_client_serial(PG_FUNCTION_ARGS)
* current database encoding if possible. Any invalid characters are * current database encoding if possible. Any invalid characters are
* replaced by question marks. * replaced by question marks.
* *
* Parameter: str - OpenSSL ASN1_STRING structure. Memory managment * Parameter: str - OpenSSL ASN1_STRING structure. Memory managment
* of this structure is responsibility of caller. * of this structure is responsibility of caller.
* *
* 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,
char *sp; outlen;
char *dp; char *sp;
text *result; char *dp;
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);
@ -146,18 +152,21 @@ Datum ASN1_STRING_to_text(ASN1_STRING *str)
* *
* Parameter: X509_NAME *name - either subject or issuer of certificate * Parameter: X509_NAME *name - either subject or issuer of certificate
* Parameter: text fieldName - field name string like 'CN' or commonName * Parameter: text fieldName - field name string like 'CN' or commonName
* to be looked up in the OpenSSL ASN1 OID database * to be looked up in the OpenSSL ASN1 OID database
* *
* 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,10 +207,11 @@ 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;
if (!(MyProcPort->peer)) if (!(MyProcPort->peer))
PG_RETURN_NULL(); PG_RETURN_NULL();
@ -232,10 +242,11 @@ 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;
if (!(MyProcPort->peer)) if (!(MyProcPort->peer))
PG_RETURN_NULL(); PG_RETURN_NULL();
@ -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,
char *sp; outlen;
char *dp; char *sp;
text *result; char *dp;
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

@ -1259,7 +1259,7 @@ build_tuplestore_recursively(char *key_fld,
int ret; int ret;
int proc; int proc;
int serial_column; int serial_column;
StringInfoData sql; StringInfoData sql;
char **values; char **values;
char *current_key; char *current_key;
char *current_key_parent; char *current_key_parent;
@ -1357,9 +1357,9 @@ build_tuplestore_recursively(char *key_fld,
SPITupleTable *tuptable = SPI_tuptable; SPITupleTable *tuptable = SPI_tuptable;
TupleDesc spi_tupdesc = tuptable->tupdesc; TupleDesc spi_tupdesc = tuptable->tupdesc;
int i; int i;
StringInfoData branchstr; StringInfoData branchstr;
StringInfoData chk_branchstr; StringInfoData chk_branchstr;
StringInfoData chk_current_key; StringInfoData chk_current_key;
/* First time through, do a little more setup */ /* First time through, do a little more setup */
if (level == 0) if (level == 0)

View File

@ -164,16 +164,19 @@ get_oidnamespace(Oid funcoid)
return nspoid; return nspoid;
} }
/* 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)) { {
char sharepath[MAXPGPATH]; if (!is_absolute_path(filename))
char *absfn; {
#ifdef WIN32 char sharepath[MAXPGPATH];
char delim = '\\'; char *absfn;
#ifdef WIN32
char delim = '\\';
#else #else
char delim = '/'; char delim = '/';
#endif #endif
get_share_path(my_exec_path, sharepath); get_share_path(my_exec_path, sharepath);
absfn = palloc(strlen(sharepath) + strlen(filename) + 2); absfn = palloc(strlen(sharepath) + strlen(filename) + 2);

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,30 +202,31 @@ 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));
ptr = res = (TSLexeme *) DatumGetPointer( ptr = res = (TSLexeme *) DatumGetPointer(
FunctionCall4(&(dict->lexize_info), FunctionCall4(&(dict->lexize_info),
PointerGetDatum(dict->dictionary), PointerGetDatum(dict->dictionary),
PointerGetDatum(VARDATA(in)), PointerGetDatum(VARDATA(in)),
Int32GetDatum(VARSIZE(in) - VARHDRSZ), Int32GetDatum(VARSIZE(in) - VARHDRSZ),
PointerGetDatum(&dstate) PointerGetDatum(&dstate)
) )
); );
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),
PointerGetDatum(dict->dictionary), PointerGetDatum(dict->dictionary),
PointerGetDatum(VARDATA(in)), PointerGetDatum(VARDATA(in)),
Int32GetDatum(VARSIZE(in) - VARHDRSZ), Int32GetDatum(VARSIZE(in) - VARHDRSZ),
PointerGetDatum(&dstate) PointerGetDatum(&dstate)
) )
); );
} }
PG_FREE_IF_COPY(in, 1); PG_FREE_IF_COPY(in, 1);

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,11 +30,14 @@ 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 getnext; /* out: dict wants next lexeme */ bool isend; /* in: marks for lexize_info about text end is
void *private; /* internal dict state between calls with getnext == true */ * reached */
} DictSubState; bool getnext; /* out: dict wants next lexeme */
void *private; /* internal dict state between calls with
* getnext == true */
} DictSubState;
/* simple parser of cfg string */ /* simple parser of cfg string */
typedef struct typedef struct
@ -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,38 +72,43 @@ typedef struct
* Lexize subsystem * Lexize subsystem
*/ */
typedef struct ParsedLex { typedef struct ParsedLex
int type; {
char *lemm; int type;
int lenlemm; char *lemm;
int lenlemm;
bool resfollow; bool resfollow;
struct ParsedLex *next; struct ParsedLex *next;
} ParsedLex; } ParsedLex;
typedef struct ListParsedLex { typedef struct ListParsedLex
ParsedLex *head; {
ParsedLex *tail; ParsedLex *head;
} ListParsedLex; ParsedLex *tail;
} ListParsedLex;
typedef struct { typedef struct
TSCfgInfo *cfg; {
Oid curDictId; TSCfgInfo *cfg;
int posDict; Oid curDictId;
DictSubState dictState; int posDict;
ParsedLex *curSub; DictSubState dictState;
ListParsedLex towork; /* current list to work */ ParsedLex *curSub;
ListParsedLex waste; /* list of lexemes that already lexized */ ListParsedLex towork; /* current list to work */
ListParsedLex waste; /* list of lexemes that already lexized */
/* fields to store last variant to lexize (basically, thesaurus /*
or similar to, which wants several lexemes */ * fields to store last variant to lexize (basically, thesaurus or similar
* to, which wants several lexemes
*/
ParsedLex *lastRes; 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

@ -15,29 +15,32 @@
#include "query_cleanup.h" #include "query_cleanup.h"
PG_FUNCTION_INFO_V1(gin_extract_tsvector); 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)); {
uint32 *nentries = (uint32*)PG_GETARG_POINTER(1); tsvector *vector = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
Datum *entries = NULL; uint32 *nentries = (uint32 *) PG_GETARG_POINTER(1);
Datum *entries = NULL;
*nentries = 0; *nentries = 0;
if ( vector->size > 0 ) { if (vector->size > 0)
int i; {
WordEntry *we = ARRPTR( vector ); int i;
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++;
} }
@ -49,45 +52,50 @@ gin_extract_tsvector(PG_FUNCTION_ARGS) {
PG_FUNCTION_INFO_V1(gin_extract_tsquery); 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);
Datum *entries = NULL; StrategyNumber strategy = DatumGetUInt16(PG_GETARG_DATUM(2));
Datum *entries = NULL;
*nentries = 0; *nentries = 0;
if ( query->size > 0 ) { if (query->size > 0)
int4 i, j=0, len; {
ITEM *item; int4 i,
j = 0,
len;
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,51 +104,54 @@ gin_extract_tsquery(PG_FUNCTION_ARGS) {
PG_RETURN_POINTER(entries); PG_RETURN_POINTER(entries);
} }
typedef struct { typedef struct
ITEM *frst; {
bool *mapped_check; ITEM *frst;
} GinChkVal; bool *mapped_check;
} 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);
bool res = FALSE; QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_DATUM(2));
bool res = FALSE;
if ( query->size > 0 ) { if (query->size > 0)
int4 i, j=0; {
ITEM *item; int4 i,
j = 0;
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(
GETQUERY(query), GETQUERY(query),
&gcv, &gcv,
true, true,
checkcondition_gin checkcondition_gin
); );
} }
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"
@ -447,7 +447,7 @@ sizebitvec(BITVECP sign)
i; i;
LOOPBYTE( LOOPBYTE(
size += number_of_ones[(unsigned char) sign[i]]; size += number_of_ones[(unsigned char) sign[i]];
); );
return size; return size;
} }
@ -460,8 +460,8 @@ hemdistsign(BITVECP a, BITVECP b)
dist = 0; dist = 0;
LOOPBYTE( LOOPBYTE(
diff = (unsigned char) (a[i] ^ b[i]); diff = (unsigned char) (a[i] ^ b[i]);
dist += number_of_ones[diff]; dist += number_of_ones[diff];
); );
return dist; return dist;
} }
@ -533,7 +533,7 @@ 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)

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;
} }
@ -165,10 +171,11 @@ bool
RS_execute(Regis * r, char *str) 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

@ -27,12 +27,12 @@ typedef struct Regis
unused:15; unused:15;
} Regis; } Regis;
bool RS_isRegis(const char *str); bool RS_isRegis(const char *str);
void RS_compile(Regis * r, bool issuffix, char *str); void RS_compile(Regis * r, bool issuffix, char *str);
void RS_free(Regis * r); void RS_free(Regis * r);
/*returns true if matches */ /*returns true if matches */
bool RS_execute(Regis * r, char *str); bool RS_execute(Regis * r, char *str);
#endif #endif

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);
@ -268,7 +271,8 @@ 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,83 +290,121 @@ 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 }
Conf->Affix[Conf->naffixes].repl = VoidString; else
Conf->Affix[Conf->naffixes].repl = VoidString;
Conf->naffixes++; Conf->naffixes++;
return (0); return (0);
} }
#define PAE_WAIT_MASK 0 #define PAE_WAIT_MASK 0
#define PAE_INMASK 1 #define PAE_INMASK 1
#define PAE_WAIT_FIND 2 #define PAE_WAIT_FIND 2
#define PAE_INFIND 3 #define PAE_INFIND 3
#define PAE_WAIT_REPL 4 #define PAE_WAIT_REPL 4
#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; {
char *pmask=mask, *pfind=find, *prepl=repl; int state = PAE_WAIT_MASK;
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)
break; /* void repl */ {
} else if ( t_isalpha(str) ) { if (t_iseq(str, '-'))
COPYCHAR(prepl,str); {
break; /* void repl */
}
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,8 +429,8 @@ 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")))
return (1); return (1);
@ -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 { }
char *affbegin; else
{
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

@ -42,8 +42,8 @@ typedef struct spell_struct
int affix; int affix;
int len; int len;
} d; } d;
} p; } p;
char word[1]; char word[1];
} SPELL; } SPELL;
#define SPELLHDRSZ (offsetof(SPELL, word)) #define SPELLHDRSZ (offsetof(SPELL, word))
@ -110,7 +110,7 @@ typedef struct
int nspell; int nspell;
int mspell; int mspell;
SPELL **Spell; SPELL **Spell;
AffixNode *Suffix; AffixNode *Suffix;
AffixNode *Prefix; AffixNode *Prefix;

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));
@ -739,23 +741,23 @@ infix(INFIX * in, bool first)
if (in->curpol->type == VAL) if (in->curpol->type == VAL)
{ {
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++;
} }
@ -104,7 +104,7 @@ tsq_mcontained(PG_FUNCTION_ARGS)
PG_GETARG_DATUM(1), PG_GETARG_DATUM(1),
PG_GETARG_DATUM(0) PG_GETARG_DATUM(0)
) )
); );
} }
PG_FUNCTION_INFO_V1(gtsq_in); PG_FUNCTION_INFO_V1(gtsq_in);
@ -272,7 +272,7 @@ 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)

View File

@ -41,13 +41,13 @@ static float weights[] = {0.1, 0.2, 0.4, 1.0};
#define wpos(wep) ( w[ WEP_GETWEIGHT(wep) ] ) #define wpos(wep) ( w[ WEP_GETWEIGHT(wep) ] )
#define RANK_NO_NORM 0x00 #define RANK_NO_NORM 0x00
#define RANK_NORM_LOGLENGTH 0x01 #define RANK_NORM_LOGLENGTH 0x01
#define RANK_NORM_LENGTH 0x02 #define RANK_NORM_LENGTH 0x02
#define RANK_NORM_EXTDIST 0x04 #define RANK_NORM_EXTDIST 0x04
#define RANK_NORM_UNIQ 0x08 #define RANK_NORM_UNIQ 0x08
#define RANK_NORM_LOGUNIQ 0x10 #define RANK_NORM_LOGUNIQ 0x10
#define DEF_NORM_METHOD RANK_NO_NORM #define DEF_NORM_METHOD RANK_NO_NORM
static float calc_rank_or(float *w, tsvector * t, QUERYTYPE * q); static float calc_rank_or(float *w, tsvector * t, QUERYTYPE * q);
static float calc_rank_and(float *w, tsvector * t, QUERYTYPE * q); static float calc_rank_and(float *w, tsvector * t, QUERYTYPE * q);
@ -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,17 +458,18 @@ reset_istrue_flag(QUERYTYPE * query)
} }
} }
typedef struct { typedef struct
int pos; {
int p; int pos;
int q; int p;
DocRepresentation *begin; int q;
DocRepresentation *end; DocRepresentation *begin;
} Extention; DocRepresentation *end;
} Extention;
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,69 +632,77 @@ 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,
doclen = 0; doclen = 0;
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 InvSum = 0.0; double Cpos = 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,13 +710,13 @@ 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
rank_cd(PG_FUNCTION_ARGS) rank_cd(PG_FUNCTION_ARGS)
{ {
ArrayType *win = (ArrayType *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); ArrayType *win = (ArrayType *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
tsvector *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); tsvector *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(2)); QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(2));
int method = DEF_NORM_METHOD; int method = DEF_NORM_METHOD;
@ -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);
@ -744,9 +755,9 @@ rank_cd_def(PG_FUNCTION_ARGS)
{ {
tsvector *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); tsvector *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
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);
@ -791,7 +802,7 @@ get_covers(PG_FUNCTION_ARGS)
text *out; text *out;
char *cptr; char *cptr;
DocRepresentation *doc; DocRepresentation *doc;
int olddwpos = 0; int olddwpos = 0;
int ncover = 1; int ncover = 1;
Extention ext; Extention ext;
@ -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,9 +325,9 @@ 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;
prs->pos++; /* set pos */ prs->pos++; /* set pos */
@ -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;
@ -349,8 +350,8 @@ parsetext_v2(TSCfgInfo * cfg, PRSTEXT * prs, char *buf, int4 buflen)
prs->curwords++; prs->curwords++;
} }
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; {
TSLexeme *ptr; ParsedLex *tmplexs;
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);
@ -445,8 +451,8 @@ hlparsetext(TSCfgInfo * cfg, HLPRSTEXT * prs, QUERYTYPE * query, char *buf, int4
char *lemm = NULL; char *lemm = NULL;
WParserInfo *prsobj = findprs(cfg->prs_id); WParserInfo *prsobj = findprs(cfg->prs_id);
LexizeData ldata; LexizeData ldata;
TSLexeme *norms; TSLexeme *norms;
ParsedLex *lexs; ParsedLex *lexs;
prsobj->prs = (void *) DatumGetPointer( prsobj->prs = (void *) DatumGetPointer(
FunctionCall2( FunctionCall2(
@ -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,70 +110,78 @@ 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 ) { {
TSLexeme *ptr; if (ld->tmpRes)
for( ptr=ld->tmpRes; ptr->lexeme; ptr++ ) {
pfree( ptr->lexeme ); TSLexeme *ptr;
pfree( ld->tmpRes );
for (ptr = ld->tmpRes; ptr->lexeme; ptr++)
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; {
ListDictionary *map; int i;
DictInfo *dict; ListDictionary *map;
TSLexeme *res; DictInfo *dict;
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),
Int32GetDatum(curVal->lenlemm), Int32GetDatum(curVal->lenlemm),
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);
} }
if (!res) /* dictionary doesn't know this lexeme */ if (!res) /* dictionary doesn't know this lexeme */
continue; continue;
RemoveHead(ld); RemoveHead(ld);
@ -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,36 +237,41 @@ 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),
Int32GetDatum(curVal->lenlemm), Int32GetDatum(curVal->lenlemm),
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,54 +70,59 @@ 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 *
lowerstr(char *str) 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; {
int len = strlen(str); wchar_t *wstr,
*wptr;
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++; *wptr = towlower((wint_t) *wptr);
} wptr++;
wchar2char(str, wstr, len); }
pfree( wstr ); wchar2char(str, wstr, len);
} else pfree(wstr);
}
else
#endif #endif
while (*ptr) while (*ptr)
{ {
@ -126,4 +131,3 @@ lowerstr(char *str)
} }
return str; return str;
} }

View File

@ -35,44 +35,44 @@
size_t wchar2char(char *to, const wchar_t *from, size_t len); size_t wchar2char(char *to, const wchar_t *from, size_t len);
size_t char2wchar(wchar_t *to, const char *from, size_t len); size_t char2wchar(wchar_t *to, const char *from, size_t len);
#else /* WIN32 */ #else /* WIN32 */
/* correct mbstowcs */ /* correct mbstowcs */
#define char2wchar mbstowcs #define char2wchar mbstowcs
#define wchar2char wcstombs #define wchar2char wcstombs
#endif /* WIN32 */ #endif /* WIN32 */
#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) )
extern int _t_isprint( const char *ptr ); #define t_isalpha(x) ( (pg_mblen(x)==1) ? isalpha( TOUCHAR(x) ) : _t_isalpha(x) )
#define t_isprint(x) ( (pg_mblen(x)==1) ? isprint( TOUCHAR(x) ) : _t_isprint(x) ) extern int _t_isprint(const char *ptr);
#define t_isprint(x) ( (pg_mblen(x)==1) ? isprint( TOUCHAR(x) ) : _t_isprint(x) )
/* /*
* t_iseq() should be called only for ASCII symbols * t_iseq() should be called only for ASCII symbols
*/ */
#define t_iseq(x,c) ( (pg_mblen(x)==1) ? ( TOUCHAR(x) == ((unsigned char)(c)) ) : false ) #define t_iseq(x,c) ( (pg_mblen(x)==1) ? ( TOUCHAR(x) == ((unsigned char)(c)) ) : false )
#define COPYCHAR(d,s) do { \ #define COPYCHAR(d,s) do { \
int lll = pg_mblen( s ); \ int lll = pg_mblen( s ); \
\ \
while( lll-- ) \ while( lll-- ) \
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_isspace(x) isspace( TOUCHAR(x) )
#define t_isdigit(x) isdigit( TOUCHAR(x) ) #define t_isalpha(x) isalpha( TOUCHAR(x) )
#define t_isspace(x) isspace( TOUCHAR(x) ) #define t_isprint(x) isprint( TOUCHAR(x) )
#define t_isalpha(x) isalpha( TOUCHAR(x) ) #define t_iseq(x,c) ( TOUCHAR(x) == ((unsigned char)(c)) )
#define t_isprint(x) isprint( TOUCHAR(x) )
#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

@ -165,13 +165,13 @@ uniqueentry(WordEntryIN * a, int4 l, char *buf, int4 *outbuflen)
} }
#define WAITWORD 1 #define WAITWORD 1
#define WAITENDWORD 2 #define WAITENDWORD 2
#define WAITNEXTCHAR 3 #define WAITNEXTCHAR 3
#define WAITENDCMPLX 4 #define WAITENDCMPLX 4
#define WAITPOSINFO 5 #define WAITPOSINFO 5
#define INPOSINFO 6 #define INPOSINFO 6
#define WAITPOSDELIM 7 #define WAITPOSDELIM 7
#define WAITCHARCMPLX 8 #define WAITCHARCMPLX 8
#define RESIZEPRSBUF \ #define RESIZEPRSBUF \
do { \ do { \
@ -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)
@ -312,12 +315,12 @@ gettoken_tsvector(TI_IN_STATE * state)
} }
else else
state->state = WAITPOSINFO; state->state = WAITPOSINFO;
continue; /* recheck current character */ continue; /* recheck current character */
} }
} }
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++ = '\'';
@ -983,36 +988,49 @@ silly_cmp_tsvector(const tsvector * a, const tsvector * b)
{ {
WordEntry *aptr = ARRPTR(a); WordEntry *aptr = ARRPTR(a);
WordEntry *bptr = ARRPTR(b); WordEntry *bptr = ARRPTR(b);
int i = 0; int i = 0;
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 ) { }
WordEntryPos *ap = POSDATAPTR(a, aptr); else if (aptr->haspos)
WordEntryPos *bp = POSDATAPTR(b, bptr); {
int j; WordEntryPos *ap = POSDATAPTR(a, aptr);
WordEntryPos *bp = POSDATAPTR(b, bptr);
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

@ -49,7 +49,7 @@ typedef uint16 WordEntryPos;
/* /*
* Structure of tsvector datatype: * Structure of tsvector datatype:
* 1) int4 len - varlena's length * 1) int4 len - varlena's length
* 2) int4 size - number of lexemes or WordEntry array, which is the same * 2) int4 size - number of lexemes or WordEntry array, which is the same
* 3) Array of WordEntry - sorted array, comparison based on word's length * 3) Array of WordEntry - sorted array, comparison based on word's length
* and strncmp(). WordEntry->pos points number of * and strncmp(). WordEntry->pos points number of
@ -57,8 +57,8 @@ typedef uint16 WordEntryPos;
* corresponding lexeme. * corresponding lexeme.
* 4) Lexeme's storage: * 4) Lexeme's storage:
* SHORTALIGNED(lexeme) and position information if it exists * SHORTALIGNED(lexeme) and position information if it exists
* Position information: first int2 - is a number of positions and it * Position information: first int2 - is a number of positions and it
* follows array of WordEntryPos * follows array of WordEntryPos
*/ */
typedef struct typedef struct

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

@ -347,8 +347,8 @@ typedef struct
typedef struct typedef struct
{ {
int cur; int cur;
int len; int len;
LexemeEntry *list; LexemeEntry *list;
} PrsStorage; } PrsStorage;

View File

@ -671,7 +671,7 @@ xpath_table(PG_FUNCTION_ARGS)
* document */ * document */
int had_values; /* To determine end of nodeset results */ int had_values; /* To determine end of nodeset results */
StringInfoData query_buf; StringInfoData query_buf;
/* We only have a valid tuple description in table function mode */ /* We only have a valid tuple description in table function mode */
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))

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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -1294,7 +1294,7 @@ slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
{ {
if (tuple == NULL) /* internal error */ if (tuple == NULL) /* internal error */
elog(ERROR, "cannot extract system attribute from virtual tuple"); elog(ERROR, "cannot extract system attribute from virtual tuple");
if (slot->tts_mintuple) /* internal error */ if (slot->tts_mintuple) /* internal error */
elog(ERROR, "cannot extract system attribute from minimal tuple"); elog(ERROR, "cannot extract system attribute from minimal tuple");
return heap_getsysattr(tuple, attnum, tupleDesc, isnull); return heap_getsysattr(tuple, attnum, tupleDesc, isnull);
} }
@ -1480,7 +1480,7 @@ slot_attisnull(TupleTableSlot *slot, int attnum)
{ {
if (tuple == NULL) /* internal error */ if (tuple == NULL) /* internal error */
elog(ERROR, "cannot extract system attribute from virtual tuple"); elog(ERROR, "cannot extract system attribute from virtual tuple");
if (slot->tts_mintuple) /* internal error */ if (slot->tts_mintuple) /* internal error */
elog(ERROR, "cannot extract system attribute from minimal tuple"); elog(ERROR, "cannot extract system attribute from minimal tuple");
return heap_attisnull(tuple, attnum); return heap_attisnull(tuple, attnum);
} }

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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -59,7 +59,7 @@ transformRelOptions(Datum oldOptions, List *defList,
/* Copy any oldOptions that aren't to be replaced */ /* Copy any oldOptions that aren't to be replaced */
if (oldOptions != (Datum) 0) if (oldOptions != (Datum) 0)
{ {
ArrayType *array = DatumGetArrayTypeP(oldOptions); ArrayType *array = DatumGetArrayTypeP(oldOptions);
Datum *oldoptions; Datum *oldoptions;
int noldoptions; int noldoptions;
int i; int i;
@ -71,15 +71,15 @@ transformRelOptions(Datum oldOptions, List *defList,
for (i = 0; i < noldoptions; i++) for (i = 0; i < noldoptions; i++)
{ {
text *oldoption = DatumGetTextP(oldoptions[i]); text *oldoption = DatumGetTextP(oldoptions[i]);
char *text_str = (char *) VARATT_DATA(oldoption); char *text_str = (char *) VARATT_DATA(oldoption);
int text_len = VARATT_SIZE(oldoption) - VARHDRSZ; int text_len = VARATT_SIZE(oldoption) - VARHDRSZ;
/* Search for a match in defList */ /* Search for a match in defList */
foreach(cell, defList) foreach(cell, defList)
{ {
DefElem *def = lfirst(cell); DefElem *def = lfirst(cell);
int kw_len = strlen(def->defname); int kw_len = strlen(def->defname);
if (text_len > kw_len && text_str[kw_len] == '=' && if (text_len > kw_len && text_str[kw_len] == '=' &&
pg_strncasecmp(text_str, def->defname, kw_len) == 0) pg_strncasecmp(text_str, def->defname, kw_len) == 0)
@ -96,33 +96,33 @@ 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)
{ {
DefElem *def = lfirst(cell); DefElem *def = lfirst(cell);
if (isReset) if (isReset)
{ {
if (def->arg != NULL) if (def->arg != NULL)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("RESET must not include values for parameters"))); errmsg("RESET must not include values for parameters")));
} }
else else
{ {
text *t; text *t;
const char *value; const char *value;
Size len; Size len;
if (ignoreOids && pg_strcasecmp(def->defname, "oids") == 0) if (ignoreOids && pg_strcasecmp(def->defname, "oids") == 0)
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,10 +163,10 @@ 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;
Datum *optiondatums; Datum *optiondatums;
int noptions; int noptions;
int i; int i;
@ -187,21 +187,21 @@ parseRelOptions(Datum options, int numkeywords, const char * const *keywords,
for (i = 0; i < noptions; i++) for (i = 0; i < noptions; i++)
{ {
text *optiontext = DatumGetTextP(optiondatums[i]); text *optiontext = DatumGetTextP(optiondatums[i]);
char *text_str = (char *) VARATT_DATA(optiontext); char *text_str = (char *) VARATT_DATA(optiontext);
int text_len = VARATT_SIZE(optiontext) - VARHDRSZ; int text_len = VARATT_SIZE(optiontext) - VARHDRSZ;
int j; int j;
/* Search for a match in keywords */ /* Search for a match in keywords */
for (j = 0; j < numkeywords; j++) for (j = 0; j < numkeywords; j++)
{ {
int kw_len = strlen(keywords[j]); int kw_len = strlen(keywords[j]);
if (text_len > kw_len && text_str[kw_len] == '=' && if (text_len > kw_len && text_str[kw_len] == '=' &&
pg_strncasecmp(text_str, keywords[j], kw_len) == 0) pg_strncasecmp(text_str, keywords[j], kw_len) == 0)
{ {
char *value; char *value;
int value_len; int value_len;
if (values[j] && validate) if (values[j] && validate)
ereport(ERROR, ereport(ERROR,
@ -218,8 +218,8 @@ parseRelOptions(Datum options, int numkeywords, const char * const *keywords,
} }
if (j >= numkeywords && validate) if (j >= numkeywords && validate)
{ {
char *s; char *s;
char *p; char *p;
s = DatumGetCString(DirectFunctionCall1(textout, optiondatums[i])); s = DatumGetCString(DirectFunctionCall1(textout, optiondatums[i]));
p = strchr(s, '='); p = strchr(s, '=');
@ -240,17 +240,17 @@ 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;
parseRelOptions(reloptions, 1, default_keywords, values, validate); parseRelOptions(reloptions, 1, default_keywords, values, 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

@ -1,14 +1,14 @@
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* ginarrayproc.c * ginarrayproc.c
* support functions for GIN's indexing of any array * support functions for GIN's indexing of any array
* *
* *
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* 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"
@ -23,11 +23,11 @@
#define GinContainedStrategy 3 #define GinContainedStrategy 3
#define GinEqualStrategy 4 #define GinEqualStrategy 4
#define ARRAYCHECK(x) do { \ #define ARRAYCHECK(x) do { \
if ( ARR_HASNULL(x) ) \ if ( ARR_HASNULL(x) ) \
ereport(ERROR, \ ereport(ERROR, \
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), \ (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), \
errmsg("array must not contain nulls"))); \ errmsg("array must not contain nulls"))); \
} while(0) } while(0)
@ -35,41 +35,49 @@
* 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; {
uint32 *nentries = (uint32*)PG_GETARG_POINTER(1); ArrayType *array;
Datum *entries = NULL; uint32 *nentries = (uint32 *) PG_GETARG_POINTER(1);
int16 elmlen; Datum *entries = NULL;
bool elmbyval; int16 elmlen;
char elmalign; bool elmbyval;
char elmalign;
/* we should guarantee that array will not be destroyed during all operation */ /*
* we should guarantee that array will not be destroyed during all
* operation
*/
array = PG_GETARG_ARRAYTYPE_P_COPY(0); array = PG_GETARG_ARRAYTYPE_P_COPY(0);
ARRAYCHECK(array); ARRAYCHECK(array);
get_typlenbyvalalign(ARR_ELEMTYPE(array), get_typlenbyvalalign(ARR_ELEMTYPE(array),
&elmlen, &elmbyval, &elmalign); &elmlen, &elmbyval, &elmalign);
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); {
StrategyNumber strategy = PG_GETARG_UINT16(1); bool *check = (bool *) PG_GETARG_POINTER(0);
ArrayType *query = PG_GETARG_ARRAYTYPE_P(2); StrategyNumber strategy = PG_GETARG_UINT16(1);
int res, i, nentries; ArrayType *query = PG_GETARG_ARRAYTYPE_P(2);
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

@ -1,14 +1,14 @@
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* ginbtree.c * ginbtree.c
* page utilities routines for the postgres inverted index access method. * page utilities routines for the postgres inverted index access method.
* *
* *
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* 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; {
int access=GIN_SHARE; Page page;
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) { {
GinBtreeStack *tmp = stack->parent; while (stack)
if ( stack->buffer != InvalidBuffer ) {
GinBtreeStack *tmp = stack->parent;
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,79 +266,94 @@ 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; {
BlockNumber rootBlkno = InvalidBuffer; GinBtreeStack *parent = stack;
Page page, rpage, lpage; BlockNumber rootBlkno = InvalidBuffer;
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);
PageSetLSN(page, recptr); PageSetLSN(page, recptr);
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 { }
Buffer rbuffer = GinNewBuffer(btree->index); else
Page newlpage; {
Buffer rbuffer = GinNewBuffer(btree->index);
Page newlpage;
/* newlpage is a pointer to memory page, it does'nt assosiates with buffer, /*
stack->buffer shoud be untouched */ * newlpage is a pointer to memory page, it does'nt assosiates
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 */ /*
Buffer lbuffer = GinNewBuffer(btree->index); * split root, so we need to allocate new left page and place
* pointer on root to left and right page
*/
Buffer lbuffer = GinNewBuffer(btree->index);
((ginxlogSplit*)(rdata->data))->isRootSplit = TRUE; ((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);
PageSetLSN(page, recptr); PageSetLSN(page, recptr);
@ -326,21 +374,24 @@ 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);
PageSetLSN(lpage, recptr); PageSetLSN(lpage, recptr);
@ -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

@ -1,14 +1,14 @@
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* ginbulk.c * ginbulk.c
* routines for fast build of inverted index * routines for fast build of inverted index
* *
* *
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* 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; {
int res = 0; EntryAccumulator *ea = accum->entries,
uint32 depth = 1; *pea = NULL;
int res = 0;
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,32 +130,35 @@ 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;
ea->value = getDatumCopy(accum, entry); ea->value = getDatumCopy(accum, 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 middle = (low+high)>>1; uint32 pos;
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,47 +264,53 @@ 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;
*value = entry->value; *value = entry->value;
list = entry->list; list = entry->list;
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

@ -1,14 +1,14 @@
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* gindatapage.c * gindatapage.c
* page utilities routines for the postgres inverted index access method. * page utilities routines for the postgres inverted index access method.
* *
* *
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* 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,
int result; high,
Page page = BufferGetPage( stack->buffer ); maxoff;
PostingItem *pitem = NULL;
int result;
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);
int result; OffsetNumber low,
high;
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,28 +384,34 @@ 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 }
GinDataPageAddItem(page, &(btree->pitem), off); else
GinDataPageAddItem(page, &(btree->pitem), off);
} }
/* /*
@ -368,78 +421,87 @@ 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);
/* set up right bound for left page */ /* set up right bound for left page */
@ -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), {
lpage = BufferGetPage(lbuf), Page page = BufferGetPage(root),
rpage = BufferGetPage(rbuf); lpage = BufferGetPage(lbuf),
PostingItem li, ri; rpage = BufferGetPage(rbuf);
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;
@ -509,21 +574,22 @@ prepareDataScan( GinBtree btree, Relation index) {
btree->fillRoot = dataFillRoot; btree->fillRoot = dataFillRoot;
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

@ -1,14 +1,14 @@
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* ginentrypage.c * ginentrypage.c
* page utilities routines for the postgres inverted index access method. * page utilities routines for the postgres inverted index access method.
* *
* *
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* 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 $
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -28,42 +28,46 @@
* - ItemPointerGetOffsetNumber(&itup->t_tid) contains number * - ItemPointerGetOffsetNumber(&itup->t_tid) contains number
* of elements in posting list (number of heap itempointer) * of elements in posting list (number of heap itempointer)
* Macroses: GinGetNPosting(itup) / GinSetNPosting(itup,n) * Macroses: GinGetNPosting(itup) / GinSetNPosting(itup,n)
* - After usial part of tuple there is a posting list * - After usial part of tuple there is a posting list
* Macros: GinGetPosting(itup) * Macros: GinGetPosting(itup)
* 2) Posting tree * 2) Posting tree
* - itup->t_info & INDEX_SIZE_MASK contains size of tuple as usial * - itup->t_info & INDEX_SIZE_MASK contains size of tuple as usial
* - ItemPointerGetBlockNumber(&itup->t_tid) contains block number of * - ItemPointerGetBlockNumber(&itup->t_tid) contains block number of
* root of posting tree * root of posting tree
* - 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,15 +78,18 @@ 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; {
bool isnull; IndexTuple itup;
bool isnull;
itup = getRightMostTuple(page); itup = getRightMostTuple(page);
@ -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; {
IndexTuple itup = NULL; OffsetNumber low,
int result; high,
Page page = BufferGetPage( stack->buffer ); maxoff;
IndexTuple itup = NULL;
int result;
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);
IndexTuple itup; OffsetNumber low,
high;
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); {
IndexTuple itup; OffsetNumber i,
maxoff = PageGetMaxOffsetNumber(page);
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; {
Page page = BufferGetPage(buf); Size itupsz = 0;
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;
char *ptr; Size lsize = 0,
IndexTuple itup, leftrightmost=NULL; size;
static ginxlogSplit data; static char tupstore[2 * BLCKSZ];
Datum value; char *ptr;
bool isnull; IndexTuple itup,
Page page; leftrightmost = NULL;
Page lpage = GinPageGetCopyPage( BufferGetPage( lbuf ) ); static ginxlogSplit data;
Page rpage = BufferGetPage( rbuf ); Datum value;
Size pageSize = PageGetPageSize( lpage ); bool isnull;
Page page;
Page lpage = GinPageGetCopyPage(BufferGetPage(lbuf));
Page rpage = BufferGetPage(rbuf);
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; {
Page page = BufferGetPage(buf); IndexTuple itup,
nitup;
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; {
IndexTuple itup; Page page;
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

@ -1,14 +1,14 @@
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* ginget.c * ginget.c
* fetch tuples from a GIN scan. * fetch tuples from a GIN scan.
* *
* *
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* 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; {
GinScanOpaque so = (GinScanOpaque) scan->opaque; uint32 i;
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; {
GinScanOpaque so = (GinScanOpaque) scan->opaque; uint32 i;
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);
} }
@ -221,29 +250,37 @@ entryGetNextItem( Relation index, GinScanEntry entry ) {
} }
#define gin_rand() (((double) random()) / ((double) MAX_RANDOM_VALUE)) #define gin_rand() (((double) random()) / ((double) MAX_RANDOM_VALUE))
#define dropItem(e) ( gin_rand() > ((double)GinFuzzySearchLimit)/((double)((e)->predictNumberResult)) ) #define dropItem(e) ( gin_rand() > ((double)GinFuzzySearchLimit)/((double)((e)->predictNumberResult)) )
/* /*
* Sets entry->curItem to new found heap item pointer for one * Sets entry->curItem to new found heap item pointer for one
* 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; {
GinScanEntry entry; uint32 i;
bool res; GinScanEntry entry;
MemoryContext oldCtx; bool res;
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; {
GinScanOpaque so = (GinScanOpaque) scan->opaque; uint32 i;
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 }
return FALSE; /* finshed one of keys */ else
return FALSE; /* finshed one of keys */
} }
for(i=1;i<=so->nkeys;i++) { for (i = 1; i <= so->nkeys; i++)
GinScanKey key = so->keys+i-1; {
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 ) {
return FALSE; /* finshed one of keys */ if (keyGetItem(scan->indexRelation, &so->ginstate, so->tempCtx, key) == TRUE)
} else { /* returns to begin */ return FALSE; /* finshed one of keys */
}
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

@ -1,14 +1,14 @@
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* gininsert.c * gininsert.c
* insert routines for the postgres inverted index access method. * insert routines for the postgres inverted index access method.
* *
* *
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* 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,12 +19,13 @@
#include "miscadmin.h" #include "miscadmin.h"
#include "utils/memutils.h" #include "utils/memutils.h"
typedef struct { typedef struct
GinState ginstate; {
double indtuples; GinState ginstate;
MemoryContext tmpCtx; double indtuples;
MemoryContext funcCtx; MemoryContext tmpCtx;
BuildAccumulator accum; MemoryContext funcCtx;
BuildAccumulator accum;
} GinBuildState; } GinBuildState;
/* /*
@ -32,24 +33,26 @@ 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;
data.node = index->rd_node; data.node = index->rd_node;
data.blkno = blkno; data.blkno = blkno;
@ -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; {
Datum key = index_getattr(old, FirstOffsetNumber, ginstate->tupdesc, &isnull); bool isnull;
IndexTuple res = GinFormTuple(ginstate, key, NULL, nitem + GinGetNPosting(old)); Datum key = index_getattr(old, FirstOffsetNumber, ginstate->tupdesc, &isnull);
IndexTuple res = GinFormTuple(ginstate, key, NULL, nitem + GinGetNPosting(old));
if ( res ) { if (res)
{
/* good, small enough */ /* 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; {
uint32 nentries; Datum *entries;
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
ItemPointerData *list; */
Datum entry; if (buildstate->accum.allocatedMemory >= maintenance_work_mem * 1024L / 2L)
uint32 nlist; {
ItemPointerData *list;
Datum entry;
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,22 +257,23 @@ 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 index = (Relation) PG_GETARG_POINTER(1); Relation heap = (Relation) PG_GETARG_POINTER(0);
Relation index = (Relation) PG_GETARG_POINTER(1);
IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2); IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
IndexBuildResult *result; IndexBuildResult *result;
double reltuples; double reltuples;
GinBuildState buildstate; GinBuildState buildstate;
Buffer buffer; Buffer buffer;
ItemPointerData *list; ItemPointerData *list;
Datum entry; Datum entry;
uint32 nlist; uint32 nlist;
MemoryContext oldCtx; MemoryContext oldCtx;
if (RelationGetNumberOfBlocks(index) != 0) if (RelationGetNumberOfBlocks(index) != 0)
elog(ERROR, "index \"%s\" already contains data", elog(ERROR, "index \"%s\" already contains data",
RelationGetRelationName(index)); RelationGetRelationName(index));
initGinState(&buildstate.ginstate, index); initGinState(&buildstate.ginstate, index);
@ -262,10 +281,11 @@ 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;
rdata.buffer = InvalidBuffer; rdata.buffer = InvalidBuffer;
rdata.data = (char *) &(index->rd_node); rdata.data = (char *) &(index->rd_node);
@ -293,26 +313,26 @@ ginbuild(PG_FUNCTION_ARGS) {
* inserted into the index * inserted into the index
*/ */
buildstate.tmpCtx = AllocSetContextCreate(CurrentMemoryContext, buildstate.tmpCtx = AllocSetContextCreate(CurrentMemoryContext,
"Gin build temporary context", "Gin build temporary context",
ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE); ALLOCSET_DEFAULT_MAXSIZE);
buildstate.funcCtx = AllocSetContextCreate(buildstate.tmpCtx, buildstate.funcCtx = AllocSetContextCreate(buildstate.tmpCtx,
"Gin build temporary context for user-defined function", "Gin build temporary context for user-defined function",
ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_INITSIZE,
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,45 +353,49 @@ 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; {
uint32 i,nentries; Datum *entries;
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); {
Datum *values = (Datum *) PG_GETARG_POINTER(1); Relation index = (Relation) PG_GETARG_POINTER(0);
bool *isnull = (bool *) PG_GETARG_POINTER(2); Datum *values = (Datum *) PG_GETARG_POINTER(1);
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);
#endif #endif
GinState ginstate; GinState ginstate;
MemoryContext oldCtx; MemoryContext oldCtx;
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,
"Gin insert temporary context", "Gin insert temporary context",
ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE); ALLOCSET_DEFAULT_MAXSIZE);
oldCtx = MemoryContextSwitchTo(insertCtx); oldCtx = MemoryContextSwitchTo(insertCtx);
@ -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

@ -1,14 +1,14 @@
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* ginscan.c * ginscan.c
* routines to manage scans inverted index relations * routines to manage scans inverted index relations
* *
* *
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* 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,10 +20,11 @@
Datum Datum
ginbeginscan(PG_FUNCTION_ARGS) { ginbeginscan(PG_FUNCTION_ARGS)
Relation rel = (Relation) PG_GETARG_POINTER(0); {
int keysz = PG_GETARG_INT32(1); Relation rel = (Relation) PG_GETARG_POINTER(0);
ScanKey scankey = (ScanKey) PG_GETARG_POINTER(2); int keysz = PG_GETARG_INT32(1);
ScanKey scankey = (ScanKey) PG_GETARG_POINTER(2);
IndexScanDesc scan; IndexScanDesc scan;
scan = RelationGetIndexScan(rel, keysz, scankey); scan = RelationGetIndexScan(rel, keysz, scankey);
@ -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,82 +131,89 @@ 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; {
uint32 nEntryValues; Datum *entryValues;
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")));
pgstat_count_index_scan(&scan->xs_pgstat_info); pgstat_count_index_scan(&scan->xs_pgstat_info);
} }
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,
ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_INITSIZE,
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));
} }
PG_RETURN_VOID(); PG_RETURN_VOID();
@ -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++)
{
if (keys[i].scanEntry[j].buffer != InvalidBuffer)
IncrBufferRefCount(keys[i].scanEntry[j].buffer);
if (keys[i].scanEntry[j].master)
{
int masterN = keys[i].scanEntry[j].master - keys[i].scanEntry;
for(j=0;j<keys[i].nentries; j++) {
if ( keys[i].scanEntry[j].buffer != InvalidBuffer )
IncrBufferRefCount( keys[i].scanEntry[j].buffer );
if ( keys[i].scanEntry[j].master ) {
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

@ -1,14 +1,14 @@
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* ginutil.c * ginutil.c
* utilities routines for the postgres inverted index access method. * utilities routines for the postgres inverted index access method.
* *
* *
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* 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,25 +20,26 @@
#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 ) {
elog(ERROR, "numberOfAttributes %d != 1", if (index->rd_att->natts != 1)
index->rd_att->natts); elog(ERROR, "numberOfAttributes %d != 1",
index->rd_att->natts);
state->tupdesc = index->rd_att; state->tupdesc = index->rd_att;
fmgr_info_copy(&(state->compareFn), fmgr_info_copy(&(state->compareFn),
index_getprocinfo(index, 1, GIN_COMPARE_PROC), index_getprocinfo(index, 1, GIN_COMPARE_PROC),
CurrentMemoryContext); CurrentMemoryContext);
fmgr_info_copy(&(state->extractValueFn), fmgr_info_copy(&(state->extractValueFn),
index_getprocinfo(index, 1, GIN_EXTRACTVALUE_PROC), index_getprocinfo(index, 1, GIN_EXTRACTVALUE_PROC),
CurrentMemoryContext); CurrentMemoryContext);
fmgr_info_copy(&(state->extractQueryFn), fmgr_info_copy(&(state->extractQueryFn),
index_getprocinfo(index, 1, GIN_EXTRACTQUERY_PROC), index_getprocinfo(index, 1, GIN_EXTRACTQUERY_PROC),
CurrentMemoryContext); CurrentMemoryContext);
fmgr_info_copy(&(state->consistentFn), fmgr_info_copy(&(state->consistentFn),
index_getprocinfo(index, 1, GIN_CONSISTENT_PROC), index_getprocinfo(index, 1, GIN_CONSISTENT_PROC),
CurrentMemoryContext); CurrentMemoryContext);
} }
/* /*
@ -48,13 +49,16 @@ initGinState( GinState *state, Relation index ) {
*/ */
Buffer Buffer
GinNewBuffer(Relation index) { GinNewBuffer(Relation index)
Buffer buffer; {
bool needLock; Buffer buffer;
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,14 +68,15 @@ 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))
return buffer; /* OK to use, if never initialized */ return buffer; /* OK to use, if never initialized */
if (GinPageIsDeleted(page)) if (GinPageIsDeleted(page))
return buffer; /* OK to use */ return buffer; /* OK to use */
LockBuffer(buffer, GIN_UNLOCK); LockBuffer(buffer, GIN_UNLOCK);
} }
@ -95,33 +100,36 @@ 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,
a, b a, 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))
/* /*
@ -132,7 +140,7 @@ static FmgrInfo* cmpDatumPtr=NULL;
* It's a pity, but it's impossible to define optimization * It's a pity, but it's impossible to define optimization
* level here. * level here.
*/ */
#define VOLATILE volatile #define VOLATILE volatile
#else #else
#define VOLATILE #define VOLATILE
#endif #endif
@ -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( {
FunctionCall2( int res = DatumGetInt32(
cmpDatumPtr, FunctionCall2(
*(Datum*)a, cmpDatumPtr,
*(Datum*)b *(Datum *) a,
) *(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 ); {
Page tmppage; Size pageSize = PageGetPageSize(page);
Page tmppage;
tmppage=(Page)palloc( pageSize ); tmppage = (Page) palloc(pageSize);
memcpy( tmppage, page, pageSize ); memcpy(tmppage, page, pageSize);
return tmppage; return tmppage;
} }

View File

@ -1,14 +1,14 @@
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* ginvacuum.c * ginvacuum.c
* delete & vacuum routines for the postgres GIN * delete & vacuum routines for the postgres GIN
* *
* *
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* 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,12 +21,13 @@
#include "storage/freespace.h" #include "storage/freespace.h"
#include "commands/vacuum.h" #include "commands/vacuum.h"
typedef struct { typedef struct
Relation index; {
IndexBulkDeleteResult *result; Relation index;
IndexBulkDeleteCallback callback; IndexBulkDeleteResult *result;
void *callback_state; IndexBulkDeleteCallback callback;
GinState ginstate; void *callback_state;
GinState ginstate;
} GinVacuumState; } GinVacuumState;
@ -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 ); {
XLogRecPtr recptr; Page page = BufferGetPage(buffer);
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);
char *ptr; }
else
{
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)); {
memcpy( ptr, itup, IndexTupleSize( itup ) ); IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
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);
bool hasVoidPage = FALSE; Page page = BufferGetPage(buffer);
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,41 +236,46 @@ 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;
int n; int n;
data.node = gvs->index->rd_node; data.node = gvs->index->rd_node;
data.blkno = deleteBlkno; data.blkno = deleteBlkno;
@ -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,122 +319,141 @@ 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 *parent; struct DataPageDeleteStack *child;
struct DataPageDeleteStack *parent;
BlockNumber blkno; BlockNumber blkno;
bool isRoot; bool isRoot;
} DataPageDeleteStack; } 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; {
Buffer buffer; DataPageDeleteStack *me;
Page page; Buffer buffer;
bool meDelete = FALSE; Page page;
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; {
DataPageDeleteStack root, *ptr, *tmp; Buffer rootBuffer = InvalidBuffer;
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; {
Datum value; bool isnull;
Datum value;
/* /*
* Some ItemPointers was deleted, so we should remake our tuple * Some ItemPointers was deleted, so we should remake our
* tuple
*/ */
if ( tmppage==origpage ) { if (tmppage == origpage)
{
/* /*
* On first difference we create temprorary page in memory * 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,30 +530,31 @@ 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);
void *callback_state = (void *) PG_GETARG_POINTER(3); void *callback_state = (void *) PG_GETARG_POINTER(3);
Relation index = info->index; Relation index = info->index;
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? */
if (stats == NULL) if (stats == NULL)
@ -494,107 +568,117 @@ 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 ); {
IndexTuple itup; Page page = BufferGetPage(buffer);
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); {
continue; /* check it one more */ LockBuffer(buffer, GIN_UNLOCK);
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 resPage; Page page = BufferGetPage(buffer);
uint32 i; Page resPage;
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;
bool needLock; bool needLock;
BlockNumber npages, BlockNumber npages,
blkno; blkno;
BlockNumber totFreePages, BlockNumber totFreePages,
nFreePages, nFreePages,
*freePages, *freePages,
maxFreePages; maxFreePages;
BlockNumber lastBlock = GIN_ROOT_BLKNO, BlockNumber lastBlock = GIN_ROOT_BLKNO,
lastFilledBlock = GIN_ROOT_BLKNO; lastFilledBlock = GIN_ROOT_BLKNO;
/* 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,9 +698,10 @@ 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; {
Page page; Buffer buffer;
Page page;
vacuum_delay_point(); vacuum_delay_point();
@ -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"
@ -17,12 +17,13 @@
#include "access/heapam.h" #include "access/heapam.h"
#include "utils/memutils.h" #include "utils/memutils.h"
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; {
BlockNumber leftBlkno; RelFileNode node;
BlockNumber leftBlkno;
BlockNumber rightBlkno; BlockNumber rightBlkno;
BlockNumber rootBlkno; BlockNumber rootBlkno;
} ginIncompleteSplit; } ginIncompleteSplit;
@ -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 { }
IndexTuple itup; else
{
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); {
Size sizeofitem = GinSizeOfItem(lpage); char *ptr = XLogRecGetData(record) + sizeof(ginxlogSplit);
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); {
Page rootPage = BufferGetPage( rootBuf ); Buffer rootBuf = XLogReadBuffer(reln, data->rootBlkno, false);
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,27 +430,29 @@ 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;
case XLOG_GIN_CREATE_PTREE: case XLOG_GIN_CREATE_PTREE:
ginRedoCreatePTree(lsn, record); ginRedoCreatePTree(lsn, record);
break; break;
case XLOG_GIN_INSERT: case XLOG_GIN_INSERT:
ginRedoInsert(lsn, record); ginRedoInsert(lsn, record);
break; break;
case XLOG_GIN_SPLIT: case XLOG_GIN_SPLIT:
ginRedoSplit(lsn, record); ginRedoSplit(lsn, record);
break; break;
case XLOG_GIN_VACUUM_PAGE: case XLOG_GIN_VACUUM_PAGE:
ginRedoVacuumPage(lsn, record); ginRedoVacuumPage(lsn, record);
break; break;
case XLOG_GIN_DELETE_PAGE: case XLOG_GIN_DELETE_PAGE:
ginRedoDeletePage(lsn, record); ginRedoDeletePage(lsn, record);
break; break;
default: default:
@ -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", {
node.spcNode, node.dbNode, node.relNode, blkno); appendStringInfo(buf, "node: %u/%u/%u blkno: %u",
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: {
appendStringInfo(buf,"Create index, "); case XLOG_GIN_CREATE_INDEX:
desc_node(buf, *(RelFileNode*)rec, GIN_ROOT_BLKNO ); appendStringInfo(buf, "Create index, ");
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,43 +516,51 @@ 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,
"GIN recovery temporary context", "GIN recovery temporary context",
ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE); ALLOCSET_DEFAULT_MAXSIZE);
} }
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;
} }
btree.rightblkno = split->rightBlkno; btree.rightblkno = split->rightBlkno;
@ -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;
/* /*
@ -199,7 +199,7 @@ gistbuildCallback(Relation index,
* after initial build do not. * after initial build do not.
*/ */
gistdoinsert(index, itup, gistdoinsert(index, itup,
RelationGetTargetPageFreeSpace(index, GIST_DEFAULT_FILLFACTOR), RelationGetTargetPageFreeSpace(index, GIST_DEFAULT_FILLFACTOR),
&buildstate->giststate); &buildstate->giststate);
buildstate->indtuples += 1; buildstate->indtuples += 1;
@ -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,
@ -307,78 +306,86 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
int tlen; int tlen;
SplitedPageLayout *dist = NULL, SplitedPageLayout *dist = NULL,
*ptr; *ptr;
BlockNumber rrlink = InvalidBlockNumber; BlockNumber rrlink = InvalidBlockNumber;
GistNSN oldnsn; GistNSN oldnsn;
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; {
char *data; int i;
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;
} }
@ -922,16 +932,16 @@ gistSplit(Relation r,
GistSplitVector v; GistSplitVector v;
GistEntryVector *entryvec; GistEntryVector *entryvec;
int i; int i;
SplitedPageLayout *res = NULL; SplitedPageLayout *res = NULL;
/* generate the item array */ /* generate the item array */
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);
/* form left and right vector */ /* form left and right vector */
lvectup = (IndexTuple *) palloc(sizeof(IndexTuple) * (len + 1)); lvectup = (IndexTuple *) palloc(sizeof(IndexTuple) * (len + 1));
@ -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,12 +16,13 @@
#include "access/gist_private.h" #include "access/gist_private.h"
typedef struct { typedef struct
Datum *attr; {
int len; Datum *attr;
int len;
OffsetNumber *entries; OffsetNumber *entries;
bool *isnull; bool *isnull;
bool *equiv; bool *equiv;
} GistSplitUnion; } GistSplitUnion;
@ -30,24 +31,27 @@ typedef struct {
* uses only tuples aren't in groups of equalent tuples * uses only tuples aren't in groups of equalent tuples
*/ */
static void static void
gistunionsubkeyvec(GISTSTATE *giststate, IndexTuple *itvec, gistunionsubkeyvec(GISTSTATE *giststate, IndexTuple *itvec,
GistSplitUnion *gsvp, int startkey) { GistSplitUnion *gsvp, int startkey)
IndexTuple *cleanedItVec; {
int i, cleanedLen=0; IndexTuple *cleanedItVec;
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];
} }
gistMakeUnionItVec(giststate, cleanedItVec, cleanedLen, startkey, gistMakeUnionItVec(giststate, cleanedItVec, cleanedLen, startkey,
gsvp->attr, gsvp->isnull); gsvp->attr, gsvp->isnull);
pfree( cleanedItVec ); pfree(cleanedItVec);
} }
/* /*
@ -56,7 +60,7 @@ gistunionsubkeyvec(GISTSTATE *giststate, IndexTuple *itvec,
static void static void
gistunionsubkey(GISTSTATE *giststate, IndexTuple *itvec, GistSplitVector *spl, int attno) gistunionsubkey(GISTSTATE *giststate, IndexTuple *itvec, GistSplitVector *spl, int attno)
{ {
GistSplitUnion gsvp; GistSplitUnion gsvp;
gsvp.equiv = spl->spl_equiv; gsvp.equiv = spl->spl_equiv;
@ -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, {
&valvec[spl->splitVector.spl_left[i]], false); float penalty = gistpenalty(giststate, attno, &entry, false,
if ( penalty == 0.0 ) { &valvec[spl->splitVector.spl_left[i]], false);
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, {
&valvec[spl->splitVector.spl_right[i]], false); float penalty = gistpenalty(giststate, attno, &entry, false,
if ( penalty == 0.0 ) { &valvec[spl->splitVector.spl_right[i]], false);
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; {
OffsetNumber *curwpos; int curlen,
i;
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 */ {
i--; /* redo the same */ equiv[a[i]] = FALSE; /* mark item as non-equivalent */
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,65 +204,77 @@ 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 { }
GISTENTRY *entry1 = (sv->spl_ldatum_exists) ? &entryL : &entryR; else
float penalty1, penalty2; {
GISTENTRY *entry1 = (sv->spl_ldatum_exists) ? &entryL : &entryR;
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,
Datum datum; noff;
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);
sv->spl_ldatum_exists = sv->spl_rdatum_exists = false; sv->spl_ldatum_exists = sv->spl_rdatum_exists = false;
} }
@ -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,21 +427,25 @@ 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; {
static OffsetNumber offInvTuples[ MaxOffsetNumber ]; int i;
int nOffInvTuples = 0; static OffsetNumber offInvTuples[MaxOffsetNumber];
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 { }
GistSplitUnion gsvp; else
{
GistSplitUnion gsvp;
v->splitVector.spl_right = offInvTuples; v->splitVector.spl_right = offInvTuples;
v->splitVector.spl_nright = nOffInvTuples; v->splitVector.spl_nright = nOffInvTuples;
@ -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; {
static OffsetNumber offNullTuples[ MaxOffsetNumber ]; int i;
int nOffNullTuples = 0; static OffsetNumber offNullTuples[MaxOffsetNumber];
int nOffNullTuples = 0;
for (i = 1; i <= len; i++) { for (i = 1; i <= len; i++)
Datum datum; {
bool IsNull; Datum datum;
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"
@ -22,8 +22,8 @@
* static *S used for temrorary storage (saves stack and palloc() call) * static *S used for temrorary storage (saves stack and palloc() call)
*/ */
static Datum attrS[INDEX_MAX_KEYS]; static Datum attrS[INDEX_MAX_KEYS];
static bool isnullS[INDEX_MAX_KEYS]; static bool isnullS[INDEX_MAX_KEYS];
/* /*
* Write itup vector to page, has no control of free space * Write itup vector to page, has no control of free space
@ -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; {
Size size=0; int i;
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; {
int i; char *ptr,
*ret;
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], {
NULL, NULL, (OffsetNumber) 0, gistentryinit(evec->vector[evec->n], attr[i],
FALSE); NULL, NULL, (OffsetNumber) 0,
FALSE);
evec->n++; evec->n++;
} }
for (j = 0; j < len; j++) { for (j = 0; j < len; j++)
Datum datum; {
bool IsNull; Datum datum;
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,19 +195,23 @@ 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];
} }
/* Make union and store in attr array */ /* Make union and store in attr array */
attr[i] = FunctionCall2(&giststate->unionFn[i], attr[i] = FunctionCall2(&giststate->unionFn[i],
PointerGetDatum(evec), PointerGetDatum(evec),
PointerGetDatum(&attrsize)); PointerGetDatum(&attrsize));
isnull[i] = FALSE; isnull[i] = FALSE;
} }
@ -213,57 +229,67 @@ 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);
} }
/* /*
* 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;
} }
*dstisnull = FALSE; *dstisnull = FALSE;
*dst = FunctionCall2(&giststate->unionFn[attno], *dst = FunctionCall2(&giststate->unionFn[attno],
PointerGetDatum(evec), PointerGetDatum(evec),
PointerGetDatum(&dstsize)); PointerGetDatum(&dstsize));
} }
} }
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],
a, b, a, b,
PointerGetDatum(&result)); PointerGetDatum(&result));
return result; return result;
} }
@ -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, {
oldentries + i, oldisnull[i], gistMakeUnionKey(giststate, i,
addentries + i, addisnull[i], oldentries + i, oldisnull[i],
attrS + i, isnullS + i ); addentries + i, addisnull[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))
{ {
@ -500,17 +528,18 @@ gistpenalty(GISTSTATE *giststate, int attno,
GISTENTRY *orig, bool isNullOrig, GISTENTRY *orig, bool isNullOrig,
GISTENTRY *add, bool isNullAdd) GISTENTRY *add, bool isNullAdd)
{ {
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,20 +78,24 @@ PageMakeUnionKey(GistVacuum *gv, Buffer buffer) {
} }
static void static void
gistDeleteSubtree( GistVacuum *gv, BlockNumber blkno ) { gistDeleteSubtree(GistVacuum *gv, BlockNumber blkno)
Buffer buffer; {
Page page; Buffer buffer;
Page page;
buffer = ReadBuffer(gv->index, blkno); buffer = ReadBuffer(gv->index, 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))
{
ItemId iid = PageGetItemId(page, i);
IndexTuple idxtuple = (IndexTuple) PageGetItem(page, iid);
for (i = FirstOffsetNumber; i <= PageGetMaxOffsetNumber(page); i = OffsetNumberNext(i)) {
ItemId iid = PageGetItemId(page, i);
IndexTuple idxtuple = (IndexTuple) PageGetItem(page, iid);
gistDeleteSubtree(gv, ItemPointerGetBlockNumber(&(idxtuple->t_tid))); gistDeleteSubtree(gv, ItemPointerGetBlockNumber(&(idxtuple->t_tid)));
} }
} }
@ -103,7 +112,7 @@ gistDeleteSubtree( GistVacuum *gv, BlockNumber blkno ) {
{ {
XLogRecData rdata[2]; XLogRecData rdata[2];
XLogRecPtr recptr; XLogRecPtr recptr;
gistxlogPageDelete xlrec; gistxlogPageDelete xlrec;
xlrec.node = gv->index->rd_node; xlrec.node = gv->index->rd_node;
xlrec.blkno = blkno; xlrec.blkno = blkno;
@ -132,24 +141,27 @@ gistDeleteSubtree( GistVacuum *gv, BlockNumber blkno ) {
} }
static Page static Page
GistPageGetCopyPage( Page page ) { GistPageGetCopyPage(Page page)
Size pageSize = PageGetPageSize( page ); {
Page tmppage; Size pageSize = PageGetPageSize(page);
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,
BlockNumber blkno = BufferGetBlockNumber(buffer); veclen = 0;
BlockNumber blkno = BufferGetBlockNumber(buffer);
MemoryContext oldCtx = MemoryContextSwitchTo(gv->opCtx); MemoryContext oldCtx = MemoryContextSwitchTo(gv->opCtx);
vec = gistextractpage(tempPage, &veclen); vec = gistextractpage(tempPage, &veclen);
@ -158,67 +170,73 @@ 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);
rdata = formSplitRdata(gv->index->rd_node, blkno, rdata = formSplitRdata(gv->index->rd_node, blkno,
false, &key, dist); false, &key, dist);
xlinfo = rdata->data; xlinfo = rdata->data;
recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_SPLIT, rdata); recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_SPLIT, rdata);
@ -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;
@ -278,7 +296,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
*addon = NULL; *addon = NULL;
bool needwrite = false; bool needwrite = false;
OffsetNumber offToDelete[MaxOffsetNumber]; OffsetNumber offToDelete[MaxOffsetNumber];
BlockNumber blkToDelete[MaxOffsetNumber]; BlockNumber blkToDelete[MaxOffsetNumber];
ItemPointerData *completed = NULL; ItemPointerData *completed = NULL;
int ncompleted = 0, int ncompleted = 0,
lencompleted = 16; lencompleted = 16;
@ -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"
@ -55,11 +55,11 @@ typedef struct gistIncompleteInsert
static MemoryContext opCtx; /* working memory for operations */ static MemoryContext opCtx; /* working memory for operations */
static MemoryContext insertCtx; /* holds incomplete_inserts list */ static MemoryContext insertCtx; /* holds incomplete_inserts list */
static List *incomplete_inserts; static List *incomplete_inserts;
#define ItemPointerEQ(a, b) \ #define ItemPointerEQ(a, b) \
( ItemPointerGetOffsetNumber(a) == ItemPointerGetOffsetNumber(b) && \ ( ItemPointerGetOffsetNumber(a) == ItemPointerGetOffsetNumber(b) && \
ItemPointerGetBlockNumber (a) == ItemPointerGetBlockNumber(b) ) ItemPointerGetBlockNumber (a) == ItemPointerGetBlockNumber(b) )
@ -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;
@ -432,11 +436,11 @@ static void
out_target(StringInfo buf, RelFileNode node, ItemPointerData key) 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));
} }
static void static void
@ -450,8 +454,8 @@ static void
out_gistxlogPageDelete(StringInfo buf, gistxlogPageDelete *xlrec) out_gistxlogPageDelete(StringInfo buf, gistxlogPageDelete *xlrec)
{ {
appendStringInfo(buf, "page_delete: rel %u/%u/%u; blkno %u", appendStringInfo(buf, "page_delete: rel %u/%u/%u; blkno %u",
xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode, xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
xlrec->blkno); xlrec->blkno);
} }
static void static void
@ -460,7 +464,7 @@ out_gistxlogPageSplit(StringInfo buf, gistxlogPageSplit *xlrec)
appendStringInfo(buf, "page_split: "); appendStringInfo(buf, "page_split: ");
out_target(buf, xlrec->node, xlrec->key); out_target(buf, xlrec->node, xlrec->key);
appendStringInfo(buf, "; block number %u splits to %d pages", appendStringInfo(buf, "; block number %u splits to %d pages",
xlrec->origblkno, xlrec->npage); xlrec->origblkno, xlrec->npage);
} }
void void
@ -486,15 +490,15 @@ gist_desc(StringInfo buf, uint8 xl_info, char *rec)
break; break;
case XLOG_GIST_CREATE_INDEX: case XLOG_GIST_CREATE_INDEX:
appendStringInfo(buf, "create_index: rel %u/%u/%u", appendStringInfo(buf, "create_index: rel %u/%u/%u",
((RelFileNode *) rec)->spcNode, ((RelFileNode *) rec)->spcNode,
((RelFileNode *) rec)->dbNode, ((RelFileNode *) rec)->dbNode,
((RelFileNode *) rec)->relNode); ((RelFileNode *) rec)->relNode);
break; break;
case XLOG_GIST_INSERT_COMPLETE: case XLOG_GIST_INSERT_COMPLETE:
appendStringInfo(buf, "complete_insert: rel %u/%u/%u", appendStringInfo(buf, "complete_insert: rel %u/%u/%u",
((gistxlogInsertComplete *) rec)->node.spcNode, ((gistxlogInsertComplete *) rec)->node.spcNode,
((gistxlogInsertComplete *) rec)->node.dbNode, ((gistxlogInsertComplete *) rec)->node.dbNode,
((gistxlogInsertComplete *) rec)->node.relNode); ((gistxlogInsertComplete *) rec)->node.relNode);
break; break;
default: default:
appendStringInfo(buf, "unknown gist op code %u", info); appendStringInfo(buf, "unknown gist op code %u", info);
@ -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]);
int veclen; IndexTuple *vec;
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;
@ -626,7 +633,7 @@ gistContinueInsert(gistIncompleteInsert *insert)
Buffer *buffers; Buffer *buffers;
Page *pages; Page *pages;
int numbuffer; int numbuffer;
OffsetNumber *todelete; OffsetNumber *todelete;
/* construct path */ /* construct path */
gistxlogFindPath(index, insert); gistxlogFindPath(index, insert);
@ -642,21 +649,22 @@ gistContinueInsert(gistIncompleteInsert *insert)
int j, int j,
k, k,
pituplen = 0; pituplen = 0;
XLogRecData *rdata; XLogRecData *rdata;
XLogRecPtr recptr; XLogRecPtr recptr;
Buffer tempbuffer = InvalidBuffer; Buffer tempbuffer = InvalidBuffer;
int ntodelete = 0; int ntodelete = 0;
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))
@ -699,7 +707,7 @@ gistContinueInsert(gistIncompleteInsert *insert)
if (BufferGetBlockNumber(buffers[0]) == GIST_ROOT_BLKNO) if (BufferGetBlockNumber(buffers[0]) == GIST_ROOT_BLKNO)
{ {
Buffer tmp; Buffer tmp;
/* /*
* we split root, just copy content from root to new page * we split root, just copy content from root to new page
@ -713,44 +721,48 @@ 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);
rdata = formUpdateRdata(index->rd_node, buffers[0], rdata = formUpdateRdata(index->rd_node, buffers[0],
todelete, ntodelete, todelete, ntodelete,
itup, lenitup, &(insert->key)); itup, lenitup, &(insert->key));
} }
/* /*
* 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
*/ */
@ -780,9 +794,9 @@ gistContinueInsert(gistIncompleteInsert *insert)
} }
ereport(LOG, ereport(LOG,
(errmsg("index %u/%u/%u needs VACUUM FULL or REINDEX to finish crash recovery", (errmsg("index %u/%u/%u needs VACUUM FULL or REINDEX to finish crash recovery",
insert->node.spcNode, insert->node.dbNode, insert->node.relNode), insert->node.spcNode, insert->node.dbNode, insert->node.relNode),
errdetail("Incomplete insertion detected during crash replay."))); errdetail("Incomplete insertion detected during crash replay.")));
} }
void void

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,9 +138,9 @@ 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),
VARSIZE(key) - VARHDRSZ); VARSIZE(key) - VARHDRSZ);

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
@ -224,7 +224,7 @@ _hash_metapinit(Relation rel)
/* /*
* Determine the target fill factor (in tuples per bucket) for this index. * Determine the target fill factor (in tuples per bucket) for this index.
* The idea is to make the fill factor correspond to pages about as full * The idea is to make the fill factor correspond to pages about as full
* as the user-settable fillfactor parameter says. We can compute it * as the user-settable fillfactor parameter says. We can compute it
* exactly if the index datatype is fixed-width, but for var-width there's * exactly if the index datatype is fixed-width, but for var-width there's
* some guessing involved. * some guessing involved.
*/ */

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);
@ -223,7 +223,7 @@ heapgettup(HeapScanDesc scan,
tuple->t_data = NULL; tuple->t_data = NULL;
return; return;
} }
page = 0; /* first page */ page = 0; /* first page */
heapgetpage(scan, page); heapgetpage(scan, page);
lineoff = FirstOffsetNumber; /* first offnum */ lineoff = FirstOffsetNumber; /* first offnum */
scan->rs_inited = true; scan->rs_inited = true;
@ -231,8 +231,8 @@ heapgettup(HeapScanDesc scan,
else else
{ {
/* continue from previously returned page/tuple */ /* continue from previously returned page/tuple */
page = scan->rs_cblock; /* current page */ page = scan->rs_cblock; /* current page */
lineoff = /* next offnum */ lineoff = /* next offnum */
OffsetNumberNext(ItemPointerGetOffsetNumber(&(tuple->t_self))); OffsetNumberNext(ItemPointerGetOffsetNumber(&(tuple->t_self)));
} }
@ -263,7 +263,7 @@ heapgettup(HeapScanDesc scan,
else else
{ {
/* continue from previously returned page/tuple */ /* continue from previously returned page/tuple */
page = scan->rs_cblock; /* current page */ page = scan->rs_cblock; /* current page */
} }
LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE); LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
@ -273,12 +273,12 @@ heapgettup(HeapScanDesc scan,
if (!scan->rs_inited) if (!scan->rs_inited)
{ {
lineoff = lines; /* final offnum */ lineoff = lines; /* final offnum */
scan->rs_inited = true; scan->rs_inited = true;
} }
else else
{ {
lineoff = /* previous offnum */ lineoff = /* previous offnum */
OffsetNumberPrev(ItemPointerGetOffsetNumber(&(tuple->t_self))); OffsetNumberPrev(ItemPointerGetOffsetNumber(&(tuple->t_self)));
} }
/* page and lineoff now reference the physically previous tid */ /* page and lineoff now reference the physically previous tid */
@ -450,7 +450,7 @@ heapgettup_pagemode(HeapScanDesc scan,
tuple->t_data = NULL; tuple->t_data = NULL;
return; return;
} }
page = 0; /* first page */ page = 0; /* first page */
heapgetpage(scan, page); heapgetpage(scan, page);
lineindex = 0; lineindex = 0;
scan->rs_inited = true; scan->rs_inited = true;
@ -458,7 +458,7 @@ heapgettup_pagemode(HeapScanDesc scan,
else else
{ {
/* continue from previously returned page/tuple */ /* continue from previously returned page/tuple */
page = scan->rs_cblock; /* current page */ page = scan->rs_cblock; /* current page */
lineindex = scan->rs_cindex + 1; lineindex = scan->rs_cindex + 1;
} }
@ -487,7 +487,7 @@ heapgettup_pagemode(HeapScanDesc scan,
else else
{ {
/* continue from previously returned page/tuple */ /* continue from previously returned page/tuple */
page = scan->rs_cblock; /* current page */ page = scan->rs_cblock; /* current page */
} }
dp = (Page) BufferGetPage(scan->rs_cbuf); dp = (Page) BufferGetPage(scan->rs_cbuf);
@ -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),
@ -764,7 +764,7 @@ relation_open_nowait(Oid relationId, LOCKMODE lockmode)
if (!ConditionalLockRelationOid(relationId, lockmode)) if (!ConditionalLockRelationOid(relationId, lockmode))
{ {
/* try to throw error by name; relation could be deleted... */ /* try to throw error by name; relation could be deleted... */
char *relname = get_rel_name(relationId); char *relname = get_rel_name(relationId);
if (relname) if (relname)
ereport(ERROR, ereport(ERROR,
@ -774,8 +774,8 @@ relation_open_nowait(Oid relationId, LOCKMODE lockmode)
else else
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_LOCK_NOT_AVAILABLE), (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
errmsg("could not obtain lock on relation with OID %u", errmsg("could not obtain lock on relation with OID %u",
relationId))); 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
@ -2723,7 +2723,7 @@ l3:
* heap_inplace_update - update a tuple "in place" (ie, overwrite it) * heap_inplace_update - update a tuple "in place" (ie, overwrite it)
* *
* Overwriting violates both MVCC and transactional safety, so the uses * Overwriting violates both MVCC and transactional safety, so the uses
* of this function in Postgres are extremely limited. Nonetheless we * of this function in Postgres are extremely limited. Nonetheless we
* find some places to use it. * find some places to use it.
* *
* The tuple cannot change size, and therefore it's reasonable to assume * The tuple cannot change size, and therefore it's reasonable to assume
@ -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
*/ */
@ -2852,7 +2853,7 @@ heap_restrpos(HeapScanDesc scan)
else else
{ {
/* /*
* If we reached end of scan, rs_inited will now be false. We must * If we reached end of scan, rs_inited will now be false. We must
* reset it to true to keep heapgettup from doing the wrong thing. * reset it to true to keep heapgettup from doing the wrong thing.
*/ */
scan->rs_inited = true; scan->rs_inited = true;
@ -2862,13 +2863,13 @@ heap_restrpos(HeapScanDesc scan)
scan->rs_cindex = scan->rs_mindex; scan->rs_cindex = scan->rs_mindex;
heapgettup_pagemode(scan, heapgettup_pagemode(scan,
NoMovementScanDirection, NoMovementScanDirection,
0, /* needn't recheck scan keys */ 0, /* needn't recheck scan keys */
NULL); NULL);
} }
else else
heapgettup(scan, heapgettup(scan,
NoMovementScanDirection, NoMovementScanDirection,
0, /* needn't recheck scan keys */ 0, /* needn't recheck scan keys */
NULL); NULL);
} }
} }
@ -2920,7 +2921,7 @@ log_heap_clean(Relation reln, Buffer buffer, OffsetNumber *unused, int uncnt)
} }
/* /*
* Perform XLogInsert for a heap-update operation. Caller must already * Perform XLogInsert for a heap-update operation. Caller must already
* have modified the buffer(s) and marked them dirty. * have modified the buffer(s) and marked them dirty.
*/ */
static XLogRecPtr static XLogRecPtr
@ -3173,8 +3174,8 @@ heap_xlog_insert(XLogRecPtr lsn, XLogRecord *record)
if (record->xl_info & XLOG_HEAP_INIT_PAGE) if (record->xl_info & XLOG_HEAP_INIT_PAGE)
{ {
buffer = XLogReadBuffer(reln, buffer = XLogReadBuffer(reln,
ItemPointerGetBlockNumber(&(xlrec->target.tid)), ItemPointerGetBlockNumber(&(xlrec->target.tid)),
true); true);
Assert(BufferIsValid(buffer)); Assert(BufferIsValid(buffer));
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
@ -3183,13 +3184,13 @@ heap_xlog_insert(XLogRecPtr lsn, XLogRecord *record)
else else
{ {
buffer = XLogReadBuffer(reln, buffer = XLogReadBuffer(reln,
ItemPointerGetBlockNumber(&(xlrec->target.tid)), ItemPointerGetBlockNumber(&(xlrec->target.tid)),
false); false);
if (!BufferIsValid(buffer)) if (!BufferIsValid(buffer))
return; return;
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
if (XLByteLE(lsn, PageGetLSN(page))) /* changes are applied */ if (XLByteLE(lsn, PageGetLSN(page))) /* changes are applied */
{ {
UnlockReleaseBuffer(buffer); UnlockReleaseBuffer(buffer);
return; return;
@ -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
@ -3345,7 +3347,7 @@ newt:;
return; return;
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
if (XLByteLE(lsn, PageGetLSN(page))) /* changes are applied */ if (XLByteLE(lsn, PageGetLSN(page))) /* changes are applied */
{ {
UnlockReleaseBuffer(buffer); UnlockReleaseBuffer(buffer);
return; return;
@ -3548,9 +3550,9 @@ static void
out_target(StringInfo buf, xl_heaptid *target) out_target(StringInfo buf, xl_heaptid *target)
{ {
appendStringInfo(buf, "rel %u/%u/%u; tid %u/%u", appendStringInfo(buf, "rel %u/%u/%u; tid %u/%u",
target->node.spcNode, target->node.dbNode, target->node.relNode, target->node.spcNode, target->node.dbNode, target->node.relNode,
ItemPointerGetBlockNumber(&(target->tid)), ItemPointerGetBlockNumber(&(target->tid)),
ItemPointerGetOffsetNumber(&(target->tid))); ItemPointerGetOffsetNumber(&(target->tid)));
} }
void void
@ -3586,8 +3588,8 @@ heap_desc(StringInfo buf, uint8 xl_info, char *rec)
appendStringInfo(buf, "update: "); appendStringInfo(buf, "update: ");
out_target(buf, &(xlrec->target)); out_target(buf, &(xlrec->target));
appendStringInfo(buf, "; new %u/%u", appendStringInfo(buf, "; new %u/%u",
ItemPointerGetBlockNumber(&(xlrec->newtid)), ItemPointerGetBlockNumber(&(xlrec->newtid)),
ItemPointerGetOffsetNumber(&(xlrec->newtid))); ItemPointerGetOffsetNumber(&(xlrec->newtid)));
} }
else if (info == XLOG_HEAP_MOVE) else if (info == XLOG_HEAP_MOVE)
{ {
@ -3599,24 +3601,24 @@ heap_desc(StringInfo buf, uint8 xl_info, char *rec)
appendStringInfo(buf, "move: "); appendStringInfo(buf, "move: ");
out_target(buf, &(xlrec->target)); out_target(buf, &(xlrec->target));
appendStringInfo(buf, "; new %u/%u", appendStringInfo(buf, "; new %u/%u",
ItemPointerGetBlockNumber(&(xlrec->newtid)), ItemPointerGetBlockNumber(&(xlrec->newtid)),
ItemPointerGetOffsetNumber(&(xlrec->newtid))); ItemPointerGetOffsetNumber(&(xlrec->newtid)));
} }
else if (info == XLOG_HEAP_CLEAN) else if (info == XLOG_HEAP_CLEAN)
{ {
xl_heap_clean *xlrec = (xl_heap_clean *) rec; xl_heap_clean *xlrec = (xl_heap_clean *) rec;
appendStringInfo(buf, "clean: rel %u/%u/%u; blk %u", appendStringInfo(buf, "clean: rel %u/%u/%u; blk %u",
xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.spcNode, xlrec->node.dbNode,
xlrec->node.relNode, xlrec->block); xlrec->node.relNode, xlrec->block);
} }
else if (info == XLOG_HEAP_NEWPAGE) else if (info == XLOG_HEAP_NEWPAGE)
{ {
xl_heap_newpage *xlrec = (xl_heap_newpage *) rec; xl_heap_newpage *xlrec = (xl_heap_newpage *) rec;
appendStringInfo(buf, "newpage: rel %u/%u/%u; blk %u", appendStringInfo(buf, "newpage: rel %u/%u/%u; blk %u",
xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.spcNode, xlrec->node.dbNode,
xlrec->node.relNode, xlrec->blkno); xlrec->node.relNode, xlrec->blkno);
} }
else if (info == XLOG_HEAP_LOCK) else if (info == XLOG_HEAP_LOCK)
{ {

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
@ -1331,7 +1331,7 @@ toast_fetch_datum_slice(varattrib *attr, int32 sliceoffset, int32 length)
VARATT_SIZEP(result) |= VARATT_FLAG_COMPRESSED; VARATT_SIZEP(result) |= VARATT_FLAG_COMPRESSED;
if (length == 0) if (length == 0)
return result; /* Can save a lot of work at this point! */ return result; /* Can save a lot of work at this point! */
startchunk = sliceoffset / TOAST_MAX_CHUNK_SIZE; startchunk = sliceoffset / TOAST_MAX_CHUNK_SIZE;
endchunk = (sliceoffset + length - 1) / TOAST_MAX_CHUNK_SIZE; endchunk = (sliceoffset + length - 1) / TOAST_MAX_CHUNK_SIZE;

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
@ -86,7 +86,7 @@ RelationGetIndexScan(Relation indexRelation,
else else
scan->keyData = NULL; scan->keyData = NULL;
scan->is_multiscan = false; /* caller may change this */ scan->is_multiscan = false; /* caller may change this */
scan->kill_prior_tuple = false; scan->kill_prior_tuple = false;
scan->ignore_killed_tuples = true; /* default setting */ scan->ignore_killed_tuples = true; /* default setting */

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